Cakephp migrations: Rename fields and update values in database

Question

I'm trying to rename fields and update values on already inserted rows in cakephp migrations.

Workflow:
In before method i fetch all already added rows in my db so i will be able to update them in after method.
Then migration happens, which create columns value_from and value_to and also drops columns price_from and price_to
Then i try in my after method fetch all "new" rows, where i wan't to update values from old ones, but error happens, because find('all') method throws errors

My code:

class ShippingTypeCostCalculationM1483610977ProjectPluginLogistics extends CakeMigration {

    /**
     * Data which will be inserted in modified table shipping costs
     * @var
     */
    private $data;

/**
 * Migration description
 *
 * @var string
 * @access public
 */
    public $description = '';

/**
 * Actions to be performed
 *
 * @var array $migration
 * @access public
 */
    public $migration = array(
        'up' => array(
            'create_field' => array(
                'shipping_costs' => array(
                    'shipping_type' => array('type' => 'string', 'null' => false, 'default' => 'order_sum', 'length' => 20, 'collate' => 'utf8_unicode_ci', 'charset' => 'utf8', 'after' => 'customer_type'),
                    'value_from' => array('type' => 'decimal', 'null' => false, 'default' => NULL, 'length' => '10,4', 'after' => 'shipping_type'),
                    'value_to' => array('type' => 'decimal', 'null' => false, 'default' => NULL, 'length' => '10,4', 'after' => 'value_from'),
                ),
            ),
            'drop_field' => array(
                'shipping_costs' => array('price_from', 'price_to',),
            )
        ),
        'down' => array(
            'drop_field' => array(
                'shipping_costs' => array('shipping_type', 'value_from', 'value_to',),
            ),
        ),
        'create_field' => array(
            'shipping_costs' => array(
                'price_from' => array('type' => 'decimal', 'null' => false, 'default' => NULL, 'length' => '10,4'),
                'price_to' => array('type' => 'decimal', 'null' => false, 'default' => NULL, 'length' => '10,4'),
            ),
        )
    );

/**
 * Before migration callback
 *
 * @param string $direction, up or down direction of migration process
 * @return boolean Should process continue
 * @access public
 */
    public function before($direction) {
        $shippingCost = ClassRegistry::init('Logistics.ShippingCost');
        $this->data = $shippingCost->find('all');

        return true;
    }

/**
 * After migration callback
 *
 * @param string $direction, up or down direction of migration process
 * @return boolean Should process continue
 * @access public
 */
    public function after($direction) {

        $shippingCost = ClassRegistry::init('Logistics.ShippingCost');
        // This is where error happens
        $shippingCosts = $shippingCost->find('all');

        foreach ($this->data as $item) {
            $shippingCost = $shippingCosts->get($item['shipping_costs']['id']);
            $shippingCost->value_from = $item['shipping_costs']['price_from'];
            $shippingCost->value_to = $item['shipping_costs']['price_to'];
            $shippingCosts->save($shippingCost);
        }

        return true;
    }
}

PROBLEM: In after method, cake php is still trying to fetch values like price_from or price_to which are already deleted.

 SQLSTATE[42S22]: Column not found: 1054 Unknown column 'ShippingCost.price_from' in 'field list'   

How can i overcome my problem? If you need any additional informations, please let me know and i will provide. Thank you in advance!


Show source
| cakephp   | php   | cakephp-2.0   2017-01-05 14:01 1 Answers

Answers to Cakephp migrations: Rename fields and update values in database ( 1 )

  1. 2017-01-09 10:01

    You run the callbacks in any case, the code is always executed.

    public function after($direction) {...}
    

    See the argument? This can be up and down. You need to wrap your code that you want to run before or after applying the migration accordingly in a check like if ($direction === 'down') { ... }.

    Also I don't think your approach is well done. If you have a lot of data you can run out of memory.

    Create a migration that will add the new fields. Then another migration file that will just do the data transformation and process the data in chunks. And a third one that will delete the no longer needed fields after that. The simple reason is: Separate data from schema changes.

Leave a reply to - Cakephp migrations: Rename fields and update values in database

◀ Go back