Benjamin Allison
Benjamin Allison

Reputation: 2154

CakePHP: afterFind is weird with associations

So afterFind works fine and dandy when I'm within the corresponding model/controller. However, when calling an associated model, the data sent to the afterFind callback is formatted differently. This causes afterFind to crap out because it can't find the same array indexes it did when just working within the original model/controller.

Anyone know why, or what a fix might be?

Upvotes: 3

Views: 2596

Answers (3)

Dom Stubbs
Dom Stubbs

Reputation: 1218

It appears that Cake 2.6 includes a fix for this, ensuring that all $results arrays are consistently formatted. I've done a little testing with the RC release and it does seem to work, with arrays all being passed in the format {n}.ModelName.data.

The fix is enabled by default, but you can also revert to the legacy behaviour if need be. Just add the following to your model (or AppModel) definition:

public $useConsistentAfterFind = false;

Upvotes: 1

gapple
gapple

Reputation: 3474

$primary may not be very helpful; I've found that it is always false when using ContainableBehaviour beyond the first depth:

$this->Model->find('first', array(
  'contain' => array(
    'SecondaryModel' => array(
      'TertiaryModel',
    ),
  ),
));

If you're setting a value based on a related model, you can check for its presence to deal with either structure like this:

function afterFind($results, $primary) {
  if (isset($results['TertiaryModel'])) {
    $results['secondary_model_field'] = 'value';
  }
  else {
    foreach ($results as &$result) {
      if (is_array($result) && isset($result['TertiaryModel'])) {
        $result[$this->alias]['secondary_model_field'] = 'value';
      }
    } unset($result);
  }

  return $results;
}

Alternately you may be able to just check for the location of a field on the model itself. If the field doesn't exist at the top level, you will need to iterate over the set of results.

Upvotes: 3

tigrang
tigrang

Reputation: 6767

This is what the second parameter to afterFind callback is for.

$primary tells if you if the find was called from this model directly (true), or if it was called by an associated model (false).

A note from the book:

The $primary parameter indicates whether or not the current model was the model that the query originated on or whether or not this model was queried as an association. If a model is queried as an association the format of $results can differ;

Code expecting $primary to be true will probably get a "Cannot use string offset as an array" fatal error from PHP if a recursive find is used.

So you may need different processing logic depending on the value of $primary

Upvotes: 2

Related Questions