Why does getSize() does not match cart collection size?

The question:

Question popped up here: Filter collection on checkout/cart

Why does a filtered $collection->getSize() returns correct value, but iterating over collection has more items?

  • three items are in cart
  • want to filter one by SKU
  • result should be only one item

Example code:

$items = Mage::getSingleton('checkout/cart')->getQuote()->getItemsCollection();
$items->addFieldToFilter('sku', 75782007);

Using var_dump($items->getSize()) correctly returns int 1, but …

foreach ($items as $item) {

… results in … (why?)

string '75782007' (length=8)
string '32811969' (length=8)
string 'hdd006' (length=6)


$itemIds = $items->getAllIds();
foreach ($items as $item) {
    if (in_array($item->getId(), $itemIds)) {

… results in …

string '75782007' (length=8)

Why is getSize() and getAllIds() correct, but does not fit to collection count?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

There are methods on the collection used for iterating. getVisibleItms is different from getAllItems. Depending upon the type of product, it could actually be that this one product is made up of a group or selection of products. Bundled products are an example of this. You will see only one item in cart but in the raw data it will show multiple products.

Method 2

You should always use the ORM methods as using PHPs count or looping over the collection is bad practice. The reasoning is most likely off by one errors, which you’ll most likely find buried some where in the framework such as varien collection.


* EDIT *
Link fixed.

Also the reasoning you’ll find in the Varien_Data_Collection class, as I mentioned if you were wanting to iterate over the collection, you’re much better off using an iterator like the class does as it’s a part of the framework’s ORM. most likely the one off is the fact that when getSize is called the returned value is set with intval into an integer. As a 0 will = false, on conditions, etc. Take a look at getLastPageNumber and it will make sense.

As for a much better means of iterations without running out of memory on large collections is:
// Walk through collection, for large collections this is much faster than using foreach
Mage::getSingleton('core/resource_iterator')->walk($collection->getSelect(), array('productUpdateCallback'));

Anyhow hopefully this explains it more.

Method 3

Sorry B00MER, Brett for wasting your time …

All is working as intended …


… just returns an already loaded collection that is stored in customer/session – so addFieldToFilter() has no affect here.

getSize() and getAllIds() gives “wrong” results because it does not count the items in that collection … it’s just runs another query to get number of rows or get the IDs where addFieldToFilter() is also applied.

So $items->getSize() returns 1, but count($items) still gives 3.

Maybe someone can confirm this explanation?

Method 4

The difference between getSize() and count() is here Marius explanation

getSize() the collection is not loaded, count() it is, that why you get int(1) in getSize() and int(3) in count() .

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment