Что и почему является правильным способом загрузки модели

9

У меня довольно большой опыт работы с Magento, но я понял, что не понимаю, какой способ загрузки модели является правильным и почему. Я прочитал все, что мог, об этой теме, но люди, объясняющие подобные вещи, никогда не заходили достаточно глубоко, чтобы объяснить, зачем использовать этот конкретный метод вместо другого. Давайте предположим, что нет репозитория для модели, которую я хочу загрузить.

До сих пор я всегда использовал модель в конструкторе, а затем просто загружал ее.

public function __construct(
    \Vendor\Module\Model\Something $somethingModel
) {
    $this->somethingModel = $somethingModel;
}

public function getTestById($id) {
    return $this->somethingModel->load($id);
}

И это всегда работало как задумано, я также уверен, что он или, по крайней мере, широко использовался в ядре.

Но потом я увидел, как один из моих коллег использовал

modelFactory->create()->load($id)

Насколько я понимаю, фабрики используются для создания новой сущности, например, если я хочу создать новый продукт, я могу создать фабрику, заполнить ее данными, а затем сохранить. Но с другой стороны, я начал исследовать эту тему и увидел пример от Фабиана Шменглера ( когда мы должны использовать репозиторий и фабрику в Magento 2? ), Который загружал модель таким образом, а также отговаривал других от простой загрузки моделей, он не объяснить, хотя, кроме того, что он «не является частью договора на обслуживание». Насколько я понимаю, репозитории являются частью сервисных контрактов, поэтому я не вижу здесь никакой связи, когда речь идет о загрузке моделей, которые недоступны через репозиторий.

Чтобы добавить еще больше путаницы, я также нашел способ загрузки модели, получая resourceModel из созданной modelFactory, он был представлен Vinai Kopp ( Как реализовать контракт на обслуживание для пользовательского модуля в Magento 2? ), И теперь я полностью потерян, поскольку я всегда читал, что я не должен использовать модели ресурсов напрямую.

Так что да, кто-то может сказать мне, какой путь правильный и почему я должен использовать его вместо всех других методов?

CZS
источник
Я буквально связываю эту ветку как с запутанным примером, вы вообще читали мой пост?
czs
1
Хороший вопрос, постараюсь найти время, чтобы подробно ответить позже. Я уже могу сказать вам очень много: это другой случай, если вы загружаете свои собственные модели (например, Vinai) или модели основных или сторонних модулей (мой ответ). Кроме того, внедрение модели через конструктор каждый раз будет давать вам один и тот же экземпляр, что может привести к нежелательным побочным эффектам.
Фабиан Шменглер

Ответы:

12

Итак, первый шаг, который вы должны проверить для рассматриваемой модели: есть ли контракт на обслуживание репозитория? Если это так, используйте это, потому что Сервисные контракты связаны с семантическим версионированием и будут продолжать вести себя так, как должны, вплоть до выхода Magento 3.x. Само собой разумеется, что когда вы создаете свои собственные модули с моделями, которые требуют постоянства, вы также должны написать репозиторий для этого.

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->productRepository = $productRepository;
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $this->productRepository->save($product);
}

Если репозиторий отсутствует, используйте модель ресурсов . Обратите внимание, что модели ресурсов не содержат состояния: они используют постоянство для своих «обычных» моделей. Поэтому вы не обязаны включать их, используя фабрику:

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product $productResource,
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productResource = $productResource;
    $this->productFactory = $productFactory;
    ...
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $product = $this->productFactory->create();
    $this->productResource->save($product);
}

«Так какое же преимущество приносит контракт на обслуживание / репозиторий по сравнению с моделью ресурсов?» Вы можете спросить. Что ж, теоретически Модель ресурсов должна отвечать только за постоянство Модели данных , тогда как Репозиторий также учитывает дополнительные задачи, связанные с сохранением объекта. Подумайте об обновлении индексов, создании отношений с другими объектами и т. Д. Это теория, хотя в реальной жизни эти линии часто размываются. Но для себя хорошо иметь это в виду.

Вы не должны использовать модели прямой save(), load()и т.д. -методы. Они устарели, потому что это семантически неверно. Подумайте об этом в твердом виде:

  • (Данные) Модели должны нести ответственность только за содержание данных.
  • Ресурсные модели должны отвечать за сохранность таких данных.
  • Хранилища должны отвечать за связь внутри и снаружи модуля для постоянных действий.

И именно этот последний момент имеет значение: когда вы общаетесь с другими модулями, в идеальном мире никогда не нужно полагаться на внутреннюю постоянную логику этих модулей (или любой из ее открытых методов в этом отношении, но это другое обсуждение), но используйте только ту функциональность, которая предусмотрена в контрактах на обслуживание модулей .

В заключении

Ответить на ваш вопрос: в порядке предпочтения. Правильный способ загрузки модели:

  • Если есть Репозиторий, загрузите его, используя Репозиторий.
  • Только если нет репозитория, используйте модель ресурсов (в сочетании с фабрикой).
Гиль Беркерс
источник
1
Итак, если я правильно следую - когда я хочу изменить / добавить новые данные и сохранить их в базе данных, тогда я должен использовать Resource Model и когда я хочу загрузить данные в память, тогда я должен использовать Factory? Так есть ли ситуации, в которых я должен использовать обычную модель напрямую (как при использовании класса Model в конструкторе)?
17
@czs Вы правы, я добавил более описательный пример для загрузки модели для того же.
Милинд Сингх
2
  • Modelsявляется Интерфейс передачи данных используется только хранить данные в объектах, то есть до setи getданных для строки.
  • ResourceModelsявляются механизмом, который отвечает за сохранность таких данных, т.е. выполняет запрос SQL к действительности saveили loadданные в Modelобъект.

Правильный способ loadи saveдолжен быть путем создания хранилища или загрузки из ресурса следующим образом:

namespace MyVendor\MyModule\Model;

class QueueRepository impliments \MyVendor\MyModule\Api\QueueRepositoryInterface
{

    /** @var \MyVendor\MyModule\Model\ResourceModel\Queue  */
    public $resource;

    /** @var \MyVendor\MyModule\Model\QueueFactory  */
    public $modelFactory;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Queue $resource,
        \MyVendor\MyModule\Model\QueueFactory $modelFactory
    ) {
        $this->resource = $resource;
        $this->modelFactory = $modelFactory;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @return $queue
     * @throws \Exception
     */
    public function save(\MyVendor\Integrator\Api\Data\QueueInterface $queue)
    {
        $this->resource->save($queue);
        return $queue;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @param int $id
     * @return $queue
     * @throws \Exception
     */
    public function load(\MyVendor\MyModule\Api\Data\QueueInterface $queue, $id)
    {
        $this->resource->load($queue, $id);
        return $queue;
    }

    public function getById($id)
    {
        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
    }
}

Здесь \MyVendor\MyModule\Api\Data\QueueInterfaceподразумевается Queueмодель.

Так, за кулисами, мы на самом деле создаем Modelобъект , то loadingего на ResourceModelобъекте. Это правильный способ загрузки или сохранения.

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
Милинд Сингх
источник