How to use the repository pattern in Magento 2

The best way to load entities in Magento

Let’s take a look at using the new repository pattern introduced in Magento 2.

Repositories are the preferred way of loading entities. They provide a layer of abstraction from the underlying mechanics of how the data is stored and loaded. It could come from the cache, from a file on disk, or most commonly from the database — however we don’t need to know this, we just care about getting the data.

Repositories are also part of the Magento API. This means that (hopefully🤞) Magento will maintain backwards compatibility on these classes & methods, so our code will continue to work in future versions of Magento.

As an example, we’ll build a new Block which loads the 5 heaviest products on our website.

Setting up the class

A few things to get started, we need to set up the namespace, add some use statements to make our code less verbose, and make sure our class is extending the core Template class. I’ve also added a method stub which we’ll use to load our product list.

<?phpnamespace DannyNimmo\HeavyProducts\Block;use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SortOrder;
use Magento\Framework\Api\SortOrderBuilder;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
class ListProduct extends Template
{
/**
* @return ProductInterface[]
*/
public function getProducts()
{}
}

Injecting the dependencies

Magento 2 provides a great dependency injection system for us to use. Dependency injection is just a fancy way of saying, “my class needs access to these other classes, can you please give them to me?”.

Note: As a rule, never use the ObjectManager class directly for instantiating classes! Always use dependency injection via the class __construct method.

We need to inject the Product repository itself, as well as a couple of builder classes which we’ll cover later. Repositories are generally located in the Api directory of a module. We can find the Product repository interface at vendor/magento/module-catalog/Api/ProductRepositoryInterface.php. Here we can see the methods available to us in the interface, including the one we want to use, getList.

By passing the class into our __construct method, Magento will instantiate it for us, and pass it to our class to use. Then all we need to do is assign these objects to private properties on our own class.

Note: Because our class is extending another class (Template), we need to inject the parent class dependencies too, and call the parent constructor from our own constructor.

private $productRepository;
private $searchCriteriaBuilder;
private $sortOrderBuilder;
public function __construct(
ProductRepositoryInterface $productRepository,
SearchCriteriaBuilder $searchCriteriaBuilder,
SortOrderBuilder $sortOrderBuilder,
Context $context,
array $data = []
) {
parent::__construct($context, $data);
$this->productRepository = $productRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->sortOrderBuilder = $sortOrderBuilder;
}

Creating the SearchCriteria

Looking at the getList method, we can see that it requires one parameter to be passed in, a SearchCriteriaInterface object. This is where we need to use the builder class we injected to help create the object for us.

A builder is similar to a factory, in that it will help instantiate a class for us. The slight difference being that we want to pass a bunch of variables & parameters first, so that when we get the new object, it’s already set up for us to use.

Filtering

The addFilter method on the builder is used for filtering out products we want. In our case, we want to filter based on the weight field, using a greater-than-or-equal-to comparison for anything 10kg or more (or lb if you hate easy-to-use measurement systems!).

In the getProducts method, let’s add the filter:

$this->searchCriteriaBuilder->addFilter('weight', 10.0, 'gteq');

Sorting

To use the addSortOrder method on the SearchCriteriaBuilder, we need to pass in a SortOrder object. We can use another builder class to create this.

Let’s sort our products from heaviest to lightest:

$sortOrder = $this->sortOrderBuilder
->setField('weight')
->setDirection(SortOrder::SORT_DESC)
->create();

$this->searchCriteriaBuilder->addSortOrder($sortOrder);

Limiting

If we want to limit the amount of products we load, we can use the setPageSize method. This is also useful for paginating entities.

We only want the 5 heaviest products:

$this->searchCriteriaBuilder
->setPageSize(5)
->setCurrentPage(1);

Create the object

All we need to do now, is create the object:

$searchCriteria = $this->searchCriteriaBuilder->create();

Now we’ve got a fully instantiated SearchCriteria object, with all of our requirements!

Using the repository

Finally, we can make use of that repository object. The getList method returns a ProductSearchResultsInterface object, which is useful for retrieving metadata for our results, such as the original search criteria, or the total count of entities.

We’ll use the getItems method, which will return an array of products.

$products = $this->productRepository
->getList($searchCriteria)
->getItems();

Putting it all together

Below is the final class in all it’s glory. Hopefully this shows how easy it is to start using repositories in Magento! Please hit me up below if there are any inaccuracies in the article, or if there is anything I need to clarify further.

Now go have fun and load some data!

<?php

namespace DannyNimmo\HeavyProducts\Block;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SortOrder;
use Magento\Framework\Api\SortOrderBuilder;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;

class ListProduct extends Template
{

/**
* Product repository
* @var ProductRepositoryInterface
*/
private $productRepository;

/**
* SearchCriteria builder
* @var SearchCriteriaBuilder
*/
private $searchCriteriaBuilder;

/**
* SortOrder builder
* @var SortOrderBuilder
*/
private $sortOrderBuilder;

/**
* ListProduct constructor
*
* @param ProductRepositoryInterface $productRepository
* @param SearchCriteriaBuilder $searchCriteriaBuilder
* @param SortOrderBuilder $sortOrderBuilder
* @param Context $context
* @param array $data
*/
public function __construct(
ProductRepositoryInterface $productRepository,
SearchCriteriaBuilder $searchCriteriaBuilder,
SortOrderBuilder $sortOrderBuilder,
Context $context,
array $data = []
) {
parent::__construct($context, $data);
$this->productRepository = $productRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->sortOrderBuilder = $sortOrderBuilder;
}

/**
* Get list of the 5 heaviest products
*
* @return ProductInterface[]
*/
public function getProducts()
{
// Filter products weighing 10kg or more
$this->searchCriteriaBuilder
->addFilter('weight', 10.0, 'gteq');

// Sort products heaviest to lightest
$sortOrder = $this->sortOrderBuilder
->setField('weight')
->setDirection(SortOrder::SORT_DESC)
->create();
$this->searchCriteriaBuilder->addSortOrder($sortOrder);

// Get the first 5 products
$this->searchCriteriaBuilder
->setPageSize(5)
->setCurrentPage(1);

// Create the SearchCriteria
$searchCriteria = $this->searchCriteriaBuilder->create();

// Load the products
$products = $this->productRepository
->getList($searchCriteria)
->getItems();

return $products;
}

}

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store