Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Products, categories, customers and orders

Products, categories, customers and orders are stored in dozens of related core tables. You do not read them with SQL queries: every kind of data has a repository — an interface with the same get, getList and save methods as the review repository. These interfaces do not change when Magento is updated.

Core repositories

DataInterface
ProductsMagento\Catalog\Api\ProductRepositoryInterface
CategoriesMagento\Catalog\Api\CategoryRepositoryInterface
CustomersMagento\Customer\Api\CustomerRepositoryInterface
OrdersMagento\Sales\Api\OrderRepositoryInterface

A repository is requested in the constructor of your class. Modules whose interfaces you use are listed in the sequence section of module.xml.

A product by SKU

Create a class in the module that gathers information about the shop:

// app/code/Acme/Hello/Model/ShopInfo.php
namespace Acme\Hello\Model;
 
use Magento\Catalog\Api\ProductRepositoryInterface;
 
class ShopInfo
{
    public function __construct(private ProductRepositoryInterface $productRepository) {}
 
    public function productName(string $sku): string
    {
        $product = $this->productRepository->get($sku);
 
        return (string) $product->getName();
    }
}

The get() method finds a product by its SKU, and getById() by its ID. If the product does not exist, both throw a NoSuchEntityException.

Using it

Let's call the class from the Status action of the earlier lessons:

// app/code/Acme/Hello/Controller/Index/Status.php
public function execute(): ResultInterface
{
    return $this->resultFactory->create(ResultFactory::TYPE_JSON)
        ->setData(['name' => $this->shopInfo->productName('24-MB01')]);
}

Add ShopInfo to the action constructor, clear the generated folder and open /hello/index/status. With the sample data installed the response is {"name":"Joust Duffle Bag"}.

A list of products

Search conditions are assembled by SearchCriteriaBuilder — the same way as for reviews:

// app/code/Acme/Hello/Model/ShopInfo.php
public function cheapProducts(): array
{
    $criteria = $this->criteriaBuilder
        ->addFilter('price', 50, 'lt')
        ->setPageSize(10)
        ->create();
 
    return $this->productRepository->getList($criteria)->getItems();
}

The method returns up to ten products cheaper than 50. Each one has getSku(), getName(), getPrice(). The Magento\Framework\Api\SearchCriteriaBuilder object is added to the constructor.

Changing a product

// app/code/Acme/Hello/Model/ShopInfo.php
public function setPrice(string $sku, float $price): void
{
    $product = $this->productRepository->get($sku);
    $product->setPrice($price);
 
    $this->productRepository->save($product);
}

The product is saved with all core checks, and indexes and the cache are refreshed automatically.

Category, customer, order

// app/code/Acme/Hello/Model/ShopInfo.php
public function summary(int $categoryId, string $email, int $orderId): array
{
    $category = $this->categoryRepository->get($categoryId);
    $customer = $this->customerRepository->get($email);
    $order = $this->orderRepository->get($orderId);
 
    return [
        'category' => $category->getName(),
        'customer' => $customer->getFirstname() . ' ' . $customer->getLastname(),
        'order' => $order->getIncrementId(),
        'total' => $order->getGrandTotal(),
    ];
}

A category and an order are found by ID, a customer by email address or through getById(). The getIncrementId() method returns the order number the customer sees, and getGrandTotal() the final amount.

A customer's orders

// app/code/Acme/Hello/Model/ShopInfo.php
public function ordersOf(string $email): array
{
    $criteria = $this->criteriaBuilder
        ->addFilter('customer_email', $email)
        ->create();
 
    return $this->orderRepository->getList($criteria)->getItems();
}

The method returns all orders with the given email address.

Common mistake

A repository is called in a loop: for a hundred reviews $this->productRepository->getById() runs a hundred times. Every call loads a whole product with all its attributes, and the page takes several seconds to open. Collect the IDs and fetch the products with a single getList() call using the in condition on the entity_id field.

Thanks for reading!

Donate to the site — we work hard for you.