Beste Möglichkeit, ein benutzerdefiniertes Modell in Magento 2 zu laden

15

Da es mir schwerfiel, den richtigen Weg zu finden, konnten Sie unten die besten Methoden finden, die ich für mich entwickelt habe. Genießen Sie, korrigieren Sie mein Englisch, wenn nötig, und sagen Sie mir, dass ich mich irre, wenn ich es bin. :)

Edit: ... und ich fand heraus, dass ich in einem Aspekt falsch lag. Also habe ich den ursprünglichen Beitrag aktualisiert, nachdem Raphaels Antworten mir geholfen haben, mehr zu verstehen. Dank ihm !

Das unten verwendete Konzept :

Wenn Sie mit diesen Konzepten vertraut sind, ist es für Sie einfacher, die folgenden Codes und Erklärungen zu verstehen:

  • Injektionsabhängigkeit (da alle $this->variableVariablen in Codes injiziert werden)
  • Servicevertrag und Repository
  • Fabrik

Kontext :

Um mehr Kontext zu haben, stellen Sie sich vor, wir haben ein Modul, das richtig konstruiert ist mit:

  • eine Blockklasse CustomBlock, die eine Methode enthält getCustomModel($id),
  • Diese Methode gibt ein CustomModel-Objekt zurück, das auf der in param übergebenen ID basiert.
  • Der CustomModel-Typ entspricht dem Modell in \Vendor\Module\Model\CustomModel
  • Dieses Modell wird mit seinem Ressourcenmodell (in \Vendor\Module\Model\ResourceModel\CustomModel) geliefert.
  • und mit seinem Repository (in \Vendor\Module\Model\CustomModelRepository).

Frage :

  • Was ist die beste Methode, um ein CustomModel-Objekt vollständig laden zu lassen?

Sie können das load()von einem CustomModel-Objekt nicht verwenden, da diese Methode veraltet ist.

Nach der guten Praxis müssen Sie den CustomModel-Servicevertrag verwenden. Serviceverträge sind Datenschnittstellen (zB CustomModelInterface) und Serviceschnittstellen (zB CustomModelRepositoryInterface). Mein Block sieht also so aus:

/ ** @var SlideRepositoryInterface * /
protected $ slideRepository;

/ **
 * CustomBlock-Konstruktor
 * ...
 * @param CustomModelRepositoryInterface $ customModelRepository
 * ...
 * /
public function __construct (
...
CustomModelRepositoryInterface $ customModelRepository
...
) {
    $ this-> customModelRepository = $ customModelRepository;
}

öffentliche Funktion getCustomModel ($ id) {
    return $ this-> customModelRepository-> get ($ id);
}

Zunächst injizieren wir das CustomModelRepositoryInterfaceObjekt in den Konstruktor und verwenden es in unserer getCustomModel()Methode.

In der Klasse Api\CustomModelRepositoryInterfacegibt es nicht viel. Im Allgemeinen (aber nichts verhindern , dass Sie anders machen) finden Sie grundlegende Methoden erklären: get, getList, save, delete, deleteById. Für den Zweck dieses Themas ist im Folgenden nur die getMethodendeklaration aufgeführt:

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

Ok, aber wenn mein CustomModel-Interface durch Abhängigkeitsinjektion in meinem Blockkonstruktor aufgerufen wird, wo ist der Code? Um diese Frage zu beantworten, müssen Sie Magento erklären, wo sich die Klasse befindet, die diese Schnittstelle implementiert. In der etc / di.xml-Datei des Moduls müssen Sie Folgendes hinzufügen:

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

So CustomModelRepositoryInterfaceKlasse ist eine Service - Schnittstelle. Bei der Implementierung müssen Sie (mindestens Vendor\Module\Api\Data\CustomModelInterfaceund Vendor\Module\Api\Data\CustomModelSearchResultsInterface) auch Datenschnittstellen implementieren . Ihr Modell muss Zeilen für jede Ihrer Schnittstellen implementieren Vendor\Module\Api\Data\CustomModelInterfaceund hinzufügen <preference ... />. Zu jedem Zeitpunkt, an dem Sie den Servicevertrag nutzen, sollten Sie mySomethingInterfacenicht mehr daran denken mySomething: Lassen Sie Magento den Voreinstellungsmechanismus nutzen di.xml.

Ok was kommt als nächstes Wenn wir CustomModelRepositoryInterfaceden Blockkonstruktor einfügen, erhalten wir ein CustomModelRepositoryObjekt. CustomModelRepositorymuss die Methode declare in implementieren CustomModelRepositoryInterface. Das haben wir also in Vendor\Module\Model\CustomModelRepository:

public function get ($ id) {
    $ customModel = $ this-> customModelFactory-> create ();
    $ customModel-> load ($ id);
    if (! $ customModel-> getId ()) {
      Neue NoSuchEntityException auslösen (__ ('CustomModel mit der ID "% 1" existiert nicht.', $ id));
    }
    return $ customModel;
}

Was machst du ? CustomModelDank der Fabrik schaffen wir ein leeres Objekt. Als nächstes laden wir Daten CustomModelmit der Lademodellmethode. Als nächstes geben wir ein zurück, NoSuchEntityExceptionwenn wir das nicht CustomModelmit der ID in params laden konnten. Aber wenn alles in Ordnung ist, geben wir das Modellobjekt zurück und das Leben geht weiter.

Aber wow ...! In diesem Beispiel, was ist das?

$customModel->load($id);

Ist das nicht dieselbe veraltete loadMethode wie zu Beginn? Ja ist es. Ich denke, es ist eine Schande, aber Sie müssen es verwenden, da in dieser load () -Methode einige Ereignisse ausgelöst werden und der Entwickler auf sie warten kann (siehe Raphaels Antwort unten).

In Zukunft werden wir von Entity Manager gespeichert. Es ist eine andere Geschichte als ein neues Magento 2-Konzept, aber wenn Sie einen Blick darauf werfen möchten, ist Entity Manager bereits im Ressourcenmodell von CMS Page (v2.1) implementiert:

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

Antworten:

15

Best Practice: über den Servicevertrag

Die beste Vorgehensweise ist immer, den Servicevertrag zu verwenden, wann immer dies möglich ist. Die Liste der Gründe finden Sie hier: Magento 2: Welche Vorteile bietet die Verwendung von Serviceverträgen?

Einzelheiten zum Implementieren eines Servicevertrags finden Sie in folgendem Thema: So implementieren Sie einen Servicevertrag für ein benutzerdefiniertes Modul in Magento 2?

Liegt kein Servicevertrag vor

Wenn kein Servicevertrag verfügbar ist, sollten Sie die Modellrepository- getMethode verwenden. Mit dieser Methode profitieren Sie vom Magento-Caching-System zum Beispiel für die CategoryRepositoryKlasse:

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

Veraltete load()Methode

Magento 2 entfernt sich langsam vom Standard-CRUD-System, indem das Vererbungssystem gelöscht und mit dem neuen 2.1-EntityManager über Komposition implementiert wird. Details finden Sie hier: Magento 2.1: Verwenden des Entity Managers

Außerdem empfehle ich Ihnen, dieses interessante Thema über die veralteten CRUD-Methoden zu lesen: Veraltete Methoden zum Speichern und Laden in Abstract Model

Warum nicht das Ressourcenmodell laden

Der Hauptgrund ist, dass Sie bei Verwendung der Ressourcenmodellmethode loadeinen wichtigen Teil des Ladesystems überspringen, der in der Modellmethode implementiert loadist. Siehe 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;
}

Das loaddirekte Aufrufen der Ressourcenmodellmethode hat folgende Auswirkungen:

  • _beforeLoad wird nicht aufgerufen: somit wird die Modelllast vor Ereignissen nicht ausgelöst
  • _afterLoad wird nicht aufgerufen: somit wird die Modelllast nach Ereignissen nicht ausgelöst
  • die gespeicherten Daten werden nicht aktualisiert, was zu verschiedenen Problemen führen kann (zB wenn Sie anrufen prepareDataForUpdatevon Magento\Framework\Model\ResourceModel\Db\AbstractDb)
Raphael bei Digital Pianism
quelle
Danke Raphael, alles was du sagst macht Sinn und vervollständigt mein Wissen. Aber ich verstehe nicht, warum KAndy (unter seiner Antwort) kommentiert, dass Marius die load () -Methode seines benutzerdefinierten Modulressourcenmodells verwenden kann? Es befindet sich in [ magento.stackexchange.com/questions/114929/… Methoden in Abstract Model speichern und laden]. Irgendwelche Ideen ?
Nicolas PERNOT
@NicolasPERNOT Grundsätzlich erklärt KAndy, dass das Ziel SL (Service Layer) für jedes Modul ist und dass dies jedes Mal verwendet werden muss, wenn Sie eine Entität laden müssen. Ich schlage vor, Sie kommentieren ihn, indem Sie ihn erwähnen. Vielleicht kann er Sie aufklären, da er ein Mitarbeiter von Magento Inc ist, denke ich
Raphael bei Digital Pianism
Nun, ich habe endlich meinen ursprünglichen Beitrag aktualisiert. Danke Raphael für deine Hilfe.
Nicolas PERNOT
Ich sehe, dass zumindest in Magento 2.2 das Wichtige in ResourceModels Load enthalten ist, so dass es nicht in Ordnung ist, ResourceModel-Methoden direkt zu verwenden, oder?
Jānis Elmeris
Derzeit können wir Model mit der Resource Model- load()Methode sicher laden . Das Ressourcenmodell ruft die Methoden des Modells von der eigenen load()Methode auf: $model->beforeLoad() { $this->_beforeLoad() }und$model->afterLoad() { $this->_afterLoad() }
sergei.sss
-1

Ich denke, die folgende Aussage ist jetzt nicht gültig.

Why not using the resource model load

wir können Magento\Framework\EntityManager\Observerordner alle veranstaltungen finden.

Siva Kumar Koduru
quelle