Search code examples
phpcakephp-3.0database-migrationphinx

Dynamically add columns in an existing table on the fly in CakePHP 3


I want to add column in my existing table in CakePHP 3.

My ContactsTable.php file code:

<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Migrations\AbstractMigration;

class ContactsTable extends Table
{
    public function initialize(array $config)
    {
        $this->addBehavior('Timestamp');
        $table = $this->table('contacts');
        $table->addColumn('price', 'decimal')->update();

    }
}

I have tried as described in CakePHP 3 documentation but I got this error:

Call to a member function addColumn() on a non-object

How do I add columns on-the-fly via the controller?


Solution

  • Code:

    <?php
    
    namespace App\Controller;
    
    use Cake\Core\Configure;
    use Cake\Network\Exception\NotFoundException;
    use Cake\View\Exception\MissingTemplateException;
    use Cake\ORM\TableRegistry;
    use Cake\Database\Schema\Table;
    use Cake\Datasource\ConnectionManager;
    use \Migrations\AbstractMigration as AbstractMigration;
    use \Phinx\Db\Adapter\MysqlAdapter as MysqlAdapter;
    
    class PagesController extends AppController
    {
        public function display()
        {
            $connectionArray = ConnectionManager::get('default')->config();
            $connectionArray['pass'] = $connectionArray['password'];
            $connectionArray['user'] = $connectionArray['username'];
            $connectionArray['name'] = $connectionArray['database'];
    
            $migrationObject = new AbstractMigration(mt_rand());
            $migrationObject->setAdapter(new MysqlAdapter($connectionArray));
            $tree = $migrationObject->table('tests');
            
    
            $tree->addColumn('something', 'text')
                            ->update();
        }
    }
    

    After few hours of Hacking, finally found a way to do it on-the-fly.

    Tested in default cakephp 3 (latest - as of today - 2nd June '16)

    If you are using a different database adapter, change it to that adapater from MysqlAdapter.

    Note to the users:

    • This is an ugly hack and should be used ONLY if you do not work in an organization where each migration commit requires peer reference.

    • mt_rand() must NEVER be used as a version number hack.

    • There is no canonical way of doing it via the controllers. Update in a datasource MUST always be done modified via migrations - using a proper structure.

    • Refer to Running Migrations in a non-shell environment and try to create a migrations logs under /config/migrations, that would be more rule-specific-on-the-fly and you will also have logs for peers to review.