Найкращий спосіб завантажити власну модель у Magento 2


15

Оскільки мені було важко знайти правильний шлях, нижче ви можете знайти найкращу практику, яку я зробив своєю. Насолоджуйтесь, виправте свою англійську, якщо потрібно, і скажіть, що я помиляюся, якщо є. :)

Редагувати: ... і я дізнався, що я помилявся з якогось аспекту. Тож я оновив оригінальний пост після того, як відповіді Рафаеля допомогли мені зрозуміти більше. Дякую йому!

Поняття, що використовується нижче :

Вам буде простіше зрозуміти коди та пояснення нижче, якщо вам подобаються ці поняття:

  • Залежність від ін'єкції (як і всі $this->variableзмінні в коди вводяться)
  • Контракт на обслуговування та сховище
  • Заводська

Контекст :

Просто, щоб мати більше контексту, уявіть, що у нас правильно побудований модуль:

  • блок-клас CustomBlock, що містить метод getCustomModel($id),
  • цей метод повертає об’єкт CustomModel на основі ідентифікатора, переданого в парамі,
  • Тип CustomModel відповідають моделі в \Vendor\Module\Model\CustomModel
  • Ця модель поставляється зі своєю ресурсною моделлю (в \Vendor\Module\Model\ResourceModel\CustomModel)
  • і з його сховищем (в \Vendor\Module\Model\CustomModelRepository).

Питання :

  • Яка найкраща практика дозволити всім завантажувати об’єкт CustomModel?

Ви не можете використовувати load()об'єкт CustomModel, оскільки цей метод застарілий.

Належна практика говорить про те, що ви повинні використовувати договір на користування CustomModel. Контрактами на обслуговування є інтерфейси даних (наприклад, CustomModelInterface) та інтерфейси обслуговування (наприклад, CustomModelRepositoryInterface). Отже, мій блок виглядає так:

/ ** @var SlideRepositoryInterface * /
захищений $ slideRepository;

/ **
 * Конструктор CustomBlock
 * ...
 * @param CustomModelRepositoryInterface $ customModelRepository
 * ...
 * /
публічна функція __construct (
...
CustomModelRepositoryInterface $ customModelRepository
...
) {
    $ this-> customModelRepository = $ customModelRepository;
}

публічна функція getCustomModel ($ id) {
    повернути $ this-> customModelRepository-> get ($ id);
}

Перш за все, ми вводимо CustomModelRepositoryInterfaceоб'єкт в конструктор і використовуємо його в нашому getCustomModel()методі.

У класі Api\CustomModelRepositoryInterfaceне багато. Як правило (але ніщо не заважає вам робити по- іншому) ви оголосите основні методи: get, getList, save, delete, deleteById. Для цієї теми нижче наведено лише getдекларацію про метод:

/**
 * Get info by id
 *
 * @param int $id
 * @return Data\CustomModelInterface
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
public function get($id);

Гаразд, але якщо мій інтерфейс CustomModel викликається введенням залежності в мій конструктор блоків, де код? Щоб відповісти на це питання, ви повинні пояснити Magento, де знайти клас, що реалізує цей інтерфейс. У файл etc / di.xml модуля ви повинні додати:

<preference for="Vendor\Module\Api\CustomModelRepositoryInterface" type="Vendor\Module\Model\CustomModelRepository" />

Тож CustomModelRepositoryInterfaceклас - це сервісний інтерфейс. Втілюючи його, вам доведеться впроваджувати також інтерфейси даних (принаймні Vendor\Module\Api\Data\CustomModelInterfaceі Vendor\Module\Api\Data\CustomModelSearchResultsInterface). Ваша модель повинна буде реалізовувати Vendor\Module\Api\Data\CustomModelInterfaceта додавати <preference ... />лінії для кожного з ваших інтерфейсів. Нарешті, у будь-який час, коли ви використовуєте контракт на обслуговування, mySomethingInterfaceне замислюйтесь про це mySomething: нехай магенто використовує di.xmlмеханізм налаштувань.

Гаразд, що далі? Коли ми вводимо CustomModelRepositoryInterfaceв конструктор блоків, ми отримуємо CustomModelRepositoryоб'єкт. CustomModelRepositoryмає реалізувати метод, оголошений в CustomModelRepositoryInterface. Отже, ми маємо це у Vendor\Module\Model\CustomModelRepository:

Отримати публічну функцію ($ id) {
    $ customModel = $ this-> customModelFactory-> create ();
    $ customModel-> завантаження ($ id);
    if (! $ customModel-> getId ()) {
      кинути новий NoSuchEntityException (__ ('CustomModel з ідентифікатором "% 1" не існує. ", $ id));
    }
    повернути $ customModel;
}

Що ми робимо? Ми створюємо порожній CustomModelоб’єкт завдяки фабриці. Далі ми завантажуємо дані за CustomModelдопомогою методу моделі навантаження. Далі ми повертаємо a, NoSuchEntityExceptionякщо нам не вдалося завантажити CustomModelідентифікатор у парамах. Але якщо все в порядку, ми повертаємо модельний об’єкт і життя продовжується.

Але вау ...! У цьому прикладі що це?

$customModel->load($id);

Це не той самий застарілий loadметод, як на початку? Так. Я думаю, що це шкода, але вам доведеться використовувати його, оскільки в цьому методі load () є деякі події, що розсилаються, і розробник може їх слухати (див. Відповідь Рафаеля нижче).

Надалі нас врятує Entity Manager. Це вже інша історія, як нова концепція Magento 2, але якщо ви хочете зазирнути, Entity Manager вже реалізований у Моделі ресурсів Сторінки CMS (v2.1):

public function load(AbstractModel $object, $value, $field = null)
{
    $pageId = $this->getPageId($object, $value, $field);
    if ($pageId) {
        $this->entityManager->load($object, $pageId);
    }
    return $this;
}

Відповіді:


16

Найкраща практика: через договір на обслуговування

Найкраща практика - завжди використовувати договір послуги, коли це можливо. Список причин ви можете знайти тут: Magento 2: які переваги використання контрактів на обслуговування?

Детальніше про те, як реалізувати контракт на обслуговування, пропоную вам перевірити цю тему: Як реалізувати договір на обслуговування користувальницького модуля в Magento 2?

Якщо договору на обслуговування немає

Якщо контракту на обслуговування немає, слід скористатися getметодом сховища моделі . Використовуючи цей метод, ви користуєтесь системою кешування magento, наприклад для CategoryRepositoryкласу:

public function get($categoryId, $storeId = null)
{
    $cacheKey = null !== $storeId ? $storeId : 'all';
    if (!isset($this->instances[$categoryId][$cacheKey])) {
        /** @var Category $category */
        $category = $this->categoryFactory->create();
        if (null !== $storeId) {
            $category->setStoreId($storeId);
        }
        $category->load($categoryId);
        if (!$category->getId()) {
            throw NoSuchEntityException::singleField('id', $categoryId);
        }
        $this->instances[$categoryId][$cacheKey] = $category;
    }
    return $this->instances[$categoryId][$cacheKey];
}

Застарілий load()метод

Magento 2 повільно відходить від стандартної системи CRUD, скидаючи спадкову систему та реалізуючи її за допомогою композиції за допомогою нового 2.1 EntityManager, ви можете знайти тут деталі: Magento 2.1: використання менеджера сутностей

Також пропоную прочитати цю цікаву тему про застарілі методи CRUD: застарілі методи збереження та завантаження в абстрактній моделі

Чому б не використовувати завантаження моделі ресурсу

Основна причина полягає в тому, що якщо ви використовуєте loadметод моделі ресурсу , ви пропустите якусь важливу частину системи завантаження, реалізованої в loadметоді моделі , див Magento\Framework\Model\AbstractModel.

public function load($modelId, $field = null)
{
    $this->_beforeLoad($modelId, $field);
    $this->_getResource()->load($this, $modelId, $field);
    $this->_afterLoad();
    $this->setOrigData();
    $this->_hasDataChanges = false;
    $this->updateStoredData();
    return $this;
}

Виклик loadметоду моделі ресурсу безпосередньо матиме такий вплив:

  • _beforeLoad не називається: таким чином завантаження моделі до подій не розсилається
  • _afterLoad не називається: таким чином завантаження моделі після подій не розсилається
  • збережені дані не обновляються , які можуть привести до різних проблем (наприклад , якщо ви телефонуєте prepareDataForUpdateз Magento\Framework\Model\ResourceModel\Db\AbstractDb)

Дякую Рафаелю, що все, що ти кажеш, має сенс і доповнити мої знання. Але я не розумію, чому Кенді коментує (під своєю відповіддю), що Маріус може використовувати метод load () у своїй спеціальній моделі ресурсу модуля? Це в [ magento.stackexchange.com/questions/114929/… методи збереження та завантаження в абстрактній моделі). Будь-які ідеї?
Ніколя ПЕРНОТ

@NicolasPERNOT в основному KAndy пояснює, що мета полягає у тому, щоб мати SL (Service Layer) для кожного модуля і що це те, що потрібно використовувати щоразу, коли потрібно завантажити об'єкт. Я пропоную вам прокоментувати, згадуючи його, можливо, він зможе просвітити вас, оскільки він є працівником Magento Inc Я думаю
Рафаель в Digital Pianism

Ну, нарешті, я оновив свій початковий пост. Дякую Рафаелю за допомогу.
Ніколя ПЕРНОТ

Я бачу, що принаймні в Magento 2.2 це важливе значення входить у навантаження ResourceModel, тому не правильно використовувати методи ResourceModel безпосередньо, правда?
Яніс Ельмеріс

В даний час ми можемо безпечно завантажувати Модель методом Resource Model load(). Модель ресурсів називає методи моделі з власного load()методу: $model->beforeLoad() { $this->_beforeLoad() }і$model->afterLoad() { $this->_afterLoad() }
sergei.sss

-2

Я думаю, що наступне твердження зараз не дійсне.

Why not using the resource model load

ми можемо знайти Magento\Framework\EntityManager\Observerпапку всіх подій.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.