loading...

Don't initialize collection multiple times with ->create(), instead cache the collection - Magento 2

pabodah profile image Paboda Hettiarachchi Updated on ・2 min read

I had to take category collection in two separate phtml files.
So the following method was called two times.

public function getSecondLevelCategories()
{
    $data = [];

    try {
        $collection = $this->categoryCollectionFactory->create();
        $collection->addAttributeToSelect('*');
        $collection->addIsActiveFilter();
        $collection->addAttributeToFilter('level', self::CATEGORY_LEVEL_2);
        $collection->addAttributeToFilter('include_in_menu', 1);
        $collection->addOrderField('position');

        foreach ($collection as $category) {
            $data[] = [
                'url' => $category->getUrl(),
                'label' => $category->getName()
            ];
        }
    } catch (\Exception $e) {
        $this->_logger->error($e->getMessage());
    }
    return $data;
}
Enter fullscreen mode Exit fullscreen mode

By using

$collection = $this->categoryCollectionFactory->create();

in the above method, I initialize the collection two times when the method is called in two different phtmls, which reduces the performance of the site.

Instead of the above, it is good to cache the data with get and set into a separate singleton class.

To do that,
1 Create a Model with get and set

<?php
namespace Vendor\Module\Model;

class CategoryListModel
{
    /**
     * @var array
     */
    protected array $items = [];

    /**
     * Set items
     *
     * @param array $items
     */
    public function setItems(array $items): void
    {
        $this->items = $items;
    }

    /**
     * Get items
     *
     * @return array
     */
    public function getItems(): array
    {
        return $this->items;
    }
}
Enter fullscreen mode Exit fullscreen mode

2 In the block class call call the above Modal with get/set methods.
In this, if you find items already loaded, it will be used for the second time.

<?php
namespace Vendor\Module\Block;
...
use Vendor\Module\Model\CategoryListModel;
...

/**
 * @var CategoryListModel
 */
private CategoryListModel $categoryListModel;

public function __construct(
...
    CategoryListModel $categoryListModel,
...
) {
...
    $this->categoryListModel = $categoryListModel;
...
}


public function getCategories()
{
    $model = $this->categoryListModel;

    if (empty($model->getItems())) {
        $model->setItems($this->getSecondLevelCategories());
    }

    return $model->getItems();
}

public function getSecondLevelCategories()
{
    $data = [];

    try {
        $collection = $this->categoryCollectionFactory->create();
        $collection->addAttributeToSelect('*');
        $collection->addIsActiveFilter();
        $collection->addAttributeToFilter('level', self::CATEGORY_LEVEL_2);
        $collection->addAttributeToFilter('include_in_menu', 1);
        $collection->addOrderField('position');

        foreach ($collection as $category) {
            $data[] = [
                'url' => $category->getUrl(),
                'label' => $category->getName()
            ];
        }
    } catch (\Exception $e) {
        $this->_logger->error($e->getMessage());
    }
    return $data;
}
Enter fullscreen mode Exit fullscreen mode

Discussion

pic
Editor guide