Version: current

      1 <?php
      2 /**
      3  * Migrates the old Translatable datamodel introduced in SilverStripe 2.1 to the new schema
      4  * introduced in SilverStripe 2.3.2.
      5  * Just works for {@link SiteTree} records and subclasses. If you have used the Translatable
      6  * extension on other {@link DataObject} subclasses before, this script won't migrate them automatically.
      7  *
      8  * <h2>Limitations</h2>
      9  *
     10  * - Information from the {@link Versioned} extension (e.g. in "SiteTree_versions" table)
     11  *   will be discarded for translated records.
     12  * - Custom translatable fields on your own {@link Page} class or subclasses thereof won't
     13  *   be migrated into the translation.
     14  * - 2.1-style subtags of a language (e.g. "en") will be automatically disambiguated to their full
     15  *   locale value (e.g. "en_US"), by the lookup defined in {@link i18n::get_locale_from_lang()}.
     16  * - Doesn't detect published translations when the script is run twice on the same data set
     17  *
     18  * <h2>Usage</h2>
     19  *
     20  * PLEASE BACK UP YOUR DATABASE BEFORE RUNNING THIS SCRIPT.
     21  *
     22  * Warning: Please run dev/build on your 2.2 database to update the schema before running this task.
     23  * The dev/build command will rename tables like "SiteTree_lang" to "_obsolete_SiteTree_lang".
     24  *
     25  * <h3>Commandline</h3>
     26  * Requires "sake" tool (see http://doc.silverstripe.com/?id=sake)
     27  * <example>
     28  * sake dev/tasks/MigrateTranslatableTask
     29  * </example>
     30  *
     31  * <h3>Browser</h3>
     32  * <example>
     33  * http://mydomain.com/dev/tasks/MigrateTranslatableTask
     34  * </example>
     35  *
     36  * @package sapphire
     37  * @subpackage tasks
     38  */
     39 class MigrateTranslatableTask extends BuildTask {
     40     protected $title = "Migrate Translatable Task";
     41
     42     protected $description = "Migrates site translations from SilverStripe 2.1/2.2 to new database structure.";
     43
     44     function init() {
     45         parent::init();
     46
     47         $canAccess = (Director::isDev() || Director::is_cli() || Permission::check("ADMIN"));
     48         if(!$canAccess) return Security::permissionFailure($this);
     49     }
     50
     51     function run($request) {
     52         $ids = array();
     53
     54         echo "#################################\n";
     55         echo "# Adding translation groups to existing records" . "\n";
     56         echo "#################################\n";
     57
     58         $allSiteTreeIDs = DB::query('SELECT "ID" FROM "SiteTree"')->column();
     59         if($allSiteTreeIDs) foreach($allSiteTreeIDs as $id) {
     60             $original = DataObject::get_by_id('SiteTree', $id);
     61             $existingGroupID = $original->getTranslationGroup();
     62             if(!$existingGroupID) $original->addTranslationGroup($original->ID);
     63             $original->destroy();
     64             unset($original);
     65         }
     66
     67         DataObject::flush_and_destroy_cache();
     68
     69         echo sprintf("Created translation groups for %d records\n", count($allSiteTreeIDs));
     70
     71         foreach(array('Stage', 'Live') as $stage) {
     72             echo "\n\n#################################\n";
     73             echo "# Migrating stage $stage" . "\n";
     74             echo "#################################\n";
     75
     76             $suffix = ($stage == 'Live') ? '_Live' : '';
     77
     78             // First get all entries in SiteTree_lang
     79             // This should be all translated pages
     80             $trans = DB::query(sprintf('SELECT * FROM "_obsolete_SiteTree_lang%s"', $suffix));
     81
     82             // Iterate over each translated pages
     83             foreach($trans as $oldtrans) {
     84                 $newLocale = i18n::get_locale_from_lang($oldtrans['Lang']);
     85
     86                 echo sprintf(
     87                     "Migrating from %s to %s translation of '%s' (#%d)\n",
     88                     $oldtrans['Lang'],
     89                     $newLocale,
     90                     Convert::raw2xml($oldtrans['Title']),
     91                     $oldtrans['OriginalLangID']
     92                 );
     93
     94                 // Get the untranslated page
     95
     96                 $original = Versioned::get_one_by_stage(
     97                     $oldtrans['ClassName'],
     98                     $stage,
     99                     '"SiteTree"."ID" = ' .  $oldtrans['OriginalLangID']
    100                 );
    101
    102                 if(!$original) {
    103                     echo sprintf("Couldn't find original for #%d", $oldtrans['OriginalLangID']);
    104                     continue;
    105                 }
    106
    107                 // write locale to $original
    108                 $original->Locale = i18n::get_locale_from_lang(Translatable::default_lang());
    109                 $original->writeToStage($stage);
    110
    111                 // Clone the original, and set it up as a translation
    112                 $existingTrans = $original->getTranslation($newLocale, $stage);
    113
    114                 if($existingTrans) {
    115                     echo sprintf("Found existing new-style translation for #%d. Already merged? Skipping.\n", $oldtrans['OriginalLangID']);
    116                     continue;
    117                 }
    118
    119                 // Doesn't work with stage/live split
    120                 //$newtrans = $original->createTranslation($newLocale);
    121
    122                 $newtrans = $original->duplicate(false);
    123                 $newtrans->OriginalID = $original->ID;
    124                 // we have to "guess" a locale based on the language
    125                 $newtrans->Locale = $newLocale;
    126                 if($stage == 'Live' && array_key_exists($original->ID, $ids)) {
    127                     $newtrans->ID = $ids[$original->ID];
    128                 }
    129
    130                 // Look at each class in the ancestry, and see if there is a _lang table for it
    131                 foreach(ClassInfo::ancestry($oldtrans['ClassName']) as $classname) {
    132                     $oldtransitem = false;
    133
    134                     // If the class is SiteTree, we already have the DB record, else check for the table and get the record
    135                     if($classname == 'SiteTree') {
    136                         $oldtransitem = $oldtrans;
    137                     } elseif(in_array(strtolower($classname) . '_lang', DB::tableList())) {
    138                         $oldtransitem = DB::query(sprintf(
    139                             'SELECT * FROM "_obsolete_%s_lang%s" WHERE "OriginalLangID" = %d AND "Lang" = \'%s\'',
    140                             $classname,
    141                             $suffix,
    142                             $original->ID,
    143                             $oldtrans['Lang']
    144                         ))->first();
    145                     }
    146
    147                     // Copy each translated field into the new translation
    148                     if($oldtransitem) foreach($oldtransitem as $key => $value) {
    149                         if(!in_array($key, array('ID', 'OriginalLangID'))) {
    150                             $newtrans->$key = $value;
    151                         }
    152                     }
    153
    154                 }
    155
    156                 // Write the new translation to the database
    157                 $sitelang = Translatable::get_current_locale();
    158                 Translatable::set_current_locale($newtrans->Locale);
    159                 $newtrans->writeToStage($stage);
    160                 Translatable::set_current_locale($sitelang);
    161
    162                 $newtrans->addTranslationGroup($original->getTranslationGroup(), true);
    163
    164
    165                 if($stage == 'Stage') {
    166                     $ids[$original->ID] = $newtrans->ID;
    167                 }
    168             }
    169         }
    170
    171         echo "\n\n#################################\n";
    172         echo "Done!\n";
    173     }
    174 }
    175
    176 ?>

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -