Jak zapisać nowe lub zaktualizowane jednostki modeli?

10

W Magento 2 mamy klasy repozytoriów. Klasyczna metoda save()używana w Magento 1.9 jest przestarzała, jeśli mam rację, od 2.04 lub 2.05. Użyłem fabryk do stworzenia nowego obiektu i po ustawieniu właściwości nowego, na przykład produktu, który nazwałem save():

$productFactory->create()->setName()...->save()

Z drugiej strony mamy repozytoria zawierające również metodę save. Używam go w skrócie:

$product = $productFactory->create()->setName()... $productRepository->save($product)

W moim kodzie mam klasy działające w obie strony. Zauważyłem również, że czasami różne sposoby oznaczają odmienne zachowanie. Czy sposób na repozytoria zapewnił dodatkowe sprawdzanie poprawności danych?

W jaki sposób powinienem to zrobić?

Bartosz Kubicki
źródło

Odpowiedzi:

10

Zobaczmy najpierw, co się stanie, jeśli użyjesz save()metody bezpośrednio na productmodelu takim jak

/**
 * @var Magento\Catalog\Model\Product $product
 */
$product->save();

Sama klasa modeli to

Magento\Catalog\Model\Product

W ramach tej klasy wyszukaj definicję metody save ().

Nie znaleziono, prawda? Cóż, istnieją przedSave () i afterSave (), ale nie same save (). Ciekawe, nie?

Następnie musimy spojrzeć na klasy nadrzędne Magento\Catalog\Model\Product.

Musimy przejść Magento\Catalog\Model\AbstractModeli Magento\Framework\Model\AbstractExtensibleModel, żeby w końcu dojść Magento\Framework\Model\AbstractModel.

Rzeczywiście, tutaj jest metoda save () i wygląda ona mniej więcej tak

public function save()
{
    $this->_getResource()->save($this);
    return $this;
}

Widzimy teraz, za każdym razem, gdy save () jest wywoływane w dowolnym modelu, AbstractModelwywoływana jest metoda save () z tego , a implementacja polega na tym, że MODEL RESOURCE faktycznie zapisuje.

Ten ostatni nie jest zaskakujący, biorąc pod uwagę, że zawsze tak jest, ponieważ, podobnie jak od początku czasu w Magento 1.0, tworzymy zarówno model, jak i model zasobów dla niemal każdego bytu.


Teraz przyjrzyjmy się, jak ProductRepositorydziała.

Pozwala otworzyć plik

/vendor/magento/module-catalog/Api/ProductRepositoryInterface.php

Interfejs ten wymaga między innymi metody save ().

Kto faktycznie wdraża ten interfejs?

Pozwala otworzyć plik

/etc/di.xml

i sprawdź linię 10

<preference for="Magento\Catalog\Api\ProductRepositoryInterface" type="Magento\Catalog\Model\ProductRepository" />

Zatem naturalnie znajdujemy w sobie implantację metody save ()

/vendor/magento/module-catalog/Model/ProductRepository

i zaczyna się na linii 444, wyglądając jak

public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveOptions = false)
{
    $tierPrices = $product->getData('tier_price');

    try {
    .... other code here ....

Ta metoda oczekuje, że obiekt $ produktu zostanie \Magento\Catalog\Api\Data\ProductInterfaceprzekazany, ale domyślnie rozwiązuje to Magento\Catalog\Model\Product.

Patrząc w dół na linię 500, w tryoświadczeniu widzimy coś takiego

$this->resourceModel->save($product);

Zgadłeś dobrze! $this->resourceModeljest typu \Magento\Catalog\Model\ResourceModel\Product, zadeklarowany jako protectedwłaściwość w wierszu 77.

Tak więc znowu ResourceModelfaktycznie oszczędza.

Ale między wierszem 444 a 500 jest tak naprawdę odpowiedzią na twoje pytanie. Cały kod tutaj wykonany, może ostatecznie i będzie prowadzić do różnic w zachowaniu między bezpośrednim zapisaniem modelu a tym sposobem zapisu w repozytorium.

Na przykład repozytorium produktów będzie pobierało i przetwarzało linki do produktów, jeśli ignore_links_flagjest ustawione na 0, sprawdź, czy jest to produkt istniejący, itp.

Prawdopodobnie musimy dojść do wniosku, że jeśli w przyszłości zaistnieje potrzeba zmiany sposobu zapisywania produktu, być może najlepszym sposobem na to jest zastąpienie repozytorium produktu zamiast modelu produktu.

To samo dotyczy zapisywania i aktualizowania produktów. Wolałbym użyć obiektu repozytorium produktów.

Uprzejmie odsyłam również do /vendor/magento/module-cms/Model/PageRepository.php

W ten sposób strona CMS byłaby zapisywana za pośrednictwem repozytorium. Tutaj rzeczy są prostsze. Identyfikator sklepu jest ustawiony, a model zasobów jest wywoływany w celu natychmiastowego zapisania.

Na podstawie tego ostatniego zawiadomienia dojdziesz do wniosku, że w niektórych przypadkach różnice między repozytorium a zapisem modelu mogą nie być zbyt duże, ale mam nadzieję, że masz teraz możliwość ich wykrycia, gdy tylko zajdzie taka potrzeba.

Marjan
źródło
1

Zachęca się do korzystania z interfejsów danych (np. \Magento\Catalog\Api\Data\ProductInterface) Zamiast modelu bezpośrednio i do korzystania z repozytoriów do ładowania i zapisywania modeli.

Zobacz dokumentację programisty Magento

ochnygosch
źródło
1
ok - to właściwy sposób dla całej encji - ale tylko w celu aktualizacji wartości niektórych atrybutów - myślę, że ładowanie / zapisywanie całej encji nie jest zalecane.
Bartosz Kubicki