Apa dan mengapa adalah cara yang tepat untuk memuat model

9

Saya memiliki cukup banyak pengalaman dengan Magento tetapi saya menyadari bahwa saya tidak mengerti cara memuat model mana yang benar dan mengapa. Saya sudah membaca semua yang saya bisa, tentang topik ini tetapi orang-orang yang menjelaskan hal-hal seperti ini tidak pernah benar-benar menjelaskan, mengapa menggunakan metode khusus ini daripada yang lain. Mari kita asumsikan tidak ada repositori untuk model yang ingin saya muat.

Sampai sekarang saya selalu menggunakan model dalam konstruktor dan kemudian hanya memuatnya.

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

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

Dan itu selalu berfungsi sebagaimana mestinya, saya juga cukup yakin itu atau setidaknya digunakan secara umum dalam inti.

Tapi kemudian saya melihat salah satu rekan saya menggunakan

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

Sejauh yang saya pahami pabrik digunakan untuk membuat entitas baru, misalnya, jika saya ingin membuat produk baru maka saya dapat membuat pabrik, mengisi dengan data dan menyimpannya. Tapi sekali lagi, saya mulai meneliti topik dan saya melihat contoh dari Fabian Schmengler ( Kapan Kita Harus Menggunakan Repositori dan Pabrik di Magento 2? ) Yang memuat model dengan cara ini dan juga mencegah orang lain dari hanya memuat model, dia tidak Saya tidak menjelaskan mengapa selain mengatakan bahwa itu 'bukan bagian dari kontrak layanan'. Sejauh yang saya mengerti repositori adalah bagian dari kontrak layanan, jadi saya tidak melihat koneksi di sini ketika datang ke memuat model yang tidak tersedia melalui repositori.

Untuk menambahkan lebih banyak kebingungan, saya juga telah menemukan cara memuat model dengan mendapatkan resourceModel dari menciptakan modelFactory, disajikan oleh Vinai Kopp ( Bagaimana menerapkan kontrak layanan untuk modul khusus di Magento 2? ) Dan sekarang saya benar-benar hilang karena saya selalu membaca bahwa saya tidak boleh menggunakan model sumber daya secara langsung.

Jadi ya, bisakah seseorang memberi tahu saya cara mana yang benar dan mengapa saya harus menggunakannya daripada semua metode lainnya?

czs
sumber
Saya benar-benar menautkan utas ini sebagai contoh yang membingungkan, apakah Anda bahkan membaca posting saya?
czs
1
Pertanyaan bagus, saya akan mencoba mencari waktu untuk menjawab secara terperinci nanti. Saya sudah bisa memberi tahu Anda banyak: ini kasus yang berbeda jika Anda memuat model Anda sendiri (misalnya oleh Vinai) atau model modul inti atau pihak ketiga (jawaban saya). Juga, menyuntikkan model melalui konstruktor akan memberi Anda contoh yang sama setiap kali, yang dapat menyebabkan efek samping yang tidak diinginkan.
Fabian Schmengler

Jawaban:

12

Nah, langkah pertama yang harus Anda periksa untuk model yang dimaksud adalah: Apakah ada Kontrak Layanan Repositori? Jika demikian, gunakan itu, karena Kontrak Layanan terikat dengan versi semantik dan akan terus berperilaku seperti seharusnya hingga Magento 3.x keluar. Tak perlu dikatakan, ketika Anda membuat modul Anda sendiri dengan model yang membutuhkan ketekunan, Anda juga harus menulis repositori untuk itu.

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

Jika tidak ada repositori, gunakan model sumber daya . Perhatikan bahwa model sumber daya tidak mengandung status: mereka menggunakan ketekunan untuk model 'reguler' mereka. Oleh karena itu Anda tidak diharuskan untuk menyertakan mereka menggunakan pabrik:

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

"Jadi, manfaat apa yang membawa Kontrak Layanan / Repositori ke Model Sumber Daya?" Anda mungkin bertanya. Nah, dalam teori, Model Sumber Daya seharusnya hanya bertanggung jawab atas kegigihan Model Data , sedangkan Repositori juga memperhitungkan tugas-tugas tambahan yang terlibat saat menyelamatkan suatu entitas. Pikirkan tentang memperbarui indeks, menciptakan hubungan dengan entitas lain, dll. Ini adalah teorinya, meskipun dalam kehidupan nyata garis-garis ini cenderung cukup kabur. Tetapi baik bagi Anda untuk mengingat hal ini.

Anda tidak harus menggunakan model langsung save(), load(), dll -methods. Mereka ditinggalkan karena semantik salah. Pikirkan tentang hal ini secara SOLID:

  • (Data) Model hanya bertanggung jawab untuk memuat data.
  • Model Sumber Daya harus bertanggung jawab atas kegigihan data tersebut.
  • Repositori harus bertanggung jawab atas komunikasi di dalam dan di luar modul untuk tindakan kegigihan.

Dan poin terakhir itulah yang membuat perbedaan: ketika berkomunikasi dengan modul-modul lain, di dunia yang ideal orang tidak perlu mengandalkan logika persisten internal modul itu (atau metode publik apa pun dalam hal ini, tapi itu diskusi lain), tetapi hanya menggunakan fungsionalitas yang disediakan oleh Kontrak Servis modul .

Kesimpulannya

Untuk menjawab pertanyaan Anda: sesuai urutan pilihan. Cara yang benar untuk memuat model adalah:

  • Jika ada Repositori, muat menggunakan Repositori.
  • Hanya jika tidak ada Repositori, gunakan Model Sumber Daya (dalam kombinasi dengan pabrik).
Giel Berkers
sumber
1
Ok, jadi jika saya mengikuti dengan benar - ketika saya ingin memodifikasi / menambahkan data baru dan menyimpannya ke database maka saya harus menggunakan Model Sumber Daya dan jika saya ingin memuat data ke memori maka saya harus menggunakan Pabrik? Jadi apakah ada situasi di mana saya harus menggunakan Model reguler secara langsung (seperti dalam menggunakan kelas Model dalam konstruktor)?
czs
@cz Anda benar Saya telah menambahkan contoh yang lebih deskriptif untuk memuat model untuk hal yang sama.
Milind Singh
2
  • ModelsData Interface digunakan untuk hanya menyimpan data dalam objek, yaitu untuk setdan getdata untuk satu baris.
  • ResourceModelsadalah mekanisme yang bertanggung jawab atas kegigihan data tersebut, yaitu mengeksekusi query SQL sebenarnya saveatau loaddata ke Modelobjek.

Cara yang benar untuk loaddan saveharus dengan membuat repositori atau memuat dari sumber sebagai berikut:

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

Di sini, \MyVendor\MyModule\Api\Data\QueueInterfacedipuji oleh QueueModel.

Jadi, di belakang layar, kita sebenarnya menciptakan Modelobjek maka loadingitu oleh ResourceModelobjek. Ini adalah cara yang benar untuk memuat atau menyimpan.

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