0

I have a table called Landmarks and a table called Categories with a HABTM relationship to each other. I am trying to retrieve all the categories for a specific Landmark with the following code:

$this->set('selected_categories', $this->Category->find('list',
    array('contain'=>array(
        'Landmarks'=>array(
           'conditions'=>array('Landmark.num'=>7)
)))));

I've tested the database query that results from this (as printed out in debug level 2), and it seems to get the right results, i.e. a subset of the Categories. However, when I var_dump $selected_categories in the view, I'm getting a list of ALL categories instead.

Am I missing something obvious here?

ETA: I told a lie when I said the above query was working. Something else on the page is generating the SQL query I want! Which is:

SELECT `Categories`.`num`, `CategoriesLandmark`.`category_num`,
  `CategoriesLandmark`.`landmark_num` 
FROM `categories` AS `Categories` JOIN `categories_landmarks` 
AS `CategoriesLandmark` ON (`CategoriesLandmark`.`landmark_num` = 7
AND `CategoriesLandmark`.`category_num` = `Categories`.`num`) WHERE 1 = 1
thesunneversets
  • 2,560
  • 3
  • 28
  • 46

1 Answers1

1

Specifying the find type as 'list' is incompatible with the Containable behavior.

Use joins instead to accomplish this:

$selectedCategories = $this->Category->find('list', array(
    'joins' => array(
        array(
            'table' => 'categories_landmarks',
            'alias' => 'CategoriesLandmark',
            'type' => 'inner',
            'conditions' => array("CategoriesLandmark.category_id = Category.id")
        ),
        array(
            'table' => 'landmarks',
            'alias' => 'Landmark',
            'type' => 'inner',
            'conditions' => array(
                "CategoriesLandmark.landmark_id = Landmark.id",
                'Landmark.num' => 7
            )
        ),
    )
));

I would ideally place this directly into the Category model like so:

function fetchListByLandmarkNum($landmarkNum) {
    return $this->find('list', array(
        'joins' => ...
    ));
}

And then call it from the controller:

$selectedCategories = $this->Category->fetchListByLandmarkNum(7);
$this->set(compact('selectedCategories'));

Always make your models fat and your controllers skinny. You can now reuse this function elsewhere. :)


The reason why ALL the categories are being returned is that the condition is applied on the related Landmark models. The result of this Containable query would be to fetch all the Categories, and return only those Landmark models which satisfy num = 7. It should NOT be interpreted as returning only those Categories for which the Landmark models satisfy the condition.

RabidFire
  • 6,280
  • 1
  • 28
  • 24
  • Yeah, I told a lie when I said my query was working - gonna re-edit my question. I think I tried changing 'list' to 'all', but I'll certainly try again! – thesunneversets Dec 02 '10 at 21:27
  • I just edited my answer actually. Try using joins. Setting it to 'all' would not work either. Will re-edit my answer to explain why. – RabidFire Dec 02 '10 at 21:28
  • Works really well... plus thanks for the extra help tidying stuff out of my controllers and into my models! – thesunneversets Dec 03 '10 at 18:41