Contain() in Table::beforeFind() sometimes causes issues in Cakephp4 (especially with Muffin/SlugBehavior)

Hi,

I have the following association : Products hasMany Photos.
My ProductsTable uses Muffin/SlugBehavior to build a unique slug on products.

In order to automatically get Photos related to a Product each time I find a Product, I made contain() in ProductsTable::beforefind(). I need contain() not in Controller.

Here is my ProductsTable :

// ProductsTable
class ProductsTable extends Table
{
   public function initialize(array $config): void
   {
      $this->hasMany('Photos');

      $this->addBehavior('Muffin/Slug.Slug', [
         'displayField' => 'title', // 'title' is the field I want to build a unique slug from.
      ]);
   }

   public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
   {
      $query->contain('Photos');
      return $query;
   }
}

In most cases it works well, but an issue happens when I try to create a Product with an already existing title (that will generate an existing slug).

I have the following InvalidArgumentException : Unable to load Photos association. Ensure foreign key in Products is selected. The exception is thrown in Muffin/SlugBehavior::_uniqueSlug() at the line $this->_table->exists($conditions).

I don’t understand exactly what’s the problem…

Could anybody tell me how to fix it ?

Fetching the related Photos requires the primary query to select the id field. Table::exists() sets a custom fields list which doesn’t include the id field which is what’s causing your problem.

The solution is to either:

  1. Add $query->enableAutoField() in your beforeFind() so that the required field auto selected for your contain to work or use a custom.
  2. Instead of beforeFind() use a custom finder which contains the Photos.

Thanks for the tip !