Update auf 3.2.5 von < 3.2 - singleSRC und multiSRC Zuordnungen stimmen nicht mehr

von Johannes Pichler

UPDATE 2:
Version 0.0.2-beta2
verfügbar

Die Version 0.0.2-beta2 beinhaltet auch die Möglichkeit die Tabelle tl_files hinsichtlich fehlender PIDs zu reparieren. Bei Nichtvohanden sein von UUIDs werden auch diese generiert.

Linkt zum Modul im ExtRep: wp_uuid_creator

UPDATE:
jetzt als Erweiterung im ER verfügbar
Um es einfacher zu machen habe ich die Funktionalität in ein BE Modul gepackt und im ER hochgeladen, damit es weniger umständlich ist eine Korrektur zu machen.

Nach dem Update alle Bilder weg?

Bei mir wurde nach dem Update in tl_files das neue Feld UUID angelegt, jedoch sind in allen singleSRC und multiSRC (bzw. input-tyle fileTree) Feldern sowohl in Tabellen vom Core als auch von anderen Erweiterungen die alten varchar Werte geblieben und lediglich das Datenbankfeld auf binary(16) umgestellt. Dies hat zur Folge, dass im Frontend nicht mehr die korrekten Dateien ausgegeben werden, und im Backend zb. beim singleSRC Feld auch nicht mehr die korrekte Datei angezeigt wird.

Dieses Problem hat mich viele Nerven gekostet, da ich in laufenden Sites ja schlecht alle Bilder usw. nochmals neu zuweisen möchte/kann, und daher habe mir mit folgendem Skript das erspart, welches ich euch nicht vorenthalten will, wenn noch jemand dieses Problem hat.

Hierzu habe ich eine runonce.php Datei erstellt, die an die \Database\Updater Klasse angelehnt ist, sodass alle Datenbank-Felder, die den input-type fileTree haben mit den zugehörigen UUID bestückt werden.
Felder, in denen bereits eine UUID steht werden hier ignoriert.

 

So bin ich vorgehangen:

  1. Update Erweiterungen und dann Update auf 3.2.5

  2. die runonce.php angelegt

  3. Ins Backend gegangen und auf den Menüpunkt Erweiterunsgsverwaltung->Datenbank aktualisieren.
    ! Wichtig !, die Datenbank dann nicht aktualisieren, sondern wieder zurück gehen, da sonst Erweiterungen die noch eine alte DCA Anweisung haben die die Feldart von binary(16) wieder auf varchar zurückstellen beim Update.

  4. Dann alle Erweiterungen aktualisiert auf Letztstand für 3.2.5

 

LG und viel Spaß,
Johannes Pichler

PS: Link zum Issue in  GitHub
PPS: Backup der Datenbank vorab ist natürlich selbstverständlich... Zwinkernd

 

/**
 * If Contao was updated to >3.2 and the singleSRC and multiSCR values where
 * not changed from an numeric (integer) value to the new UUID an so all the
 * connections to the files are gone in backend and frontend, this runonce.php
 * will correct it and will replace the integers in the binary(16) fields to
 * an UUID.
 * 
 * Therefore it looks up for all fields with input-type fileTree and executes
 * on these fields only.
 *
 * @author johannespichler
 */
class correctUUIDS extends Contao\Controller {

    public function __construct() {
        parent::__construct();
    }

    public function run() {

        $this->import('Database');
        $this->updateFileTreeFields();
    }

    /**
     * Update all FileTree fields
     */
    public function updateFileTreeFields() {

        $arrFiles = array();


        foreach (scan(TL_ROOT . '/system/modules') as $strModule) {
            $strDir = 'system/modules/' . $strModule . '/dca';

            if (!is_dir(TL_ROOT . '/' . $strDir)) {
                continue;
            }

            foreach (scan(TL_ROOT . '/' . $strDir) as $strFile) {
                // Ignore non PHP files and files which have been included before
                if (substr($strFile, -4) != '.php' || in_array($strFile, $arrFiles)) {
                    continue;
                }

                $arrFiles[] = substr($strFile, 0, -4);
            }
        }

        $arrFields = array();

        // Find all fileTree fields
        foreach ($arrFiles as $strTable) {
            try {
                $this->loadDataContainer($strTable);
            } catch (\Exception $e) {
                continue;
            }

            $arrConfig = &$GLOBALS['TL_DCA'][$strTable]['config'];

            // Skip non-database DCAs
            if ($arrConfig['dataContainer'] == 'File') {
                continue;
            }
            if ($arrConfig['dataContainer'] == 'Folder' && !$arrConfig['databaseAssisted']) {
                continue;
            }

            // Make sure there are fields (see #6437)
            if (is_array($GLOBALS['TL_DCA'][$strTable]['fields'])) {
                foreach ($GLOBALS['TL_DCA'][$strTable]['fields'] as $strField => $arrField) {
                    // FIXME: support other field types
                    if ($arrField['inputType'] == 'fileTree') {
                        if ($this->Database->fieldExists($strField, $strTable, true)) {
                            $key = $arrField['eval']['multiple'] ? 'multiple' : 'single';
                            $arrFields[$key][] = $strTable . '.' . $strField;
                        }

                        // Convert the order fields as well
                        if (isset($arrField['eval']['orderField']) && isset($GLOBALS['TL_DCA'][$strTable]['fields'][$arrField['eval']['orderField']])) {
                            if ($this->Database->fieldExists($arrField['eval']['orderField'], $strTable, true)) {
                                $arrFields['order'][] = $strTable . '.' . $arrField['eval']['orderField'];
                            }
                        }
                    }
                }
            }
        }


        // Update the existing singleSRC entries
        if (isset($arrFields['single'])) {
            foreach ($arrFields['single'] as $val) {
                list($table, $field) = explode('.', $val);

                static::convertSingleField($table, $field);
            }
        }

        // Update the existing multiSRC entries
        if (isset($arrFields['multiple'])) {
            foreach ($arrFields['multiple'] as $val) {
                list($table, $field) = explode('.', $val);
                static::convertMultiField($table, $field);
            }
        }
        
    }

    /**
     * Convert a single source field to UUIDs
     *
     * @param string $table The table name
     * @param string $field The field name
     */
    public static function convertSingleField($table, $field) {


        $backup = $field . '_backup';


        $objDatabase = \Contao\Database::getInstance();
        // Backup temporarly the original column and then change the column type
        if (!$objDatabase->fieldExists($backup, $table, true)) {
            $objDatabase->query("ALTER TABLE `$table` ADD `$backup` varchar(255) NOT NULL default ''");
            $objDatabase->query("ALTER TABLE `$table` CHANGE `$field` `$field` binary(16) NULL");
        }
        $objDatabase->query("UPDATE `$table` SET `$backup` = '_'");



        $objRow = $objDatabase->query("SELECT id, $field, $backup FROM $table WHERE $backup !=''");

        while ($objRow->next()) {


            if (($objRow->$field) > 0) {



                $objFile = \FilesModel::findById(intval($objRow->$field));



                if ($objFile) {
                    $objDatabase->prepare("UPDATE $table SET $field=? WHERE id=?")
                            ->execute($objFile->uuid, $objRow->id);
                    $objDatabase->prepare("UPDATE $table SET $backup=? WHERE id=?")
                            ->execute($objRow->$field, $objRow->id);
                }
            }
        }
        $objDatabase->query("ALTER TABLE `$table` DROP `$backup` ");
    }

    /**
     * Convert a multi source field to UUIDs
     *
     * @param string $table The table name
     * @param string $field The field name
     */
    public static function convertMultiField($table, $field) {
        $backup = $field . '_backup';
        $objDatabase = \Database::getInstance();

        // Backup temporarly the original column and then change the column type
        if (!$objDatabase->fieldExists($backup, $table, true)) {
            $objDatabase->query("ALTER TABLE `$table` ADD `$backup` blob NULL");
            $objDatabase->query("ALTER TABLE `$table` CHANGE `$field` `$field` blob NULL");
        }
        $objDatabase->query("UPDATE `$table` SET `$backup` = '_'");

        $objRow = $objDatabase->query("SELECT id, $field, $backup FROM $table WHERE $backup!=''");

        while ($objRow->next()) {
            $arrPaths = deserialize($objRow->$backup, true);

            if (empty($arrPaths)) {
                continue;
            }

            foreach ($arrPaths as $k => $v) {

                if (($v) > 0) {
                    $objFile = \FilesModel::findByPk(intval($v));
                    if ($objFile) {
                    $arrPaths[$k] = $objFile->uuid;
                    }
                }
            }

            $objDatabase->prepare("UPDATE $table SET $field=? WHERE id=?")
                    ->execute(serialize($arrPaths), $objRow->id);
        }
        $objDatabase->query("ALTER TABLE `$table` DROP `$backup` ");
    }

}

$correct_it = new correctUUIDS();
$correct_it->run();

Zurück

Einen Kommentar schreiben

Kommentar von Chistine Szendi |

Hey, das Problem hatte ich doch auch schon mal!

Großes Danke, dass du sogar eine Erweiterung für alle draus gebastelt hast, ganz fein!

Liebe Grüße Christine

Antwort von Johannes Pichler

Hallo Christine!

echt, das Problem hattest du auch? Uiwei. Ich dachte bei dir waren die Zuordnungen von den 3.x tl_content zu den News nicht mehr in Ordnung. Wusste nicht mehr, dass bei dir auch die singleSRC und multiSRC weg waren...

Naja, habe ich gemacht, weil man einem Kunden ja schlecht sagen kann, er soll nach dem Updaten (falls was schiefgelaufen ist) wieder alle Zuordnungen manuell neu machen... Weinend

LG, Johannes