Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove an association on the fly in CakePHP v3

In previous versions of CakePHP you could temporarily alter associations with Table::bindModel('SomeModel'); but I can't figure out how to do it in v3.

I want to temporarily disable a hasMany association that's defined in the Table class because it's causing errors when I run older migrations that were written before that table existed. I don't fully understand the migration problem but it immediately goes away when I comment out the association in the Table class.

class AgenciesTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->table('agencies');
        $this->displayField('full_name');
        $this->primaryKey('id');
        $this->addBehavior('Timestamp');

        $this->hasMany('Routes');

enter image description here

like image 639
emersonthis Avatar asked Sep 01 '16 22:09

emersonthis


Video Answer


1 Answers

The issue here is that you should not rely on the actual model classes when using migrations. This can cause exactly the kind of issue you just encountered.

Instead use the TableRegistry or a Table object directly and create a table object without any dependencies. Load the associations you need directly on that object.

$agencies = new Table(['table' => 'agencies', /*...*/]);
$agencies->belongsTo('Whatever');
/* Do your data manipulation */

This way the migration will work no matter what other changes has been made to your AgenciesTable class. And this is IMHO the proper way of doing it in migrations.

I think that even if you don't create the association explicit by calling $this->hasMany('Routes'); you'll end up with the same error because the eager loader will still try to find a matching table class and load it dynamically. This is also the reason why there is no "uncontain" method.

Also you're not showing your actual query code... So I assume you're calling a custom find or method that calls Query::contain() somewhere. Just write a new query without that contain?

$agencies->find()->contain(['One', 'Two'])->where([/*...*/])->all();

If you have a big query it might be a good idea to break it up into more custom finds because they can be combined:

$agencies->find('withoutMyContain')->all();
$agencies->find('withoutMyContain')->find('withMyContain')->all();

See Custom Finder Methods.

like image 172
floriank Avatar answered Oct 03 '22 01:10

floriank