CakePHP — limiting results from one model to those with matching conditions in an associated model

StackOverflow https://stackoverflow.com/questions/8734241

  •  14-04-2021
  •  | 
  •  

Question

I'm just getting started in CakePHP, and am running into trouble limiting retrieved results to those where a field in an associated model matches a certain value. I've found a lot of related questions here and elsewhere, but they seem to deal with situations that are either more complicated or more simple than my scenario, so here we go:

I have two models that I'm interested in: Image, and Collection, which are associated by a HABTM relationship. The relationship is set up in Image.php and Collection.php correctly through join table collections_images, and I've had no issue writing or retrieving data in general. Containable is also set up properly in the Image model.

What I would like to do is run find() on $this->Image, and return only those that belong to a particular collection, whose title is $collection. I have tried this a couple different ways:

$this->Image->contain("Collection"); // to exclude other models "Image" is related to

pr($this->Image->find("all", 
                       array("conditions" => array("Collection.title" => $collection))
                      ));

For this, I get the following error:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Collection.title' in 'where clause'

It seems you cannot directly establish a search condition through a related model, so I went back and tried to limit my contain as follows:

$this->Image->contain(array(
                          "Collection" => array(
                              "conditions" => array(
                                  "Collection.title" => $collection))));

pr($this->Image->find("all"));

This time I get results, but they include Images that do not belong to the right collection. Here is a simplified snippet that the pr() gives me for $collection = "Urban":

[3] => Array
    (
        [Image] => Array
            (
                [id] => 39
                [title] => Star Trails over Greenlake
            )

        [Collection] => Array
            (
            )
    )

[4] => Array
    (
        [Image] => Array
            (
                [id] => 40
                [title] => Aurora Bridge and Reflections

            )

        [Collection] => Array
            (
                [0] => Array
                    (
                        [id] => 3
                        [title] => Urban
                        [CollectionsImage] => Array
                            (
                                [id] => 62
                                [collection_id] => 3
                                [image_id] => 40
                            )

                    )

            )

    )

As you can see, it is omitting Collection data for the Images where the Collection title does not match $collection, but it is still including the Image data.

What am I missing here? Is there a way to make either of these two approaches do what I'm aiming for?

For the record, I have also gone about it from the other direction:

$this->Collection->find("all", array("conditions" => array("Collection.title" => $collection)))

which returns just the desired data. However, the array structure of the data it returns creates complications elsewhere in my code, and I'd like to eventually be able to paginate directly off of Image.

Thanks for your time and help, everyone.

EDIT:

After additional searching, I've found an acceptable solution here:

http://cakebaker.42dh.com/2007/10/17/pagination-of-data-from-a-habtm-relationship/

This required me to create a model for the mapping table "CollectionsImage.php" and establish hasOne relationships to both Image and Collection. The paginate() is then performed on CollectionsImage, like so:

$data = $this->paginate("CollectionsImage", array("Collection.id" => $collection_id));

This seems a little roundabout and requires an extra step for me in finding the id for a collection with a specified title, so I'm still wondering if anyone knows a more direct solution.

Was it helpful?

Solution

If you want to retrieve the images that belongs to a particular collection, it means that you are actually willing to retrieve a collection with its related images. I would do something like this :

<?php
    $this->Image->Collection->find('first', array(
      'conditions' => array('Collection.title' => 'Urban'),
      'contain' => array(
        'Image'
      )
    ));
?>

OTHER TIPS

I've written a quite lengthy article on the subtleties of HABTM models and CakePHP. You might find it worthwhile: http://www.24100.net/2012/07/cakephp-hasandbelongstomany-relationship-queries-demystified/.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top