Cara Terbaik untuk Muat Model Kustom di Magento 2

15

Karena sulit bagi saya untuk menemukan jalan yang benar, di bawah ini Anda dapat menemukan praktik terbaik yang saya buat menjadi milik saya. Nikmati, perbaiki bahasa Inggris saya jika perlu dan katakan saya salah jika saya salah. :)

Sunting: ... dan saya tahu saya salah dalam beberapa aspek. Jadi saya memperbarui posting asli setelah jawaban Raphael membantu saya untuk lebih mengerti. Berkat dia !

Konsep yang digunakan di bawah ini :

Akan lebih mudah bagi Anda untuk memahami kode dan penjelasan di bawah ini jika Anda merasa nyaman dengan konsep-konsep ini:

  • Ketergantungan Injeksi (karena setiap $this->variablevariabel dalam kode disuntikkan)
  • Kontrak dan Repositori Layanan
  • Pabrik

Konteks :

Hanya untuk memiliki lebih banyak konteks, bayangkan kita memiliki modul yang dibangun dengan:

  • kelas blok CustomBlock yang berisi metode getCustomModel($id),
  • metode ini mengembalikan objek CustomModel berdasarkan id yang dilewatkan di param,
  • Jenis CustomModel sesuai dengan model di \Vendor\Module\Model\CustomModel
  • Model ini dilengkapi dengan model sumber dayanya (dalam \Vendor\Module\Model\ResourceModel\CustomModel)
  • dan dengan repositori-nya \Vendor\Module\Model\CustomModelRepository.

Pertanyaan :

  • Apa praktik terbaik untuk membiarkan semuanya memuat objek CustomModel?

Anda tidak dapat menggunakan load()dari objek CustomModel karena metode ini sudah usang.

Praktik yang baik mengatakan bahwa Anda harus menggunakan Kontrak Layanan CustomModel. Kontrak layanan adalah antarmuka data (mis. CustomModelInterface) dan antarmuka layanan (mis. CustomModelRepositoryInterface). Jadi blok saya terlihat seperti ini:

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

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

fungsi publik getCustomModel ($ id) {
    return $ this-> customModelRepository-> get ($ id);
}

Pertama-tama, kita menyuntikkan CustomModelRepositoryInterfaceobjek ke dalam konstruktor dan kita menggunakannya dalam getCustomModel()metode kita .

Di kelas Api\CustomModelRepositoryInterfacetidak banyak. Umumnya (tapi tidak mencegah Anda lakukan secara berbeda) Anda akan mendeklarasikan metode dasar: get, getList, save, delete, deleteById. Untuk tujuan topik ini, di bawah ini hanya getdeklarasi metode:

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

Oke, tetapi jika CustomModel Interface saya dipanggil dengan injeksi dependensi di konstruktor blok saya, di mana kodenya? Untuk menjawab pertanyaan ini, Anda harus menjelaskan kepada Magento di mana menemukan kelas yang mengimplementasikan antarmuka ini. Dalam file etc / di.xml modul, Anda harus menambahkan:

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

Jadi CustomModelRepositoryInterfacekelas adalah antarmuka layanan. Dalam mengimplementasikannya Anda harus mengimplementasikan juga antarmuka data (setidaknya Vendor\Module\Api\Data\CustomModelInterfacedan Vendor\Module\Api\Data\CustomModelSearchResultsInterface). Model Anda harus mengimplementasikan Vendor\Module\Api\Data\CustomModelInterfacedan menambahkan <preference ... />baris untuk masing-masing antarmuka Anda. Akhirnya kapan saja Anda menggunakan kontrak layanan, pikirkan mySomethingInterfacetidak lagi di mySomething: biarkan magento menggunakan di.xmlmekanisme preferensi.

Ok, apa yang terjadi selanjutnya? Saat kami menyuntikkan CustomModelRepositoryInterfacedi blok konstruktor, kami mendapatkan CustomModelRepositoryobjek. CustomModelRepositoryharus mengimplementasikan metode yang dinyatakan dalam CustomModelRepositoryInterface. Jadi kita punya ini di Vendor\Module\Model\CustomModelRepository:

fungsi publik dapatkan ($ id) {
    $ customModel = $ this-> customModelFactory-> create ();
    $ customModel-> load ($ id);
    if (! $ customModel-> getId ()) {
      melempar NoSuchEntityException baru (__ ('CustomModel dengan id "% 1" tidak ada.', $ id));
    }
    mengembalikan $ customModel;
}

Apa yang kita lakukan Kami membuat CustomModelobjek kosong berkat pabrik. Selanjutnya kita memuat data dalam CustomModelmenggunakan metode model beban. Selanjutnya kita mengembalikan a NoSuchEntityExceptionjika kita gagal memuat CustomModeldengan id dalam params. Tetapi jika semuanya baik-baik saja, kami mengembalikan objek model dan kehidupan terus berlanjut.

Tapi wow ...! Dalam contoh ini apa itu?

$customModel->load($id);

Bukankah loadmetode usang yang sama dari pada awalnya? Ya itu. Saya pikir ini memalukan, tetapi Anda harus menggunakannya karena dalam metode load () ini ada beberapa acara yang dikirimkan dan pengembang dapat mendengarkannya (lihat jawaban Raphael di bawah).

Di masa depan, kita akan diselamatkan oleh Entity Manager. Ini cerita lain sebagai konsep Magento 2 yang baru, tetapi jika Anda ingin mengetahuinya, Entity Manager sudah diterapkan dalam Resource Model CMS Page (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;
}
Nicolas PERNOT
sumber

Jawaban:

16

Praktik terbaik: melalui kontrak layanan

Praktik terbaik adalah selalu menggunakan kontrak layanan kapan pun memungkinkan. Anda dapat menemukan daftar alasan di sini: Magento 2: apa manfaat menggunakan kontrak layanan?

Untuk detail tentang bagaimana menerapkan kontrak layanan, saya sarankan Anda memeriksa topik ini: Bagaimana menerapkan kontrak layanan untuk modul khusus di Magento 2?

Jika tidak ada kontrak layanan yang tersedia

Jika tidak ada kontrak layanan yang tersedia, Anda harus menggunakan getmetode repositori model . Menggunakan metode ini, Anda mendapat manfaat dari sistem caching magento misalnya untuk CategoryRepositorykelas:

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()Metode usang

Magento 2 perlahan-lahan menjauh dari sistem CRUD standar dengan menjatuhkan sistem warisan dan mengimplementasikannya melalui komposisi menggunakan 2.1 EntityManager baru Anda dapat menemukan detailnya di sini: Magento 2.1: menggunakan manajer entitas

Saya juga menyarankan Anda membaca topik menarik ini tentang metode CRUD yang sudah tidak digunakan lagi: Metode simpan dan muat yang sudah tidak digunakan dalam Model Abstrak

Mengapa tidak menggunakan model sumber daya memuat

Alasan utama adalah bahwa jika Anda menggunakan loadmetode model sumber daya , Anda akan melewati beberapa bagian penting dari sistem pemuatan yang diterapkan dalam loadmetode model , lihat 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;
}

Memanggil loadmetode model sumber daya secara langsung akan memiliki dampak sebagai berikut:

  • _beforeLoad tidak disebut: dengan demikian model memuat sebelum peristiwa tidak dikirim
  • _afterLoad tidak disebut: dengan demikian model memuat setelah peristiwa tidak dikirim
  • data yang disimpan tidak diperbarui yang dapat menyebabkan berbagai masalah (misalnya jika Anda menelepon prepareDataForUpdatedari Magento\Framework\Model\ResourceModel\Db\AbstractDb)
Raphael di Digital Pianism
sumber
Terima kasih Raphael, setiap hal yang Anda katakan masuk akal dan melengkapi pengetahuan saya. Tapi saya tidak mengerti mengapa KAndy berkomentar (di bawah jawabannya) bahwa Marius dapat menggunakan metode load () dari model sumber daya modul kustomnya? Ada di [ magento.stackexchange.com/questions/114929/... simpan dan muat metode dalam Model Abstrak). Ada ide?
Nicolas PERNOT
@NicolasPERNOT pada dasarnya KAndy menjelaskan bahwa tujuannya adalah untuk memiliki SL (Lapisan Layanan) untuk setiap modul dan bahwa inilah yang harus digunakan setiap kali Anda perlu memuat suatu entitas. Saya sarankan Anda berkomentar dengan menyebutkan dia mungkin dia akan dapat mencerahkan Anda karena ia adalah karyawan Magento Inc, saya pikir
Raphael di Digital Pianism
Yah, saya akhirnya memperbarui posting asli saya. Terima kasih Raphael atas bantuan Anda.
Nicolas PERNOT
Saya melihat bahwa setidaknya dalam Magento 2.2 yang penting dimasukkan ke dalam beban ResourceModel, jadi tidak apa-apa untuk menggunakan metode ResourceModel secara langsung, bukan?
Jānis Elmeris
Saat ini, kami dapat memuat Model dengan aman menggunakan metode Resource Model load(). Resource Model menyebut metode model dari metode sendiri load(): $model->beforeLoad() { $this->_beforeLoad() }dan$model->afterLoad() { $this->_afterLoad() }
sergei.sss
-2

Saya pikir pernyataan berikut ini tidak valid sekarang.

Why not using the resource model load

kita dapat menemukan Magento\Framework\EntityManager\Observerfolder semua acara.

Siva Kumar Koduru
sumber