Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Модели, ресурсные модели и коллекции

Чтобы работать с таблицей из кода, в Magento пишут три класса. Модель представляет одну запись, ресурсная модель выполняет запросы к базе, а коллекция выбирает сразу много записей. Команды для их создания нет — файлы создают вручную.

app/code/Acme/Hello/
└── Model/
    ├── Review.php                      модель
    └── ResourceModel/
        ├── Review.php                  ресурсная модель
        └── Review/
            └── Collection.php          коллекция

Ресурсная модель

// app/code/Acme/Hello/Model/ResourceModel/Review.php
namespace Acme\Hello\Model\ResourceModel;
 
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
 
class Review extends AbstractDb
{
    protected function _construct(): void
    {
        $this->_init('acme_hello_review', 'review_id');
    }
}

Метод _init() называет таблицу и столбец первичного ключа. Обратите внимание: _construct() с одним подчёркиванием — это метод Magento, а не конструктор PHP.

Модель

// app/code/Acme/Hello/Model/Review.php
namespace Acme\Hello\Model;
 
use Magento\Framework\Model\AbstractModel;
 
class Review extends AbstractModel
{
    protected function _construct(): void
    {
        $this->_init(ResourceModel\Review::class);
    }
}

Модель указывает свою ресурсную модель. Значения столбцов она хранит во внутреннем массиве: их читают через getData('author') или через «волшебный» метод getAuthor(), а записывают через setData('author', 'Анна') или setAuthor('Анна').

Коллекция

// app/code/Acme/Hello/Model/ResourceModel/Review/Collection.php
namespace Acme\Hello\Model\ResourceModel\Review;
 
use Acme\Hello\Model\ResourceModel\Review as ReviewResource;
use Acme\Hello\Model\Review;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
 
class Collection extends AbstractCollection
{
    protected function _construct(): void
    {
        $this->_init(Review::class, ReviewResource::class);
    }
}

Коллекция знает, какие объекты создавать для строк таблицы и через какую ресурсную модель их читать.

Создание записи

Новую модель получают из фабрики, а сохраняет её ресурсная модель:

// app/code/Acme/Hello/Model/ReviewService.php
namespace Acme\Hello\Model;
 
use Acme\Hello\Model\ResourceModel\Review as ReviewResource;
 
class ReviewService
{
    public function __construct(
        private ReviewFactory $reviewFactory,
        private ReviewResource $reviewResource,
    ) {}
 
    public function add(int $productId, string $author, int $rating): int
    {
        $review = $this->reviewFactory->create();
        $review->setData(['product_id' => $productId, 'author' => $author, 'rating' => $rating]);
 
        $this->reviewResource->save($review);
 
        return (int) $review->getId();
    }
}

Метод добавляет строку в таблицу и возвращает её номер. Загрузить запись по номеру можно вызовом $this->reviewResource->load($review, 5), удалить — $this->reviewResource->delete($review).

Чтение списка

Выведем последние отзывы на странице /hello. Модель представления получает фабрику коллекции:

// app/code/Acme/Hello/ViewModel/LatestReviews.php
namespace Acme\Hello\ViewModel;
 
use Acme\Hello\Model\ResourceModel\Review\CollectionFactory;
use Magento\Framework\View\Element\Block\ArgumentInterface;
 
class LatestReviews implements ArgumentInterface
{
    public function __construct(private CollectionFactory $collectionFactory) {}
 
    public function getReviews(): array
    {
        $collection = $this->collectionFactory->create();
        $collection->addFieldToFilter('rating', ['gteq' => 4])
            ->setOrder('created_at', 'DESC')
            ->setPageSize(5);
 
        return $collection->getItems();
    }
}

Метод возвращает до пяти последних отзывов с оценкой не ниже четырёх. Запрос к базе выполняется только при вызове getItems().

<!-- app/code/Acme/Hello/view/frontend/templates/reviews.phtml -->
<?php $viewModel = $block->getData('view_model'); ?>
<ul>
    <?php foreach ($viewModel->getReviews() as $review): ?>
        <li><?= $escaper->escapeHtml($review->getAuthor()) ?>: <?= (int) $review->getRating() ?></li>
    <?php endforeach; ?>
</ul>

Добавьте в макет hello_index_index.xml блок с этим шаблоном и моделью представления, выполните bin/magento cache:clean — на странице появится список авторов с оценками. Пока таблица пуста, список пуст; первые записи добавит урок о заплатках.

Условия фильтра

УсловиеЗначение
eq, neqРавно, не равно
gt, gteq, lt, lteqБольше, не меньше, меньше, не больше
likeСовпадение по шаблону
in, ninВходит в список, не входит
null, notnullПусто, не пусто

Частая ошибка

Модель создают словом new Review() или просят в конструкторе сам класс Review. В первом случае объект не получит своих зависимостей, во втором все классы будут делить один и тот же экземпляр с чужими данными. Новую запись всегда берите из ReviewFactory, а список — из CollectionFactory.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.