3

does anyone have an idea, how can I split one collection of entities in Magento into three equal independent collections?

Following example:

$_category = Mage::getModel('catalog/category')->load(129);
$_category_children = $_category->getChildrenCategories();

In $_category_children I have a collection of subcategories of the category with ID=129. Let's say, there are 30 subcategories there. Now I want to get three collections of it:

$_category_children_1 -> independent collection with items 1-10 of $_category_children
$_category_children_2 -> independent collection with items 11-20 of $_category_children
$_category_children_3 -> independent collection with items 21-30 of $_category_children

I already tried http://php.net/manual/function.array-chunk.php, but it doesn't help, but only returns NULL.

Thanks a lot in advance for the help!

2
  • have you tried using the same collection but using only something like entity_id 1-10 for x, entity_id 11-20 for y, and entity_id 21-30 for z? For example, you can build and load that initial collection, then simply filter it based upon entity IDs later on to create 3 different collections. What is the purpose of this split collection? Feb 12, 2015 at 16:15
  • Thank you for the answer! I need splitting for some custom menu rendering - only this way I can get a clean HTML structure. I want to build 3 custom and different HTML blocks and then iterate in each of them through the dedicated collection. entity_id as filter is generally a good idea, but unfortunately I don't think, getChildrenCategories() supports any filtering options like that... Apart from that, all entity_ids are different - actually the only common thing of this subcategories is their parent category - that's why I use getChildrenCategories() as the main function to get them. Feb 12, 2015 at 16:27

3 Answers 3

2

Call category collection and create different collection on limit

$_category = Mage::getModel('catalog/category')->load(129);

    $Children=$_category->getResource()->getChildren($_category, false));
            $collection = Mage::getResourceModel('catalog/product_collection');
            $collection->addAttributeToSelect('url_key')
                ->addAttributeToSelect('name')
                ->addAttributeToSelect('all_children')
                ->addAttributeToSelect('is_anchor')
                ->setOrder('position', Varien_Db_Select::SQL_ASC)
                ->joinUrlRewrite()
            ->addAttributeToFilter('is_active', 1)
                ->addIdFilter( implode(',', $Children))
                ->addAttributeToSelect('*');

Using setCurPage() and setPageSize() divide the collection by three part

Collection for 1-10;

$collection->setCurPage(1);
$collection->setPageSize(10);

Collection for 11-20;

$collection->setCurPage(2);
$collection->setPageSize(10);

Collection for 21-30;

$collection->setCurPage(3);
$collection->setPageSize(10)

;

2

Thank you very much for the feedback! Now I think, I found the solution. My final code is:

$parent_category_id = $this->getData('parent_category_id'); // 129
$number_of_columns = $this->getData('number_of_columns');   // 3

/** @var $_category Mage_Catalog_Model_Resource_Category_Collection */
$_categories = Mage::getModel('catalog/resource_category_collection')
    ->addAttributeToSort('name', 'ASC')
    ->addAttributeToSelect(array('name', 'url'))
    ->addIsActiveFilter()
    ->addFieldToFilter('parent_id', $parent_category_id);

$_page_size = (int) round($_categories->getSize() / $number_of_columns);

$_categories1 = clone $_categories;
$_categories1 = $_categories1->setPageSize(10)->setCurPage(1);
$_categories2 = clone $_categories;
$_categories2 = $_categories2->setPageSize(10)->setCurPage(2);
$_categories3 = clone $_categories;
$_categories3 = $_categories3->setPageSize(10)->setCurPage(3);

And then I can iterate through them separately:

<div class="column even" style="width: 25% !important;">
    <div class="itemMenu level1">
        <div class="title"><strong>Alphabetisch:</strong></div>
        <?php foreach ($_categories1 as $_child): ?>
        <a class="itemMenuName level1" href="<?php echo $_child->getUrl() ?>">
            <span><?php echo $_child->getName() ?></span>
        </a>
        <?php endforeach; ?>
    </div>
</div>

<div class="column odd" style="width: 25% !important; margin-top:2.75em;">
    <div class="itemMenu level1">
        <?php foreach ($_categories2 as $_child): ?>
        <a class="itemMenuName level1" href="<?php echo $_child->getUrl() ?>">
            <span><?php echo $_child->getName() ?></span>
        </a>
        <?php endforeach; ?>
    </div>
</div>

<div class="column even" style="width: 25% !important; margin-top:2.75em;">
    <div class="itemMenu level1">
        <?php foreach ($_categories3 as $_child): ?>
        <a class="itemMenuName level1" href="<?php echo $_child->getUrl() ?>">
            <span><?php echo $_child->getName() ?></span>
        </a>
        <?php endforeach; ?>
    </div>
</div>


<div class="clearBoth"></div>

I'm aware of the increase of memory consumption through clone, but hope, that there will be no other negative performance impacts. If you see any drawbacks for the solution, please, don't hesitate to post / ask.

1

@Amit has a good answer.

Another way is to use PHP's array_chunk. That way you only do one SQL query instead of three.

You can use it like so:

$_categoryChuncks = array_chunk(
    $_category->getChildrenCategories()->getItems(),
    ceil($_count / 3)
);

Note: I think when flat categories are enabled, $_category->getChildrenCategories() returns an array, not a collection model, so you might have to check for that.

2
  • Thank you! But will this solution only work, if flat categories are enabled? I think, it actually should be the case, but the top menu is one of the most important elements of the shop, so I would not like to implement something, which might break and which is directly dependent on a user-controlled option in the admin. Feb 13, 2015 at 7:13
  • You can just check if flat categories are enabled, and not call getItems()
    – Erfan
    Feb 13, 2015 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.