Magento 2でカスタムモデルを読み込む最良の方法


15

正しい方法を見つけることは私にとって困難だったので、以下であなたが私が作ったベストプラクティスを見つけることができました。楽しんで、必要に応じて英語を修正し、私が間違っていると言ってください。:)

編集: ...そして、私はいくつかの面で間違っていたことがわかりました。だから、ラファエルの答えが私をもっと理解するのを助けてから、元の投稿を更新しました。彼に感謝!

以下で使用される概念

これらの概念に慣れていれば、以下のコードと説明を理解しやすくなります。

  • インジェクションの依存関係($this->variableコード内のすべての変数がインジェクトされるため)
  • サービス契約とリポジトリ
  • 工場

コンテキスト

より多くのコンテキストを持つために、モジュールが正しく構築されていると想像してください:

  • 方法を含むブロッククラスCustomBlock getCustomModel($id)
  • このメソッドは、paramで渡された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){
    return $ this-> customModelRepository-> get($ id);
}

まず、CustomModelRepositoryInterfaceオブジェクトをコンストラクターに注入し、getCustomModel()メソッドで使用します。

クラスApi\CustomModelRepositoryInterfaceでは多くはありません。一般的に、基本的なメソッドを宣言します(が、何も違っ行うためにあなたを防ぎます): 、getgetListsave、。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ください。magentoにdi.xml設定メカニズムを使用させます。

さて、次は何ですか?CustomModelRepositoryInterfaceブロックコンストラクターに注入すると、CustomModelRepositoryオブジェクトが取得されます。CustomModelRepositoryメソッドdeclareを実装する必要がありCustomModelRepositoryInterfaceます。だから私たちはこれを持っていますVendor\Module\Model\CustomModelRepository

パブリック関数get($ id){
    $ customModel = $ this-> customModelFactory-> create();
    $ customModel-> load($ id);
    if(!$ customModel-> getId()){
      throw New NoSuchEntityException(__( 'id "%1"のCustomModelは存在しません。'、$ id));
    }
    return $ customModel;
}

何をしているの?CustomModel工場のおかげで空のオブジェクトを作成します。次にCustomModel、ロードモデルメソッドを使用してデータをロードします。次に、paramsでid NoSuchEntityExceptionをロードできなかった場合にを返しCustomModelます。しかし、すべてが大丈夫であれば、モデルオブジェクトを返し、人生は続きます。

しかし、すごい...!この例では何ですか?

$customModel->load($id);

load最初と同じ非推奨のメソッドではありませんか?はい、そうです。残念だと思いますが、このload()メソッドにはいくつかのイベントがディスパッチされており、開発者がそれらをリッスンできるため、使用する必要があります(以下のRaphaelの回答を参照)。

将来的には、Entity Managerによって保存されます。新しいMagento 2コンセプトとしては別の話ですが、注目したい場合は、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;
}

回答:


15

ベストプラクティス:サービス契約経由

ベストプラクティスは、可能な場合は常にサービスコントラクトを使用することです。理由のリストはここで見つけることができます:Magento 2:サービス契約を使用する利点は何ですか?

サービスコントラクトを実装する方法の詳細については、次のトピックを確認することをお勧めします。Magento2でカスタムモジュールのサービスコントラクトを実装する方法

利用可能なサービス契約がない場合

利用可能なサービス契約がない場合は、モデルリポジトリgetメソッドを使用する必要があります。この方法を使用すると、たとえばCategoryRepositoryクラスのmagentoキャッシングシステムのメリットが得られます。

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は、継承システムを削除し、新しい2.1 EntityManagerを使用して構成を介して実装することにより、標準のCRUDシステムから徐々に離れています。詳細は、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()メソッドを使用できるとKAndyが(彼の答えに基づいて)コメントする理由がわかりません。[ magento.stackexchange.com/questions/114929/…抽象モデルのメソッドの保存と読み込み]にあります。何か案は ?
ニコラスペルノ

@NicolasPERNOT基本的にKAndyは、目標はすべてのモジュールにSL(サービスレイヤー)を持たせることであり、これはエンティティをロードする必要があるたびに使用する必要があることだと説明しています。私は彼が私が思うのMagento社の従業員として、彼はあなたを啓発することができるでしょう、多分彼を言及することにより、あなたのコメントを示唆
ラファエルデジタルでPianism

さて、私は最終的に元の投稿を更新しました。ラファエル、助けてくれてありがとう。
ニコラスペルノ16年

少なくともMagento 2.2では、この重要な要素がResourceModelのロードに含まれていることがわかります。したがって、ResourceModelメソッドを直接使用することはできません。
ジャニスエルメリス

現在、Resource Model load()メソッドを使用してModelを安全にロードできます。リソース・モデルは、独自のモデルのメソッドを呼び出すload()方法:$model->beforeLoad() { $this->_beforeLoad() }$model->afterLoad() { $this->_afterLoad() }
sergei.sss

-1

次の文は現在有効ではないと思います。

Why not using the resource model load

Magento\Framework\EntityManager\Observerフォルダーのすべてのイベントを見つけることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.