モデルをロードする適切な方法は何で、なぜですか


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でリポジトリとファクトリを使用する必要がある場合)の例を見ました tそれが「サービス契約の一部ではない」と言うことのほかに理由を説明してください。リポジトリがサービスコントラクトの一部であることを理解している限り、リポジトリからは利用できないモデルの読み込みに関しては、ここでは何の関係もありません。

さらに混乱を加えるために、作成されたmodelFactoryからresourceModelを取得してモデルをロードする方法も見つけました。VinaiKoppによって提示されました(Magento 2でカスタムモジュールのサービスコントラクトを実装する方法は?リソースモデルを直接使用するべきではないことをいつも読んだので、完全に失われました。

だから、ええ、誰かが正しい方法を教えてもらえますか?なぜ私が他のすべての方法の代わりにそれを使うべきなのでしょうか?


私は文字通りこのスレッドを混乱する例が含まれているとリンクしています。私の投稿を読んでもいませんか
CZ

1
良い質問です。後で詳しく答える時間を見つけようと思います。私はすでに多くのことを言うことができます:あなたがあなた自身のモデル(ビナイによる例)またはコアまたはサードパーティのモジュール(私の答え)のモデルをロードする場合、それは別のケースです。また、コンストラクターを介してモデルを注入すると、毎回同じインスタンスが得られ、望ましくない副作用が発生する可能性があります。
Fabian Schmengler 2017年

回答:


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()-methodsなど。セマンティックが正しくないため、これらは非推奨です。しっかりと考えてください:

  • (データ)モデルは、データを含むことのみを担当します。
  • リソースモデルは、このようなデータの永続性を担当する必要があります。
  • リポジトリには、内部の通信のために責任を負わなければならないと外の永続性行動のためのモジュール。

そして、それが違いをもたらす最後のポイントです。他のモジュールと通信するとき、理想的な世界では、そのモジュールの内部永続ロジック(またはその問題のパブリックメソッドのいずれかに依存する必要はないはずですが、それは別の議論です)、ただし、モジュールのサービスコントラクトによって提供される機能のみを使用します。

結論として

あなたの質問に答えるために:好みの順に。モデルをロードする正しい方法は次のとおりです。

  • リポジトリがある場合は、リポジトリを使用してロードします。
  • リポジトリーがない場合にのみ、リソース・モデルを(ファクトリーと組み合わせて)使用してください。

1
わかりましたので、正しく従えば、新しいデータを変更/追加してデータベースに保存したい場合は、リソースモデルを使用し、データをメモリにロードしたい場合は、ファクトリを使用しますか?では、コンストラクタでModelクラスを使用する場合など、通常のModelを直接使用する必要がある状況はありますか?
czs

@czs正解です。同じモデル読み込みのよりわかりやすい例を追加しました。
Milind Singh

2
  • Modelsデータインタフェースのみに、すなわち、オブジェクト内のデータを保持するために使用されるsetget行のデータ。
  • ResourceModelsそのようなデータの永続化を担当するメカニズムです。つまり、SQLクエリを実行して、実際に、saveまたはloadデータをModelオブジェクトに入れます。

正しい方法loadsave作成することでなければならないリポジトリまたはリソースからのロードを次のように

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