Was und warum ist der richtige Weg, um ein Modell zu laden?

9

Ich habe ziemlich viel Erfahrung mit Magento, aber mir wurde klar, dass ich nicht verstehe, welche Art des Ladens eines Modells die richtige ist und warum. Ich habe alles über das Thema gelesen, was ich konnte, aber Leute, die solche Dinge erklären, gehen nie tief genug, um zu erklären, warum sie diese spezielle Methode anstelle einer anderen verwenden. Nehmen wir an, es gibt kein Repository für das Modell, das ich laden möchte.

Bis jetzt habe ich immer model im Konstruktor verwendet und es dann einfach geladen.

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

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

Und es hat immer wie beabsichtigt funktioniert, ich bin mir auch ziemlich sicher, dass es im Kern allgemein verwendet wird oder zumindest verwendet wurde.

Aber dann sah ich einen meiner Kollegen mit

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

Soweit ich weiß, werden Fabriken zum Erstellen einer neuen Entität verwendet. Wenn ich beispielsweise ein neues Produkt erstellen möchte, kann ich die Fabrik erstellen, mit Daten füllen und dann speichern. Andererseits habe ich angefangen, das Thema zu untersuchen, und ich habe ein Beispiel von Fabian Schmengler ( Wann sollten wir ein Repository und eine Factory in Magento 2 verwenden? ) Gesehen, der das Modell auf diese Weise geladen hat und auch andere davon abgehalten hat, die Modelle einfach zu laden. Ich erkläre nicht, warum, abgesehen davon, dass es nicht Teil des Servicevertrags ist. Soweit ich weiß, sind Repositorys Teil von Serviceverträgen, daher sehe ich hier keinen Zusammenhang, wenn es darum geht, Modelle zu laden, die nicht über ein Repository verfügbar sind.

Um noch mehr Verwirrung zu stiften, habe ich auch eine Möglichkeit gefunden, das Modell zu laden, indem ich das resourceModel von der erstellten modelFactory abgerufen habe. Es wurde von Vinai Kopp vorgestellt ( Wie implementiere ich einen Servicevertrag für ein benutzerdefiniertes Modul in Magento 2? ) Und jetzt bin ich es völlig verloren, da ich immer gelesen habe, dass ich Ressourcenmodelle nicht direkt verwenden sollte.

Könnte mir jemand sagen, welcher Weg der richtige ist und warum ich ihn anstelle aller anderen Methoden verwenden sollte?

czs
quelle
Ich verlinke diesen Thread buchstäblich als verwirrendes Beispiel. Hast du meinen Beitrag überhaupt gelesen?
czs
1
Gute Frage, ich werde versuchen, Zeit zu finden, um sie später ausführlich zu beantworten. Das kann ich Ihnen schon sagen: Es ist ein anderer Fall, wenn Sie Ihre eigenen Modelle (Beispiel von Vinai) oder Modelle der Kern- oder Drittmodule laden (meine Antwort). Wenn Sie das Modell über einen Konstruktor injizieren, erhalten Sie jedes Mal dieselbe Instanz, was zu unerwünschten Nebenwirkungen führen kann.
Fabian Schmengler

Antworten:

12

Der erste Schritt, den Sie für das betreffende Modell überprüfen sollten, ist: Gibt es einen Repository-Servicevertrag? Wenn ja, verwenden Sie dies, da Serviceverträge an die semantische Versionierung gebunden sind und sich bis zum Erscheinen von Magento 3.x weiterhin so verhalten, wie sie sollten. Wenn Sie Ihre eigenen Module mit Modellen erstellen, die Persistenz erfordern, sollten Sie natürlich auch das Repository dafür schreiben.

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

Wenn kein Repository vorhanden ist, verwenden Sie das Ressourcenmodell . Beachten Sie, dass Ressourcenmodelle keinen Status enthalten: Sie verwenden die Persistenz für ihre "regulären" Modelle. Daher müssen Sie sie nicht in einer Fabrik einschließen:

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);
}

"Welchen Nutzen bringt ein Servicevertrag / Repository gegenüber einem Ressourcenmodell?" du könntest fragen. Theoretisch sollte ein Ressourcenmodell nur für die Persistenz eines Datenmodells verantwortlich sein , während ein Repository auch die zusätzlichen Aufgaben berücksichtigt, die beim Speichern einer Entität anfallen. Denken Sie daran, Indizes zu aktualisieren, Beziehungen zu anderen Entitäten herzustellen usw. Dies ist die Theorie, obwohl diese Linien im wirklichen Leben häufig verschwimmen. Aber es ist gut für dich, das im Hinterkopf zu behalten.

Sie sollten nicht die Modelle direkt verwenden save(), load()etc. -Methoden. Sie sind veraltet, weil sie semantisch falsch sind. Denken Sie fest darüber nach:

  • (Daten-) Modelle sollten nur für das Enthalten von Daten verantwortlich sein.
  • Ressourcenmodelle sollten für die Persistenz solcher Daten verantwortlich sein.
  • Repositorys sollten für die Kommunikation innerhalb und außerhalb des Moduls für Persistenzaktionen verantwortlich sein.

Und genau dieser letzte Punkt macht den Unterschied: Wenn man mit anderen Modulen kommuniziert, sollte man sich in einer idealen Welt niemals auf die interne persistente Logik dieser Module verlassen müssen (oder auf eine ihrer öffentlichen Methoden, aber das ist eine andere Diskussion). sondern nur , dass die Funktionalität verwenden , das von der Module zur Verfügung gestellt Serviceverträge .

Abschließend

Um Ihre Frage zu beantworten: in der Reihenfolge Ihrer Präferenz. Der richtige Weg, um ein Modell zu laden, ist:

  • Wenn es ein Repository gibt, laden Sie es über das Repository.
  • Verwenden Sie das Ressourcenmodell (in Kombination mit einer Factory) nur, wenn kein Repository vorhanden ist.
Giel Berkers
quelle
1
Ok, wenn ich richtig folge - wenn ich neue Daten ändern / hinzufügen und in der Datenbank speichern möchte, sollte ich das Ressourcenmodell verwenden und wen ich Daten in den Speicher laden möchte, sollte ich Factory verwenden? Gibt es also eine Situation, in der ich reguläres Modell direkt verwenden sollte (wie bei der Verwendung einer Modellklasse im Konstruktor)?
czs
@czs Sie haben Recht, ich habe ein aussagekräftigeres Beispiel für das Laden von Modellen hinzugefügt.
Milind Singh
2
  • ModelsDiese Datenschnittstelle wird verwendet, um nur die Daten in Objekten zu speichern , dh zu setund getDaten für eine Zeile.
  • ResourceModelssind ein Mechanismus, der für die Persistenz solcher Daten verantwortlich ist, dh die SQL-Abfrage tatsächlich saveoder loadDaten in das ModelObjekt ausführen .

Der richtige Weg zu loadund savesollte darin bestehen, ein Repository zu erstellen oder aus einer Ressource wie folgt zu laden :

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;
    }
}

Hier \MyVendor\MyModule\Api\Data\QueueInterfacewird von QueueModel implementiert .

Hinter den Kulissen erstellen wir also tatsächlich ein ModelObjekt und dann loadingdas ResourceModelObjekt. Dies ist der richtige Weg zum Laden oder Speichern.

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
Milind Singh
quelle