Skip to content

Instantly share code, notes, and snippets.

@joshangell
Last active February 1, 2016 14:07
Show Gist options
  • Save joshangell/26d6413a1eb243d4e8a1 to your computer and use it in GitHub Desktop.
Save joshangell/26d6413a1eb243d4e8a1 to your computer and use it in GitHub Desktop.

Revisions

  1. joshangell renamed this gist Jan 22, 2016. 1 changed file with 4 additions and 6 deletions.
    10 changes: 4 additions & 6 deletions gistfile1.txt → MyPluginController.php
    Original file line number Diff line number Diff line change
    @@ -9,15 +9,13 @@ class MyPluginController extends BaseController

    /**
    * Start the migration Task
    */
    public function actionMigrate()
    */
    public function actionMigrate()
    {

    // Create the Task
    craft()->tasks->createTask('MyPlugin_MigrateManager');

    if (!craft()->tasks->isTaskRunning())
    {
    if (!craft()->tasks->isTaskRunning()) {
    // Is there a pending task?
    $task = craft()->tasks->getNextPendingTask();

    @@ -31,6 +29,6 @@ public function actionMigrate()
    craft()->tasks->runPendingTasks();
    }
    }

    }

    }
  2. joshangell revised this gist Jan 22, 2016. 3 changed files with 57 additions and 6 deletions.
    2 changes: 1 addition & 1 deletion MyPlugin_MigrateManagerTask.php
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@ public function getTotalSteps()
    $criteria->enabled = null;
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->sectionId = 15;
    $criteria->sectionId = 15; // The ID of the section we are copying from
    $elements = $criteria->find();

    // Chunk the elements into groups of 10 - if the content is quite
    25 changes: 20 additions & 5 deletions MyPlugin_MigrateTask.php
    Original file line number Diff line number Diff line change
    @@ -48,18 +48,18 @@ public function runStep($step)
    $criteria->enabled = null;
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->sectionId = 22;
    $criteria->sectionId = 22; // The ID of the section we are copying to
    $criteria->title = $element->getContent()->title;
    $targetElement = $criteria->first();

    // If we didn’t get an existing element, make one here
    if (!$targetElement) {
    $targetElement = new EntryModel();
    $targetElement->sectionId = 22;
    $targetElement->typeId = 23;
    $targetElement->typeId = 23; // The ID of the Entry Type we want
    }

    // XXX This is where it gets fun - copy your field content!
    // NOTE: This is where it gets fun - copy your field content!

    // Copy the blocks from a Matrix field - be aware that if the target
    // element already exists and has blocks they will be lost.
    @@ -71,7 +71,7 @@ public function runStep($step)
    {
    // Setup a new block
    $newBlock = new MatrixBlockModel();
    $newBlock->fieldId = 4;
    $newBlock->fieldId = 4; // Whatever the ID of `myMatrixField` is
    $newBlock->typeId = $block->getType()->id;
    $newBlock->ownerId = $targetElement->id;
    $newBlock->locale = $block->locale;
    @@ -90,6 +90,7 @@ public function runStep($step)
    if (in_array($field->type, array('Assets', 'Entries', 'Categories', 'Tags'))) {
    $value = $block->$fieldHandle->ids();
    } else {
    // For ‘normal’ fields just copy their content directly
    $value = $block->$fieldHandle;
    }

    @@ -105,16 +106,30 @@ public function runStep($step)

    // Set the content on the target element
    $targetElement->setContent(array(

    // Don’t forget a title!
    'title' => $element->getContent()->title,

    // Here are the Matrix blocks we just made
    'myMatrixField' => $newBlocks,

    // Same as before, just get the IDs of relationship fields
    // Same as inside the Matrix, just get the IDs of relationship fields
    'someAssetField' => $element->someAssetField->ids(),

    // Simpler fields can just be directly copied
    'someSimpleTextField' => $element->someSimpleTextField,
    ));

    // Keep a bunch of attributes
    $targetElement->setAttributes(array(
    'slug' => $sourceElement->slug,
    'postDate' => $sourceElement->postDate,
    'expiryDate' => $sourceElement->expiryDate,
    'enabled' => $sourceElement->enabled,
    'archived' => $sourceElement->archived,
    'localeEnabled' => $sourceElement->localeEnabled,
    ));

    // Wrap in a transaction in case something goes wrong
    $transaction = craft()->db->getCurrentTransaction() === null ? craft()->db->beginTransaction() : null;
    try {
    36 changes: 36 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    <?php
    namespace Craft;

    class MyPluginController extends BaseController
    {

    // This lets anyone run the controller actions we specify, useful for CRON etc
    protected $allowAnonymous = array('actionMigrate');

    /**
    * Start the migration Task
    */
    public function actionMigrate()
    {

    // Create the Task
    craft()->tasks->createTask('MyPlugin_MigrateManager');

    if (!craft()->tasks->isTaskRunning())
    {
    // Is there a pending task?
    $task = craft()->tasks->getNextPendingTask();

    if ($task) {
    // Attempt to close the connection if this is an Ajax request
    if (craft()->request->isAjaxRequest()) {
    craft()->request->close();
    }

    // Start running tasks
    craft()->tasks->runPendingTasks();
    }
    }

    }
    }
  3. joshangell created this gist Jan 18, 2016.
    62 changes: 62 additions & 0 deletions MyPlugin_MigrateManagerTask.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,62 @@
    <?php

    namespace Craft;

    class MyPlugin_MigrateManagerTask extends BaseTask
    {

    private $_elements;

    /**
    * @inheritDoc ITask::getDescription()
    *
    * @return string
    */
    public function getDescription()
    {
    return Craft::t('Migrating old content');
    }

    /**
    * @inheritDoc ITask::getTotalSteps()
    *
    * @return int
    */
    public function getTotalSteps()
    {
    // Setup the criteria for finding the elements we want to migrate
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->enabled = null;
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->sectionId = 15;
    $elements = $criteria->find();

    // Chunk the elements into groups of 10 - if the content is quite
    // light you may want to up this to 100 or so
    $this->_elements = array_chunk($elements, 10);

    return count($this->_elements);
    }

    /**
    * @inheritDoc ITask::runStep()
    *
    * @param int $step
    *
    * @return bool
    */
    public function runStep($step)
    {
    // I frequently found I ran out of memory doing these sort of operations
    // so just bumped up what Craft is allowed to use here - in this to 2.5GB
    craft()->config->set('phpMaxMemoryLimit', '2560M');
    craft()->config->maxPowerCaptain();

    // Run the migration as a sub Task with the current chunk of elements
    return $this->runSubTask('MyPlugin_Migrate', null, array(
    'elements' => $this->_elements[$step]
    ));
    }

    }
    171 changes: 171 additions & 0 deletions MyPlugin_MigrateTask.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,171 @@
    <?php

    namespace Craft;

    class MyPlugin_MigrateTask extends BaseTask
    {

    /**
    * @inheritDoc ITask::getDescription()
    *
    * @return string
    */
    public function getDescription()
    {
    return Craft::t('Migrating ...');
    }

    /**
    * @inheritDoc ITask::getTotalSteps()
    *
    * @return int
    */
    public function getTotalSteps()
    {
    return count($this->getSettings()->elements);
    }

    /**
    * @inheritDoc ITask::runStep()
    *
    * @param int $step
    *
    * @return bool
    */
    public function runStep($step)
    {
    // Again, bump the memory
    craft()->config->set('phpMaxMemoryLimit', '2560M');
    craft()->config->maxPowerCaptain();

    // Get the element we want to copy from
    $element = $this->getSettings()->elements[$step];

    // See if the one we are copying to already exists.
    // What you use to determine this will vary, in this case I just
    // used the title but you may need something more bullet proof.
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->enabled = null;
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->sectionId = 22;
    $criteria->title = $element->getContent()->title;
    $targetElement = $criteria->first();

    // If we didn’t get an existing element, make one here
    if (!$targetElement) {
    $targetElement = new EntryModel();
    $targetElement->sectionId = 22;
    $targetElement->typeId = 23;
    }

    // XXX This is where it gets fun - copy your field content!

    // Copy the blocks from a Matrix field - be aware that if the target
    // element already exists and has blocks they will be lost.
    // ref: https://craftcms.stackexchange.com/questions/8517/duplicating-matrix-fields-with-content-from-another-locale
    $newBlocks = array();
    $i = 0;

    foreach ($element->myMatrixField->find() as $block)
    {
    // Setup a new block
    $newBlock = new MatrixBlockModel();
    $newBlock->fieldId = 4;
    $newBlock->typeId = $block->getType()->id;
    $newBlock->ownerId = $targetElement->id;
    $newBlock->locale = $block->locale;

    $newBlockContent = $newBlock->getContent();

    $values = array();

    // Loop the fields on this block
    foreach ($block->getFieldLayout()->getFields() as $blockFieldLayoutField)
    {
    $field = $blockFieldLayoutField->getField();
    $fieldHandle = $field->handle;

    // Cope with element fields by getting an array of their IDs
    if (in_array($field->type, array('Assets', 'Entries', 'Categories', 'Tags'))) {
    $value = $block->$fieldHandle->ids();
    } else {
    $value = $block->$fieldHandle;
    }

    $values[$fieldHandle] = $value;
    }

    // Set the content on the new block
    $newBlock->setContentFromPost($values);

    $newBlocks['new'.$i] = $newBlock;
    $i++;
    }

    // Set the content on the target element
    $targetElement->setContent(array(
    'title' => $element->getContent()->title,
    'myMatrixField' => $newBlocks,

    // Same as before, just get the IDs of relationship fields
    'someAssetField' => $element->someAssetField->ids(),

    // Simpler fields can just be directly copied
    'someSimpleTextField' => $element->someSimpleTextField,
    ));

    // Wrap in a transaction in case something goes wrong
    $transaction = craft()->db->getCurrentTransaction() === null ? craft()->db->beginTransaction() : null;
    try {

    // Try and save, throw an exception if it didn’t for some reason
    if (!craft()->entries->saveEntry($targetElement)) {

    // Try and get the errors so the log is more useful
    if ($targetElement->hasErrors()) {
    $firstError = array_shift($targetElement->getErrors())[0];
    throw new Exception(Craft::t('Couldn’t migrate from {title}. First error to correct: {error}', array('title' => $element->title, 'error' => firstError)));
    } else {
    throw new Exception(Craft::t('Couldn’t migrate from {title}.', array('title' => $element->title)));
    }

    }

    if ($transaction !== null)
    {
    $transaction->commit();
    }

    } catch (Exception $e) {

    if ($transaction !== null)
    {
    $transaction->rollback();
    }

    // Log that exception message so we can debug it in the log viewer
    MyPlugin::log($e->getMessage(), LogLevel::Error);
    return $e->getMessage();

    }

    return true;

    }

    /**
    * @inheritDoc BaseSavableComponentType::defineSettings()
    *
    * @return array
    */
    protected function defineSettings()
    {

    return array(
    'elements' => AttributeType::Mixed
    );

    }

    }