Question

I have one collection in a method where I want to perform two different operations on this collection. So, I want two separate copies of same collection, and then assign one of the two collections to original collection again and return it.

To make this simple, suppose I have an object collection called $collection.

Now, I am trying it with PHP cloning as I don't know if there is any Magento collection cloning inbuilt or not.

$coll1 = clone $collection;
$coll2 = clone $collection;

Now I am trying to perform different operations on these two separate clones of the original collection, something like.

$coll1->getSelect()->where('some where condition');
$coll2->getSelect()->where('some different where condition');
if($coll1->count() == 0) {
    $collection = $coll2;
} else {
    $collection = $coll1;
}

But the weird thing is, both these cloned collections have both the where conditions assigned! $coll1 condition is applied to $coll2 along with $coll2's condition, and vice versa.

Does anyone know how to achieve this?

Thanks!

Was it helpful?

Solution

Use of the PHP clone operator, where deep cloning is desired, requires classes which store objects on properties implement a __clone method to copy the objects. If they don't define it, the properties on both instances will reference the same object.

Magento does not implement __clone on it's collection abstracts, and therefore does not support deep cloning as you want it to.

My suggestion is to look for other ways to accomplish what you are wanting to do, as cloning a collection could be pretty expensive.

The example you gave (for instance) could be changed to clone the select, modify it to select a count of the records it would have loaded and then based on that result modify the collection. This would also perform better since you would not be loading a collection and counting it just to determine which one to use.

EDIT: The following demonstrates how to grab a count without loading or actually modifying the collection.

$collection = Mage::getModel(...)->getCollection();

$count = $collection->getSelectCountSql();
$count->where('some where condition');
if ($count->query()->fetchColumn() == 0) {
    ...
} else {
    ...
}

OTHER TIPS

To expand on @davidalger's answer, you can reset the select if you want to do a different operation than a count - like so:

$select= $collection->getSelectCountSql()->reset();

$select
    ->from('newsletter_subscriber', array('some_column'))
    ->distinct();

Be careful though, this could have detrimental effects later in the process since this modifies the collection.

A better way would be to clone the select somehow, but a shallow copy wouldn't cut it since the object contains complex types (Varien_Db_Select nor Zend_Db_Select have a __clone method).

One way to get around this is to save the select data, modify it, run your query, then put back the original select data.

See here for an example: https://ka.lpe.sh/2013/05/23/magento-clone-collection-how-to-clone-collection-in-magento/

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top