rex_sql_util

Keywords: SQL-Utilities, Import, Dump, Priorities, copyTable, organizePriorities, slowQueryLog

Übersicht

rex_sql_util bietet Hilfsfunktionen für SQL-Operationen: Import von .sql-Dumps, Tabellen-Kopieren (mit/ohne Daten), automatische Prioritäts-Nummerierung (z.B. für Sortierung). Unterstützt Platzhalter (%TABLE_PREFIX%, %USER%, %TIME%).

Methoden

Methode Parameter Rückgabe Beschreibung
importDump($file, $debug) string, bool bool Importiert .sql-Datei in DB (install.sql, uninstall.sql)
organizePriorities($table, $prioCol, $where, $orderBy, $startBy) string, string, string, string, int void Nummeriert Spalte fortlaufend durch (Sortierreihenfolge)
copyTable($source, $dest) string, string void Kopiert Tabellenstruktur (ohne Daten)
copyTableWithData($source, $dest) string, string void Kopiert Tabelle inkl. Daten
slowQueryLogPath() - string\|null Gibt Pfad zur Slow-Query-Log-Datei zurück
splitSqlFile(&$queries, $sql, $release) array, string, int bool Interner Parser: Splittet SQL-Dump in Statements

Praxisbeispiele

SQL-Dump importieren (install.sql)

// In install.php: SQL-Datei ausführen
$installSql = rex_path::addon('myaddon', 'install.sql');

if (file_exists($installSql)) {
    rex_sql_util::importDump($installSql);
}

// Mit Debug-Modus
rex_sql_util::importDump($installSql, true);

Install.sql mit Platzhaltern

-- install.sql
CREATE TABLE %TABLE_PREFIX%myaddon_items (
    id INT(11) AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_by VARCHAR(255) DEFAULT '%USER%',
    created_at INT(11) DEFAULT %TIME%
);

INSERT INTO %TABLE_PREFIX%myaddon_items (name) VALUES ('Demo Item');

Uninstall.sql importieren

// In uninstall.php
$uninstallSql = rex_path::addon('myaddon', 'uninstall.sql');

if (file_exists($uninstallSql)) {
    rex_sql_util::importDump($uninstallSql);
}

Uninstall.sql Beispiel

-- uninstall.sql
DROP TABLE IF EXISTS %TABLE_PREFIX%myaddon_items;
DROP TABLE IF EXISTS %TABLE_PREFIX%myaddon_categories;

Prioritäten organisieren (Auto-Nummerierung)

// Nach INSERT/UPDATE: Prioritäten neu durchnummerieren
rex_sql_util::organizePriorities(
    rex::getTable('myaddon_items'),  // Tabellenname
    'priority',                       // Spaltenname für Priorität
    '',                              // WHERE-Bedingung (leer = alle)
    'priority',                      // ORDER BY
    1                                // Start bei 1
);

// Resultat: priority = 1, 2, 3, 4, ...

Prioritäten mit WHERE-Filter

// Nur Items einer Kategorie neu nummerieren
rex_sql_util::organizePriorities(
    rex::getTable('myaddon_items'),
    'priority',
    'category_id = 5',  // Nur Kategorie 5
    'priority, name',   // Sortierung
    1
);

Structure: Artikel-Prioritäten

// rex_article_service nutzt organizePriorities
rex_sql_util::organizePriorities(
    rex::getTable('article'),
    'priority',
    'clang_id=' . $clangId . ' AND parent_id=' . $parentId,
    'priority',
    1
);

Slices/Module: Content-Prioritäten

// Nach Slice-Verschiebung
rex_sql_util::organizePriorities(
    rex::getTable('article_slice'),
    'priority',
    'article_id=' . $articleId . ' AND clang_id=' . $clangId . ' AND ctype_id=' . $ctypeId,
    'priority',
    1
);

Clang-Prioritäten neu sortieren

// rex_clang_service nutzt nach addCLang/editCLang/deleteCLang:
rex_sql_util::organizePriorities(
    rex::getTable('clang'),
    'priority',
    '',
    'priority'
);

Metainfo-Feld-Prioritäten

// Metainfo-Felder nach Prefix sortieren
rex_sql_util::organizePriorities(
    rex::getTablePrefix() . 'metainfo_field',
    'priority',
    'name LIKE "art_%"',  // Nur Article-Felder
    'priority, updatedate'
);

Media Manager Effects sortieren

// Effects nach Bearbeitung neu sortieren
rex_sql_util::organizePriorities(
    rex::getTable('media_manager_type_effect'),
    'priority',
    'type_id=' . $typeId,
    'priority'
);

Tabelle kopieren (nur Struktur)

// Backup-Tabelle erstellen (ohne Daten)
try {
    rex_sql_util::copyTable(
        rex::getTable('myaddon_items'),
        rex::getTable('myaddon_items_backup')
    );
} catch (rex_exception $e) {
    echo 'Fehler: ' . $e->getMessage();
}

Tabelle mit Daten kopieren

// Vollständiges Backup
rex_sql_util::copyTableWithData(
    rex::getTable('myaddon_items'),
    rex::getTable('myaddon_items_' . date('Ymd'))
);

Demo-Daten importieren

// In Backend-Page: Demo-Daten Button
if (rex_post('import_demo', 'boolean')) {
    $file = rex_path::addon('myaddon', 'install/demo.sql');
    
    if (file_exists($file)) {
        try {
            rex_sql_util::importDump($file);
            echo rex_view::success('Demo-Daten importiert');
        } catch (rex_sql_exception $e) {
            echo rex_view::error($e->getMessage());
        }
    }
}

Demo.sql mit mehreren Inserts

-- demo.sql
INSERT INTO %TABLE_PREFIX%myaddon_categories (name, priority) VALUES
('Kategorie 1', 1),
('Kategorie 2', 2),
('Kategorie 3', 3);

INSERT INTO %TABLE_PREFIX%myaddon_items (name, category_id, created_at) VALUES
('Item A', 1, %TIME%),
('Item B', 1, %TIME%),
('Item C', 2, %TIME%);

Update.sql für Migration

// update.php: Spalte hinzufügen via SQL-Datei
$version = $addon->getProperty('version');

if (version_compare($version, '2.0.0', '>=')) {
    $updateSql = rex_path::addon('myaddon', 'update/2.0.0.sql');
    
    if (file_exists($updateSql)) {
        rex_sql_util::importDump($updateSql);
    }
}

Slow Query Log auslesen

// Backend-Page: Slow Queries anzeigen
$slowQueryPath = rex_sql_util::slowQueryLogPath();

if ($slowQueryPath && is_readable($slowQueryPath)) {
    $lines = file($slowQueryPath, FILE_IGNORE_NEW_LINES);
    $recent = array_slice($lines, -100);
    
    echo '<pre>' . implode("\n", $recent) . '</pre>';
} else {
    echo 'Slow Query Log nicht verfügbar';
}

System-Log: Slow Queries Page

// rex_be_controller fügt Page hinzu wenn Log existiert
if ('system' === rex_be_controller::getCurrentPagePart(1) && 'log' === rex_be_controller::getCurrentPagePart(2)) {
    $slowQueryLogPath = rex_sql_util::slowQueryLogPath();
    
    if (null !== $slowQueryLogPath && @is_readable($slowQueryLogPath)) {
        $logsPage->addSubpage((new rex_be_page('slow-queries', rex_i18n::msg('syslog_slowqueries')))
            ->setSubPath(rex_path::core('pages/system.log.slow-queries.php')));
    }
}

Platzhalter in SQL-Dumps

// Automatisch ersetzt beim Import:
// %TABLE_PREFIX% -> rex_ (oder Custom)
// %TEMP_PREFIX% -> tmp_rex_
// %USER% -> aktueller User-Login
// %TIME% -> time() Timestamp

Eigene Platzhalter

// prepareQuery ist private, aber eigene Wrapper möglich:
$sql = file_get_contents($sqlFile);
$sql = str_replace('%CUSTOM_VAL%', $myValue, $sql);
file_put_contents($tempFile, $sql);
rex_sql_util::importDump($tempFile);
unlink($tempFile);

rex_form_element_prio nutzt organizePriorities

// form/elements/prio.php verwendet intern:
if ($this->fieldSaved) {
    rex_sql_util::organizePriorities(
        $this->getTable(),
        $this->getName(),
        $whereCondition,
        $this->params['order_by']
    );
}

Tracks Addon: Content-Prioritäten

// tracks/lib/Content.php
public function reorganizePriorities() {
    rex_sql_util::organizePriorities(
        rex::getTable('tracks_content'),
        'priority',
        'track_id=' . $this->getId(),
        'priority'
    );
}

Sprog: Struktur-Copy mit Prioritäten

// Nach Artikel-Kopie: Slices neu nummerieren
\rex_sql_util::organizePriorities(
    \rex::getTable('article_slice'),
    'priority',
    'article_id=' . $newArticleId . ' AND clang_id=' . $clangId,
    'priority'
);

Error-Handling bei importDump

try {
    rex_sql_util::importDump($sqlFile);
} catch (rex_sql_exception $e) {
    rex_logger::logException($e);
    echo rex_view::error('SQL-Import fehlgeschlagen: ' . $e->getMessage());
    return false;
}

return true;

Import mit Validierung

$sqlFile = rex_path::addon('myaddon', 'install.sql');

if (!file_exists($sqlFile)) {
    throw new rex_exception('install.sql nicht gefunden');
}

if (!str_ends_with($sqlFile, '.sql')) {
    throw new rex_exception('Nur .sql Dateien erlaubt');
}

rex_sql_util::importDump($sqlFile);

Batch-Import mehrerer SQL-Files

$sqlFiles = [
    'install/tables.sql',
    'install/data.sql',
    'install/demo.sql',
];

foreach ($sqlFiles as $file) {
    $path = rex_path::addon('myaddon', $file);
    
    if (file_exists($path)) {
        rex_sql_util::importDump($path);
    }
}

Prioritäten manuell setzen vor organizePriorities

// Elemente mit priority = 999 ans Ende sortieren
$sql = rex_sql::factory();
$sql->setQuery('UPDATE ' . rex::getTable('items') . ' SET priority = 999 WHERE special = 1');

// Dann durchnummerieren (special items kommen ans Ende)
rex_sql_util::organizePriorities(
    rex::getTable('items'),
    'priority',
    '',
    'priority'  // 999 wird zu höchster Nummer
);

Prioritäten mit Kategorien

// Jede Kategorie einzeln neu nummerieren
$categories = rex_sql::factory()->getArray('SELECT DISTINCT category_id FROM ' . rex::getTable('items'));

foreach ($categories as $cat) {
    rex_sql_util::organizePriorities(
        rex::getTable('items'),
        'priority',
        'category_id=' . $cat['category_id'],
        'priority, name',
        1
    );
}

Table-Copy für Tests

// Test-Setup: Tabelle als Backup
if (rex::isDebugMode()) {
    rex_sql_util::copyTableWithData(
        rex::getTable('myaddon_items'),
        rex::getTable('myaddon_items_test')
    );
}

// Tests durchführen...

// Cleanup
rex_sql_table::get(rex::getTable('myaddon_items_test'))->drop();

SQL-Dump mit Kommentaren

-- install.sql: Kommentare werden ignoriert

-- Tabelle für Items
CREATE TABLE %TABLE_PREFIX%myaddon_items (
    id INT(11) AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    /* Multi-Line
       Kommentar */
    created_at INT(11)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

# Hash-Kommentare auch möglich
INSERT INTO %TABLE_PREFIX%myaddon_items (name) VALUES ('Test');

Conditional Import

// Nur importieren wenn Tabelle nicht existiert
if (!rex_sql_table::get(rex::getTable('myaddon_items'))->exists()) {
    rex_sql_util::importDump(rex_path::addon('myaddon', 'install.sql'));
}