Bug in CakePHP Containable Behavior, Related Records not Being Returned When Parent Contains a Single Field

I just stumbled on a bug in CakePHP that prevents related child records from being returned when only selecting a single field from the parent. It looks something like this:

$this->Model->find('all', array(
  'contain' => array(
    'Parent' => array(
      'fields' => array('id', 'type'),
      'Child' => array(
        'fields' => array('id', 'type')
      )
    )
  )
);
// Returns as expected
//array(
//  'Model' => array(...),
//  'Parent' => array(
//    'id' => '',
//    'type' => '',
//    'Child' => array(
//      array(
//        'id' => '',
//        'type' => ''
//      ),
//      ...
//    )
//  )
//)

Now if we modify the contain for Parent to only return one field we lose all Child records:

$this->Model->find('all', array(
  'contain' => array(
    'Parent' => array(
      'fields' => array('id'),
      'Child' => array(
        'fields' => array('id', 'type')
      )
    )
  )
);
// Returns no Child records
//array(
//  'Model' => array(...),
//  'Parent' => array(
//    'id' => '',
//    'type' => '',
//  )
//)

This is due to a bug in Model/DataSource/DboSource.php in the _mergeAssociation method. On line 1401 it checks count($merge[0][$association]) > 1 before it will merge the records. Since Parent only has one field, ‘id’, it does not do the merge. This has been corrected in CakePHP 2.4.2 to !empty() instead of count() > 1.

This has been fixed in the CakePHP master branch with this commit: https://github.com/cakephp/cakephp/commit/940a51b5faa0b88fa5334764c19f93fe8364ef30

Leave a Reply

Your email address will not be published. Required fields are marked *