I'm trying to write a script to get a category given its path, which seems like it should be easy to do. As a test, I have a base category with an ID of 2, and it has 2 children, 'Foo' and 'Bar'. I'm using this code to try to get the 'Foo' category:
// Get the 'base' category.
$category = Mage::getModel('catalog/category')->load(2);
// Try to filter it out so that I only get 'Foo'
$category = $category->getChildrenCategories()->addFieldToFilter('name', 'Foo');
At this point, calling print_r($category->getData());
shows that it should be doing what I want:
Array
(
[0] => Array
(
[entity_id] => 16
[entity_type_id] => 3
[attribute_set_id] => 0
[parent_id] => 2
[created_at] => 2016-06-25 22:47:23
[updated_at] => 2016-06-25 22:47:23
[path] => 1/2/16
[position] => 2
[level] => 2
[children_count] => 28
[request_path] =>
[is_active] => 1
[name] => Foo
)
)
There is 1 item in the collection, and it's the one I'm looking for. However, then I do:
$category = $category->getFirstItem();
print_r($category->getData());
I expect it to select the 'Foo' category, but it's selecting the 'Bar' category instead:
Array
(
[entity_id] => 5
[entity_type_id] => 3
[attribute_set_id] => 0
[parent_id] => 2
[created_at] => 2016-06-25 22:42:19
[updated_at] => 2016-06-25 22:42:19
[path] => 1/2/5
[position] => 1
[level] => 2
[children_count] => 87
[request_path] =>
[is_active] => 1
[name] => Bar
[url_key] => bar
[is_anchor] => 1
)
I'm assuming at this point that getFirstItem()
just gets the first item in the whole collection and ignores the filters, but I can't seem to find any documentation for it (although it's used in just about every example I've found). This method doesn't seem to exist in the collection class.
Am I missing a step somewhere? Where can I find the documentation for this method?
Update: I forgot to mention, but this is in Magento 1.9
Best Answer
getFirstItem()
is defined inVarien_Data_Collection
which is the data source independent base class for all collections:It does what you think it does, loads the collection (if not already loaded) and returns the first item. getFirstItem() is not your problem.
Although you should always call
setPageSize(1)
beforegetFirstItem()
, if you only need the first item, otherwise all items that match the filters are loaded which can easily hurt performance.The problem is that
getChildrenCategories()
immediately loads the children collection, so filters that you add afterwards do not have any effect.Now there is one additional trap, that you fell into:
getData()
on collections works different from other methods. It does not check if the collection is loaded, instead it checks if the_data
property is empty. When you load a collection,_data
is not populated, only when you callgetData()
!This results in a second database query as soon as you call
getData()
and this time, your new filter is applied. But it does not change the_items
property, so your previously loaded result is still used for everything else.By the way, I still did not come across any reasonable use case for this method. It's used internally by
load()
but probably should not have been public. The core doesn't use it from outside the collection class anywhere as far as I see.Solution
Clear the collection (which resets
_items
and marks it as not loaded):