Bagaimana cara menerapkan kontrak layanan untuk modul khusus di Magento 2?

42

Seperti yang terlihat di posting ini: Usang menyimpan dan metode beban di Abstrak Model yang savedan loadmetode yang usang dalam Magento 2 mengembangkan cabang.

Dengan demikian, praktik yang baik sekarang adalah menerapkan kontrak layanan untuk berurusan dengan entitas CRUD.

Apa proses langkah demi langkah yang harus saya ikuti untuk menerapkan kontrak layanan untuk entitas modul khusus saya?

NB: Saya tahu mungkin ada ribuan metode dalam model CRUD saya, saya hanya meminta metode yang jelas seperti yang dinyatakan di sini: http://devdocs.magento.com/guides/v2.0/extension-dev-guide /service-contracts/design-patterns.html :

  • get
  • save
  • getList
  • delete
  • deleteById
Raphael di Digital Pianism
sumber

Jawaban:

90

Saya ingin memberikan sedikit lebih detail selain jawaban yang sangat bagus dari @ryanF.

Saya ingin meringkas alasan untuk menambahkan repositori untuk entitas kustom, memberikan contoh cara melakukannya, dan juga menjelaskan cara mengekspos metode repositori tersebut sebagai bagian dari Web API.

Penafian: Saya hanya menjelaskan pendekatan pragmatis bagaimana melakukan ini untuk modul pihak ketiga - tim inti memiliki standar sendiri yang mereka ikuti (atau tidak).

Secara umum, tujuan repositori adalah untuk menyembunyikan logika terkait penyimpanan.
Klien repositori tidak perlu peduli apakah entitas yang dikembalikan disimpan dalam memori dalam array, diambil dari database MySQL, diambil dari API jarak jauh atau dari file.
Saya menganggap tim inti Magento melakukan ini sehingga mereka dapat mengubah atau mengganti ORM di masa depan. Di Magento, ORM saat ini terdiri dari Model, Model Sumber Daya, dan Koleksi.
Jika modul pihak ketiga hanya menggunakan repositori, Magento dapat mengubah bagaimana dan di mana data disimpan, dan modul akan terus bekerja, meskipun ada perubahan yang dalam.

Repositori umumnya memiliki metode seperti findById(), findByName(), put()atau remove().
Di Magento ini biasa disebut getbyId(), save()dan delete(), bahkan tidak berpura-pura melakukan hal lain selain operasi CRUD DB.

Metode repositori Magento 2 dapat dengan mudah diekspos sebagai sumber daya API, membuatnya berharga untuk integrasi dengan sistem pihak ketiga atau instance Magento tanpa kepala.

"Haruskah saya menambahkan repositori untuk entitas kustom saya?"

Seperti biasa, jawabannya adalah

"Tergantung".

Untuk mempersingkat cerita, jika entitas Anda akan digunakan oleh modul lain, maka ya, Anda mungkin ingin menambahkan repositori.

Ada faktor lain yang diperhitungkan di sini: di Magento 2, repositori dapat dengan mudah diekspos sebagai API Web - yaitu REST dan SOAP - sumber daya.

Jika itu menarik bagi Anda karena integrasi sistem pihak ketiga atau pengaturan Magento tanpa kepala, sekali lagi, ya, Anda mungkin ingin menambahkan repositori untuk entitas Anda.

Bagaimana cara menambahkan repositori untuk entitas khusus saya?

Mari kita asumsikan Anda ingin mengekspos entitas Anda sebagai bagian dari API REST. Jika itu tidak benar, Anda dapat melewati bagian yang akan datang untuk membuat antarmuka dan langsung ke "Buat repositori dan implementasi model data" di bawah ini.

Buat repositori dan antarmuka model data

Buat folder Api/Data/di modul Anda. Ini hanya konvensi, Anda bisa menggunakan lokasi yang berbeda, tetapi Anda tidak boleh.
Repositori masuk ke Api/folder. The Data/subdirektori adalah untuk nanti.

Di Api/, buat antarmuka PHP dengan metode yang ingin Anda paparkan. Menurut konvensi Magento 2, semua nama antarmuka berakhir dengan akhiran Interface.
Misalnya, untuk Hamburgerentitas, saya akan membuat antarmuka Api/HamburgerRepositoryInterface.

Buat antarmuka repositori

Repositori Magento 2 adalah bagian dari logika domain modul. Itu berarti, tidak ada set metode tetap yang harus diterapkan oleh repositori.
Itu sepenuhnya tergantung pada tujuan modul.

Namun, dalam praktiknya semua repositori sangat mirip. Mereka adalah pembungkus untuk fungsionalitas CRUD.
Sebagian besar memiliki metode getById, save, deletedan getList.
Mungkin ada lebih banyak, misalnya CustomerRepositorymemiliki metode get, yang menjemput pelanggan melalui email, getByIdyang digunakan untuk mengambil pelanggan dengan ID entitas.

Berikut ini contoh antarmuka repositori untuk entitas hamburger:

<?php

namespace VinaiKopp\Kitchen\Api;

use Magento\Framework\Api\SearchCriteriaInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerInterface;

interface HamburgerRepositoryInterface
{
    /**
     * @param int $id
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getById($id);

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerInterface $hamburger
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
     */
    public function save(HamburgerInterface $hamburger);

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerInterface $hamburger
     * @return void
     */
    public function delete(HamburgerInterface $hamburger);

    /**
     * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface
     */
    public function getList(SearchCriteriaInterface $searchCriteria);

}

Penting! Di sini ada timesinks!
Ada beberapa gotcha di sini yang sulit di-debug jika Anda salah paham:

  1. JANGAN gunakan jenis argumen skalar PHP7 atau ketik kembali jika Anda ingin menghubungkan ini ke REST API!
  2. Tambahkan penjelasan PHPDoc untuk semua argumen dan jenis kembali ke semua metode!
  3. Gunakan Nama Kelas yang Sepenuhnya Memenuhi Syarat di blok PHPDoc!

Anotasi diuraikan oleh Magento Framework untuk menentukan bagaimana mengkonversi data ke dan dari JSON atau XML. Impor kelas (yaitu, usepernyataan) tidak diterapkan!

Setiap metode harus memiliki anotasi dengan jenis argumen apa pun dan jenis kembali. Bahkan jika suatu metode tidak mengambil argumen dan tidak menghasilkan apa-apa, itu harus memiliki anotasi:

/**
 * @return void
 */

Jenis skalar ( string, int, floatdan bool) juga harus ditentukan, baik untuk argumen dan sebagai nilai kembali.

Perhatikan bahwa pada contoh di atas, anotasi untuk metode yang mengembalikan objek juga ditentukan sebagai antarmuka.
Jenis antarmuka kembali semua dalam Api\Datadirektori namespace /.
Ini untuk menunjukkan bahwa mereka tidak mengandung logika bisnis. Mereka hanyalah sekumpulan data.
Kita harus membuat antarmuka ini selanjutnya.

Buat antarmuka DTO

Saya pikir Magento menyebut antarmuka ini "model data", nama yang saya tidak suka sama sekali.
Tipe kelas ini umumnya dikenal sebagai Obyek Transfer Data , atau DTO .
Kelas-kelas DTO ini hanya memiliki getter dan setter untuk semua propertinya.

Alasan saya lebih suka menggunakan DTO daripada model data adalah bahwa kurang mudah untuk bingung dengan model data ORM, model sumber daya atau model tampilan ... terlalu banyak hal sudah model di Magento.

Pembatasan yang sama terkait pengetikan PHP7 yang berlaku untuk repositori juga berlaku untuk DTO.
Juga, setiap metode harus memiliki anotasi dengan semua tipe argumen dan tipe pengembalian.

<?php

namespace VinaiKopp\Kitchen\Api\Data;

use Magento\Framework\Api\ExtensibleDataInterface;

interface HamburgerInterface extends ExtensibleDataInterface
{
    /**
     * @return int
     */
    public function getId();

    /**
     * @param int $id
     * @return void
     */
    public function setId($id);

    /**
     * @return string
     */
    public function getName();

    /**
     * @param string $name
     * @return void
     */
    public function setName($name);

    /**
     * @return \VinaiKopp\Kitchen\Api\Data\IngredientInterface[]
     */
    public function getIngredients();

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\IngredientInterface[] $ingredients
     * @return void
     */
    public function setIngredients(array $ingredients);

    /**
     * @return string[]
     */
    public function getImageUrls();

    /**
     * @param string[] $urls
     * @return void
     */
    public function setImageUrls(array $urls);

    /**
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface|null
     */
    public function getExtensionAttributes();

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface $extensionAttributes
     * @return void
     */
    public function setExtensionAttributes(HamburgerExtensionInterface $extensionAttributes);
}

Jika metode mengambil atau mengembalikan array, jenis item dalam array harus ditentukan dalam penjelasan PHPDoc, diikuti oleh tanda kurung buka dan tutup [].
Ini berlaku untuk nilai skalar (misalnya int[]) maupun objek (misalnya IngredientInterface[]).

Perhatikan bahwa saya menggunakan Api\Data\IngredientInterfacecontoh untuk metode mengembalikan array objek, saya tidak akan menambahkan kode bahan ke posting sulit ini.

ExtensibleDataInterface?

Dalam contoh di atas HamburgerInterfacemeluas ExtensibleDataInterface.
Secara teknis ini hanya diperlukan jika Anda ingin modul lain dapat menambahkan atribut ke entitas Anda.
Jika demikian, Anda juga perlu menambahkan pasangan pengambil / penyetel lain, dengan konvensi dipanggil getExtensionAttributes()dan setExtensionAttributes().

Penamaan tipe pengembalian metode ini sangat penting!

Kerangka kerja Magento 2 akan menghasilkan antarmuka, implementasi, dan pabrik untuk implementasi jika Anda menamainya dengan tepat. Detail dari mekanika ini berada di luar cakupan tulisan ini.
Sekadar tahu, jika antarmuka objek yang ingin Anda buat extensible disebut \VinaiKopp\Kitchen\Api\Data\HamburgerInterface, maka jenis atribut ekstensi haruslah \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface. Jadi kata Extensiontersebut harus dimasukkan setelah nama entitas, tepat sebelum Interfaceakhiran.

Jika Anda tidak ingin entitas Anda dapat diperluas, maka antarmuka DTO tidak harus memperluas antarmuka lainnya, getExtensionAttributes()dan setExtensionAttributes()metode dan dapat dihilangkan.

Cukup tentang antarmuka DTO untuk saat ini, saatnya untuk kembali ke antarmuka repositori.

GetList () mengembalikan tipe SearchResults

Metode repositori getListmengembalikan tipe lain, yaitu SearchResultsInterfaceinstance.

Metode getListtentu saja bisa saja mengembalikan array objek yang cocok dengan yang ditentukan SearchCriteria, tetapi mengembalikan sebuah SearchResultsinstance memungkinkan menambahkan beberapa data meta yang berguna ke nilai yang dikembalikan.

Anda dapat melihat cara kerjanya di bawah ini dalam getList()implementasi metode repositori .

Berikut ini contoh antarmuka hasil pencarian hamburger:

<?php

namespace VinaiKopp\Kitchen\Api\Data;

use Magento\Framework\Api\SearchResultsInterface;

interface HamburgerSearchResultInterface extends SearchResultsInterface
{
    /**
     * @return \VinaiKopp\Kitchen\Api\Data\HamburgerInterface[]
     */
    public function getItems();

    /**
     * @param \VinaiKopp\Kitchen\Api\Data\HamburgerInterface[] $items
     * @return void
     */
    public function setItems(array $items);
}

Semua antarmuka ini dilakukan hanya mengganti tipe untuk dua metode getItems()dan setItems()antarmuka induk.

Ringkasan antarmuka

Kami sekarang memiliki antarmuka berikut:

  • \VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface
  • \VinaiKopp\Kitchen\Api\Data\HamburgerInterface
  • \VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface

Repositori meluas apa-apa,
yang HamburgerInterfacememperluas \Magento\Framework\Api\ExtensibleDataInterface,
dan HamburgerSearchResultInterfacememperluas \Magento\Framework\Api\SearchResultsInterface.

Buat repositori dan implementasi model data

Langkah selanjutnya adalah membuat implementasi dari tiga antarmuka.

Repositori

Intinya, repositori menggunakan ORM untuk melakukan tugasnya.

Metode getById(), save() dan delete()metodenya cukup lurus ke depan.
Itu HamburgerFactorydisuntikkan ke repositori sebagai argumen konstruktor, seperti yang dapat dilihat sedikit lebih jauh di bawah ini.

public function getById($id)
{
    $hamburger = $this->hamburgerFactory->create();
    $hamburger->getResource()->load($hamburger, $id);
    if (! $hamburger->getId()) {
        throw new NoSuchEntityException(__('Unable to find hamburger with ID "%1"', $id));
    }
    return $hamburger;
}

public function save(HamburgerInterface $hamburger)
{
    $hamburger->getResource()->save($hamburger);
    return $hamburger;
}

public function delete(HamburgerInterface $hamburger)
{
    $hamburger->getResource()->delete($hamburger);
}

Sekarang ke bagian repositori, getList()metode yang paling menarik .
The getList()metode memiliki untuk menerjemahkan SerachCriteriakondisi dalam metode panggilan pada koleksi.

Bagian rumit dari mendapatkan ANDdan ORkondisi untuk filter yang tepat, terutama karena sintaks untuk mengatur kondisi pada koleksi berbeda tergantung pada apakah itu adalah EAV atau entitas tabel datar.

Dalam kebanyakan kasus, getList()dapat diimplementasikan seperti diilustrasikan dalam contoh di bawah ini.

<?php

namespace VinaiKopp\Kitchen\Model;

use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SortOrder;
use Magento\Framework\Exception\NoSuchEntityException;
use VinaiKopp\Kitchen\Api\Data\HamburgerInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterfaceFactory;
use VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface;
use VinaiKopp\Kitchen\Model\ResourceModel\Hamburger\CollectionFactory as HamburgerCollectionFactory;
use VinaiKopp\Kitchen\Model\ResourceModel\Hamburger\Collection;

class HamburgerRepository implements HamburgerRepositoryInterface
{
    /**
     * @var HamburgerFactory
     */
    private $hamburgerFactory;

    /**
     * @var HamburgerCollectionFactory
     */
    private $hamburgerCollectionFactory;

    /**
     * @var HamburgerSearchResultInterfaceFactory
     */
    private $searchResultFactory;

    public function __construct(
        HamburgerFactory $hamburgerFactory,
        HamburgerCollectionFactory $hamburgerCollectionFactory,
        HamburgerSearchResultInterfaceFactory $hamburgerSearchResultInterfaceFactory
    ) {
        $this->hamburgerFactory = $hamburgerFactory;
        $this->hamburgerCollectionFactory = $hamburgerCollectionFactory;
        $this->searchResultFactory = $hamburgerSearchResultInterfaceFactory;
    }

    // ... getById, save and delete methods listed above ...

    public function getList(SearchCriteriaInterface $searchCriteria)
    {
        $collection = $this->collectionFactory->create();

        $this->addFiltersToCollection($searchCriteria, $collection);
        $this->addSortOrdersToCollection($searchCriteria, $collection);
        $this->addPagingToCollection($searchCriteria, $collection);

        $collection->load();

        return $this->buildSearchResult($searchCriteria, $collection);
    }

    private function addFiltersToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        foreach ($searchCriteria->getFilterGroups() as $filterGroup) {
            $fields = $conditions = [];
            foreach ($filterGroup->getFilters() as $filter) {
                $fields[] = $filter->getField();
                $conditions[] = [$filter->getConditionType() => $filter->getValue()];
            }
            $collection->addFieldToFilter($fields, $conditions);
        }
    }

    private function addSortOrdersToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        foreach ((array) $searchCriteria->getSortOrders() as $sortOrder) {
            $direction = $sortOrder->getDirection() == SortOrder::SORT_ASC ? 'asc' : 'desc';
            $collection->addOrder($sortOrder->getField(), $direction);
        }
    }

    private function addPagingToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        $collection->setPageSize($searchCriteria->getPageSize());
        $collection->setCurPage($searchCriteria->getCurrentPage());
    }

    private function buildSearchResult(SearchCriteriaInterface $searchCriteria, Collection $collection)
    {
        $searchResults = $this->searchResultFactory->create();

        $searchResults->setSearchCriteria($searchCriteria);
        $searchResults->setItems($collection->getItems());
        $searchResults->setTotalCount($collection->getSize());

        return $searchResults;
    }
}

Filter dalam a FilterGroupharus dikombinasikan menggunakan operator ATAU .
Grup filter terpisah digabungkan menggunakan operator logika DAN .

Fiuh
Ini adalah pekerjaan terbesar. Implementasi antarmuka lainnya lebih sederhana.

DTO

Magento awalnya dimaksudkan pengembang untuk menerapkan DTO sebagai kelas yang terpisah, berbeda dari model entitas.

Tim inti hanya melakukan ini untuk modul pelanggan ( \Magento\Customer\Api\Data\CustomerInterfacediterapkan oleh \Magento\Customer\Model\Data\Customer, bukan \Magento\Customer\Model\Customer).
Dalam semua kasus lain, model entitas mengimplementasikan antarmuka DTO (misalnya \Magento\Catalog\Api\Data\ProductInterfacediimplementasikan oleh \Magento\Catalog\Model\Product).

Saya telah bertanya kepada anggota tim inti tentang hal ini di konferensi, tetapi saya tidak mendapatkan jawaban yang jelas apa yang dianggap praktik yang baik.
Kesan saya adalah bahwa rekomendasi ini telah ditinggalkan. Akan menyenangkan untuk mendapatkan pernyataan resmi tentang ini.

Untuk saat ini saya telah membuat keputusan pragmatis untuk menggunakan model sebagai implementasi antarmuka DTO. Jika Anda merasa lebih bersih menggunakan model data terpisah, jangan ragu untuk melakukannya. Kedua pendekatan bekerja dengan baik dalam praktik.

Jika DTO inteface memperluas Magento\Framework\Api\ExtensibleDataInterface, model harus diperluas Magento\Framework\Model\AbstractExtensibleModel.
Jika Anda tidak peduli tentang ekstensibilitas, model hanya dapat terus memperluas kelas dasar model ORM Magento\Framework\Model\AbstractModel.

Karena contoh HamburgerInterfacemeluas ExtensibleDataInterfacemodel hamburger memperluas AbstractExtensibleModel, seperti dapat dilihat di sini:

<?php

namespace VinaiKopp\Kitchen\Model;

use Magento\Framework\Model\AbstractExtensibleModel;
use VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface;
use VinaiKopp\Kitchen\Api\Data\HamburgerInterface;

class Hamburger extends AbstractExtensibleModel implements HamburgerInterface
{
    const NAME = 'name';
    const INGREDIENTS = 'ingredients';
    const IMAGE_URLS = 'image_urls';

    protected function _construct()
    {
        $this->_init(ResourceModel\Hamburger::class);
    }

    public function getName()
    {
        return $this->_getData(self::NAME);
    }

    public function setName($name)
    {
        $this->setData(self::NAME, $name);
    }

    public function getIngredients()
    {
        return $this->_getData(self::INGREDIENTS);
    }

    public function setIngredients(array $ingredients)
    {
        $this->setData(self::INGREDIENTS, $ingredients);
    }

    public function getImageUrls()
    {
        $this->_getData(self::IMAGE_URLS);
    }

    public function setImageUrls(array $urls)
    {
        $this->setData(self::IMAGE_URLS, $urls);
    }

    public function getExtensionAttributes()
    {
        return $this->_getExtensionAttributes();
    }

    public function setExtensionAttributes(HamburgerExtensionInterface $extensionAttributes)
    {
        $this->_setExtensionAttributes($extensionAttributes);
    }
}

Mengekstraksi nama properti menjadi konstanta memungkinkan untuk menyimpannya di satu tempat. Mereka dapat digunakan oleh pasangan pengambil / penyetel dan juga oleh skrip Penataan yang membuat tabel database. Kalau tidak, tidak ada untungnya mengekstraksi mereka menjadi konstanta.

SearchResult

Ini SearchResultsInterfaceadalah yang paling sederhana dari tiga antarmuka untuk diimplementasikan, karena dapat mewarisi semua fungsionalitasnya dari kelas kerangka kerja.

<?php

namespace VinaiKopp\Kitchen\Model;

use Magento\Framework\Api\SearchResults;
use VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface;

class HamburgerSearchResult extends SearchResults implements HamburgerSearchResultInterface
{

}

Konfigurasikan preferensi ObjectManager

Meskipun implementasinya selesai, kami masih tidak dapat menggunakan antarmuka sebagai dependensi dari kelas lain, karena manajer objek Magento Framework tidak tahu implementasi apa yang digunakan. Kita perlu menambahkan etc/di.xmlkonfigurasi untuk preferensi.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" type="VinaiKopp\Kitchen\Model\HamburgerRepository"/>
    <preference for="VinaiKopp\Kitchen\Api\Data\HamburgerInterface" type="VinaiKopp\Kitchen\Model\Hamburger"/>
    <preference for="VinaiKopp\Kitchen\Api\Data\HamburgerSearchResultInterface" type="VinaiKopp\Kitchen\Model\HamburgerSearchResult"/>
</config>

Bagaimana repositori dapat diekspos sebagai sumber daya API?

Bagian ini sangat sederhana, ini adalah hadiah untuk melalui semua pekerjaan menciptakan antarmuka, implementasi dan menghubungkannya bersama-sama.

Yang perlu kita lakukan hanyalah membuat etc/webapi.xmlfile.

<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
    <route method="GET" url="/V1/vinaikopp_hamburgers/:id">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="getById"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
    <route method="GET" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="getList"/>
        <resources>
            <resource ref="anonymouns"/>
        </resources>
    </route>
    <route method="POST" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="save"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
    <route method="PUT" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="save"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
    <route method="DELETE" url="/V1/vinaikopp_hamburgers">
        <service class="VinaiKopp\Kitchen\Api\HamburgerRepositoryInterface" method="delete"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
</routes>

Perhatikan bahwa konfigurasi ini tidak hanya memungkinkan penggunaan repositori sebagai titik akhir REST, tetapi juga memperlihatkan metode sebagai bagian dari SOAP API.

Dalam contoh rute pertama <route method="GET" url="/V1/vinaikopp_hamburgers/:id">,, placeholder :idharus mencocokkan nama argumen dengan metode yang dipetakan public function getById($id),.
Kedua nama harus cocok, misalnya /V1/vinaikopp_hamburgers/:hamburgerIdtidak akan berfungsi, karena nama variabel argumen metode adalah $id.

Untuk contoh ini saya telah mengatur aksesibilitas ke <resource ref="anonymous"/>. Ini berarti sumber daya diekspos secara publik tanpa batasan apa pun!
Untuk membuat sumber daya hanya tersedia untuk pelanggan yang masuk, gunakan <resource ref="self"/>. Dalam hal ini, kata khusus medalam URL titik akhir sumber daya akan digunakan untuk mengisi variabel argumen $iddengan ID pelanggan yang saat ini masuk.
Lihatlah Pelanggan Magento etc/webapi.xmldan CustomerRepositoryInterfacejika Anda membutuhkannya.

Akhirnya, <resources>ini juga dapat digunakan untuk membatasi akses ke sumber daya ke akun pengguna admin. Untuk melakukan ini, setel <resource>ref ke pengenal yang ditentukan dalam etc/acl.xmlfile.
Misalnya, <resource ref="Magento_Customer::manage"/>akan membatasi akses ke akun admin apa pun yang memiliki hak istimewa untuk mengelola pelanggan.

Contoh permintaan API menggunakan curl bisa terlihat seperti ini:

$ curl -X GET http://example.com/rest/V1/vinaikopp_hamburgers/123

Catatan: menulis ini dimulai sebagai jawaban untuk https://github.com/astorm/pestle/issues/195
Periksa alu , beli Commercebug dan menjadi pelindung @alanstorm

Vinai
sumber
1
Terima kasih atas jawaban yang bagus ini. Maaf mungkin saya kehilangan sesuatu, tetapi apa gunanya memiliki antarmuka yang bersih untuk suatu entitas ketika pada akhirnya harus diperluas dari AbstractModel yang memiliki metode setData yang berarti bahwa Anda dapat menambahkan apa pun ke objek terlepas dari antarmuka?
LDusan
Kelas dapat mengimplementasikan sejumlah antarmuka dan menambahkan metode tambahan juga. Yang penting adalah bahwa kelas lain hanya bergantung pada metode antarmuka dan karenanya tidak tahu tentang yang lain. Itu membuat rincian implementasi metode non-antarmuka, yang dapat diubah setiap saat tanpa melanggar kelas eksternal. Itulah ide di balik inversi ketergantungan. Baik kelas dan klien mana pun bergantung pada antarmuka, dan tidak tahu tentang detail implementasi. Apakah itu menjelaskan?
Vinai
Terima kasih atas jawabannya, saya mengerti maksud Anda. Masalahnya setData adalah metode publik oleh karena itu saya tidak yakin apakah itu dapat dianggap sebagai detail implementasi. Jika itu dimaksudkan untuk digunakan seperti metode publik, bagaimana kita bisa yakin bahwa itu tidak akan merusak apa pun eksternal ketika diubah?
LDusan
3
Saya minta maaf. Apa yang Anda gambarkan adalah sudut pandang yang sama. Mekanisme dependensi tidak intuitif dan karena PHP memungkinkan pemanggilan metode yang bukan bagian dari ketergantungan pada antarmuka, dan juga karena itu tidak perlu dikompilasi, itu membuat cara dependensi bekerja lebih buram dan sulit dilihat dengan jelas. . Itu juga dapat diamati pada inti Magento 2, di mana ada banyak tempat di mana metode implementasi disebut yang bukan bagian dari ketergantungan pada antarmuka. Ini berfungsi sebagai contoh buruk dan membuatnya lebih sulit untuk mendapatkan pemahaman yang jelas dan sehat.
Vinai
35

@Raphael di Digital Pianism:

Silakan merujuk ke struktur modul sampel berikut:

app/
   code/
  |    Namespace/
  |   |    Custom/
  |   |   |    Api/
  |   |   |   |    CustomRepositoryInterface.php
  |   |   |   |    Data/
  |   |   |   |   |    CustomInterface.php
  |   |   |   |   |    CustomSearchResultsInterface.php
  |   |   |    etc/
  |   |   |   |    di.xml
  |   |   |   |    module.xml
  |   |   |    Model/
  |   |   |   |    Custom.php
  |   |   |   |    CustomRepository.php
  |   |   |   |    ResourceModel/
  |   |   |   |   |    Custom.php
  1. Buat antarmuka repositori (Kontrak Layanan)
    Namespace/Custom/Api/CustomRepositoryInterface.php: http://codepad.org/WognSKnH

  2. Buat SearchResultsInterface
    Namespace/Custom/Api/Data/CustomSearchResultsInterface.php: http://codepad.org/zcbi8X4Z

  3. Buat CustomInterface (Wadah Data)
    Namespace/Custom/Api/Data/CustomInterface.php: http://codepad.org/Ze53eT4o

  4. Buat CustomRepository (Concrete Repository)
    Namespace/Custom/Model/CustomRepository.php: http://codepad.org/KNt5QAGZ
    Di sinilah "keajaiban" terjadi. Melalui konstruktor DI, Anda memasukkan model sumber daya / pabrik pengumpulan untuk modul khusus Anda; Mengenai metode simpan CRUD dalam Repositori ini, karena CustomRepositoryInterface Anda, Anda harus mengirimkan parameter CustomInterface. Di.xml modul Anda memiliki preferensi untuk mengganti antarmuka jenis ini dengan model entitas. Model entitas diteruskan ke Model Sumber Daya dan disimpan.

  5. Atur preferensi di
    Namespace/Custom/etc/di.xml: http://codepad.org/KmcoOUeV

  6. Model entitas yang mengimplementasikan Custom Interface (Data Container)
    Namespace/Custom/Model/Custom.php: http://codepad.org/xQiBU7p7 .

  7. Model sumber daya
    Namespace/Custom/Model/ResourceModel/Custom.php: http://codepad.org/IOsxm9qW

Beberapa hal yang perlu diperhatikan:

  • Penolakan!!! Saya menggunakan "Namespace" sebagai ganti nama vendor kustom Anda, nama agensi, dll ... nama apa pun yang Anda gunakan untuk mengelompokkan modul-modul Anda bersama-sama ... penggunaan sebenarnya dari "Namespace" sepenuhnya tidak valid di Php ... jadi ketahui bahwa saya melakukan ini demi kenyamanan, dan bahwa saya tidak berpikir ini akan bekerja, saya juga tidak menyarankan itu dengan cara apapun.

  • @Ryan Street mengajari saya ini ... jadi saya tidak ingin mengambil semua pujian

  • Ubah implementasi Repositori sesuai dengan kebutuhan Anda

  • Anda menerapkan interaksi dengan model entitas kustom / model sumber daya / koleksi di Repositori konkret ...

  • Saya tahu saya tidak membahas semua metode yang Anda cantumkan dalam pertanyaan Anda, tetapi ini merupakan awal yang baik dan harus menjembatani kesenjangan antara dokumen dan implementasi aktual.

ryanF
sumber
Ryan, apakah metode yang disebutkan dalam Kontrak Layanan wajib untuk setiap api sabun kustom yang kami buat, yaitu save (), delete () dll?
Sushivam
Bisakah Anda memberi saya ide tentang cara membuat api sabun kustom di magento 2?
Sushivam
@SachinS Sayangnya, saya tidak memiliki wawasan untuk menawarkan tentang SOAP. Saya belum melihatnya, saya juga belum mengimplementasikannya. Yang terbaik yang bisa saya sarankan adalah membuka pertanyaan baru di sini tentang itu. Saya akan mengatakan periksa dokumen juga, tapi sayangnya itu tidak selalu tindakan terbaik (mereka mungkin kurang). Anda selalu dapat melihat basis kode inti atau ekstensi pihak ke-3, dan melihat apakah ada wawasan di sana. Semoga berhasil! Jika Anda menemukan jawaban Anda, mungkin lebih baik menambahkan tautan di sini. Terima kasih
ryanF
Terima kasih atas balasannya @ryan, lagipula saya menerapkan modul saya menggunakan REST, karena bobotnya yang ringan dibandingkan dengan SOAP ... Jika saya menerapkan hal yang sama dalam SOAP, sakit posting itu
Sushivam
3
@ryanF Terima kasih atas jawaban yang sangat berguna ini. Saya tahu ini tidak seharusnya menjadi copy / paste kode kerja tetapi di sini ada beberapa kesalahan ketik untuk kepentingan orang lain. Dalam repositori, CustomSearchResultsInterfaceFactory harus CustomSearchResultsFactory. $ searchResults-> setCriteria seharusnya $ searchResults-> setSearchCriteria. $ Bea Cukai [] dalam foreach harus $ bea cukai []. Saya pikir itu saja.
tetranz
3

menyelesaikan file menggunakan kontrak layanan

Kustom / Modul / registrasi.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Custom_Module',
    __DIR__
);

../etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Custom_Module" setup_version="1.0.0" />
</config>

../Setup/InstallSchema.php

<?php
namespace Custom\Module\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;
class InstallSchema implements InstallSchemaInterface {
    public function install( SchemaSetupInterface $setup, ModuleContextInterface $context ) {
        $installer = $setup;
        $installer->startSetup();
        $table = $installer->getConnection()->newTable(
            $installer->getTable( 'ad_shipping_quote' )
        )->addColumn(
            'entity_id',
            Table::TYPE_SMALLINT,
            null,
            [ 'identity' => true, 'nullable' => false, 'primary' => true ],
            'Post ID'
        )->addColumn(
            'product_id',
            Table::TYPE_SMALLINT,
            255,
            [ ],
            'Post ID'
        )
            ->addColumn(
            'customer_name',
            Table::TYPE_TEXT,
            255,
            [ 'nullable' => false ],
            'Post Title'
        )

            ->addColumn(
            'customer_email',
            Table::TYPE_TEXT,
            '2M',
            [ ],
            'Post Content'
        ) ->addColumn(
                'customer_comments',
                Table::TYPE_TEXT,
                255,
                [ 'nullable' => false ],
                'Post Title'
            )->addColumn(
                'date_added',
                Table::TYPE_TEXT,
                255,
                [ 'nullable' => false ],
                'Post Title'
            )->addColumn(
                'date_updated',
                Table::TYPE_TEXT,
                255,
                [ 'nullable' => false ],
                'Post Title'
            )
            ->setComment(
            'Ad Shipping Quote Table'
        );
        $installer->getConnection()->createTable( $table );
        $installer->endSetup();
    }
}

../etc/di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Custom\Module\Api\ModelRepositoryInterface"
                type="Custom\Module\Model\ModelRepository" />
    <preference for="Custom\Module\Api\Data\ModelInterface"
                type="Custom\Module\Model\Model" />
    <preference for="Custom\Module\Api\Data\ModelSearchResultsInterface"
                type="Custom\Module\Model\ModelSearchResults" />
</config>

../etc/webapi.xml

  <?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">

    <route method="GET" url="/V1/model/:id">
        <service class="Custom\Module\Api\ModelRepositoryInterface" method="getById"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>


    <route method="GET" url="/V1/model">
        <service class="Custom\Module\Api\ModelRepositoryInterface" method="getList"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
</routes>

../Api/ModelRepositoryInterface.php

  <?php
namespace Custom\Module\Api;

use \Custom\Module\Api\Data\ModelInterface;
use \Magento\Framework\Api\SearchCriteriaInterface;

interface ModelRepositoryInterface
{
    /**
     * @api
     * @param \Custom\Module\Api\Data\ModelInterface $model
     * @return \Custom\Module\Api\Data\ModelInterface
     */
    public function save(ModelInterface $model);

    /**
     * @api
     * @param \Custom\Module\Api\Data\ModelInterface $model
     * @return \Custom\Module\Api\Data\ModelInterface
     */
    public function delete(ModelInterface $model);

    /**
     * @api
     * @param \Custom\Module\Api\Data\ModelInterface $id
     * @return void
     */
    public function deleteById($id);

    /**
     * @api
     * @param int $id
     * @return \Custom\Module\Api\Data\ModelInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getById($id);

    /**
     * @api
     * @param \Magento\Framework\Api\SearchCriteriaInterface $criteria
     * @return \Custom\Module\Api\Data\ModelSearchResultsInterface
     */
    public function getList(SearchCriteriaInterface $criteria);
}

../Api/Data/ModelInterface.php

<?php
namespace Custom\Module\Api\Data;

interface ModelInterface
{
    /**
     * Return the Entity ID
     *
     * @return int
     */
    public function getEntityId();

    /**
     * Set Entity ID
     *
     * @param int $id
     * @return $this
     */
    public function setEntityId($id);

    /**
     * Return the Product ID associated with Quote
     *
     * @return int
     */
    public function getProductId();

    /**
     * Set the Product ID associated with Quote
     *
     * @param int $productId
     * @return $this
     */
    public function setProductId($productId);

    /**
     * Return the Customer Name
     *
     * @return string
     */
    public function getCustomerName();

    /**
     * Set the Customer Name
     *
     * @param string $customerName
     * @return $this
     */
    public function setCustomerName($customerName);

    /**
     * Return the Customer Email
     *
     * @return string
     */
    public function getCustomerEmail();

    /**
     * Set the Customer Email
     *
     * @param string $customerEmail
     * @return $this
     */
    public function setCustomerEmail($customerEmail);

    /**
     * Return the Customer Comments
     *
     * @return string
     */
    public function getCustomerComments();

    /**
     * Set the Customer Comments
     *
     * @param string $customerComments
     * @return $this
     */
    public function setCustomerComments($customerComments);

    /**
     * Return the Date and Time of record added
     *
     * @return string
     */
    public function getDateAdded();

    /**
     * Set the Date and Time of record added
     *
     * @param string $date
     * @return $this
     */
    public function setDateAdded($date);

    /**
     * Return the Date and Time of record updated
     *
     * @return string
     */
    public function getDateUpdated();

    /**
     * Set the Date and Time of record updated
     *
     * @param string $date
     * @return $this
     */
    public function setDateUpdated($date);
}

..Api / Data / ModelSearchResultsInterface.php

<?php

namespace Custom\Module\Api\Data;

use Magento\Framework\Api\SearchResultsInterface;

interface ModelSearchResultsInterface extends SearchResultsInterface
{
    /**
     * @return \Custom\Module\Api\Data\ModelInterface[]
     */
    public function getItems();

    /**
     * @param \Custom\Module\Api\Data\ModelInterface[] $items
     * @return $this
     */
    public function setItems(array $items);
}

../Model/Model.php

    <?php

namespace Custom\Module\Model;

use Custom\Module\Api\Data\ModelInterface;

class Model extends \Magento\Framework\Model\AbstractModel implements
    \Custom\Module\Api\Data\ModelInterface
{
    protected function _construct()
    {
        $this->_init('Custom\Module\Model\ResourceModel\Model');
    }

    /**
     * @inheritdoc
     */
    public function getEntityId()
    {
        return $this->_getData('entity_id');
    }

    /**
     * @inheritdoc
     */
    public function setEntityId($id)
    {
        $this->setData('entity_id', $id);
    }

    /**
     * @inheritdoc
     */
    public function getProductId()
    {
        return $this->_getData('product_id');
    }

    /**
     * @inheritdoc
     */
    public function setProductId($productId)
    {
        $this->setData('product_id', $productId);
    }

    /**
     * @inheritdoc
     */
    public function getCustomerName()
    {
        return $this->_getData('customer_name');
    }

    /**
     * @inheritdoc
     */
    public function setCustomerName($customerName)
    {
        $this->setData('customer_name', $customerName);
    }

    /**
     * @inheritdoc
     */
    public function getCustomerEmail()
    {
        return $this->_getData('customer_email');
    }

    /**
     * @inheritdoc
     */
    public function setCustomerEmail($customerEmail)
    {
        $this->setData('customer_email', $customerEmail);
    }

    /**
     * @inheritdoc
     */
    public function getCustomerComments()
    {
        return $this->_getData('customer_comments');
    }

    /**
     * @inheritdoc
     */
    public function setCustomerComments($customerComments)
    {
        $this->setData('customer_comments', $customerComments);
    }

    /**
     * @inheritdoc
     */
    public function getDateAdded()
    {
        return $this->_getData('date_added');
    }

    /**
     * @inheritdoc
     */
    public function setDateAdded($date)
    {
        $this->setData('date_added', $date);
    }

    /**
     * @inheritdoc
     */
    public function getDateUpdated()
    {
        return $this->_getData('date_updated');
    }

    /**
     * @inheritdoc
     */
    public function setDateUpdated($date)
    {
        $this->setData('date_updated', $date);
    }
}

../Model/ResourceModel/Model.php

<?php

namespace Custom\Module\Model\ResourceModel;

class Model extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
    protected $_idFieldName = 'entity_id';

    protected function _construct()
    {
        $this->_init('ad_shipping_quote','entity_id');
    }
}

../Model/ResourceModel/Model/Collection.php

<?php

namespace Custom\Module\Model\ResourceModel\Model;

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
    protected $_idFieldName = 'entity_id';
    protected $_eventPrefix = 'ad_shipping_quote_collection';
    protected $_eventObject = 'quote_collection';

    protected function _construct()
    {
        $this->_init('Custom\Module\Model\Model', 'Custom\Module\Model\ResourceModel\Model');
    }
}

../Model/ModelRepository.php

 <?php
    namespace Custom\Module\Model;

    use \Custom\Module\Api\Data\ModelInterface;
    use \Custom\Module\Model\ResourceModel\Model as ObjectResourceModel;
    use \Magento\Framework\Api\SearchCriteriaInterface;
    use \Magento\Framework\Exception\CouldNotSaveException;
    use \Magento\Framework\Exception\NoSuchEntityException;
    use \Magento\Framework\Exception\CouldNotDeleteException;

    class ModelRepository implements \Custom\Module\Api\ModelRepositoryInterface
    {
        protected $objectFactory;

        protected $objectResourceModel;

        protected $collectionFactory;

        protected $searchResultsFactory;

        public function __construct(
            \Custom\Module\Model\ModelFactory $objectFactory,
            ObjectResourceModel $objectResourceModel,
            \Custom\Module\Model\ResourceModel\Model\CollectionFactory $collectionFactory,
            \Magento\Framework\Api\SearchResultsInterfaceFactory $searchResultsFactory
        ) {
            $this->objectFactory        = $objectFactory;
            $this->objectResourceModel  = $objectResourceModel;
            $this->collectionFactory    = $collectionFactory;
            $this->searchResultsFactory = $searchResultsFactory;
        }

        public function save(ModelInterface $object)
        {
            $name = $object->getCustomerName();
            $hasSpouse = $object->getSpouse();
            if ($hasSpouse == true) {
                $name = "Mrs. " . $name;
            } else {
                $name = "Miss. " . $name;
            }
            $object->setCustomerName($name);
            try {
                $this->objectResourceModel->save($object);
            } catch (\Exception $e) {
                throw new CouldNotSaveException(__($e->getMessage()));
            }
            return $object;
        }

        /**
         * @inheritdoc
         */
        public function getById($id)
        {
            $object = $this->objectFactory->create();
            $this->objectResourceModel->load($object, $id);
            if (!$object->getId()) {
                throw new NoSuchEntityException(__('Object with id "%1" does not exist.', $id));
            }
            return $object;
        }

        public function delete(ModelInterface $object)
        {
            try {
                $this->objectResourceModel->delete($object);
            } catch (\Exception $exception) {
                throw new CouldNotDeleteException(__($exception->getMessage()));
            }
            return true;
        }

        public function deleteById($id)
        {
            return $this->delete($this->getById($id));
        }

        /**
         * @inheritdoc
         */
        public function getList(SearchCriteriaInterface $criteria)
        {
            $searchResults = $this->searchResultsFactory->create();
            $searchResults->setSearchCriteria($criteria);
            $collection = $this->collectionFactory->create();
            foreach ($criteria->getFilterGroups() as $filterGroup) {
                $fields = [];
                $conditions = [];
                foreach ($filterGroup->getFilters() as $filter) {
                    $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq';
                    $fields[] = $filter->getField();
                    $conditions[] = [$condition => $filter->getValue()];
                }
                if ($fields) {
                    $collection->addFieldToFilter($fields, $conditions);
                }
            }
            $searchResults->setTotalCount($collection->getSize());
            $sortOrders = $criteria->getSortOrders();
            if ($sortOrders) {
                /** @var SortOrder $sortOrder */
                foreach ($sortOrders as $sortOrder) {
                    $collection->addOrder(
                        $sortOrder->getField(),
                        ($sortOrder->getDirection() == SortOrder::SORT_ASC) ? 'ASC' : 'DESC'
                    );
                }
            }
            $collection->setCurPage($criteria->getCurrentPage());
            $collection->setPageSize($criteria->getPageSize());
            $objects = [];
            foreach ($collection as $objectModel) {
                $objects[] = $objectModel;
            }
            $searchResults->setItems($objects);
            return $searchResults;
        }
    }

../Model/ModelSearchResults.php

namespace Custom\Module\Model;

use \Magento\Framework\Api\SearchResults;
use \Custom\Module\Api\Data\ModelSearchResultsInterface;


class ModelSearchResults extends SearchResults implements ModelSearchResultsInterface
{

}

../Controller/Index/Save.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Save extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelFactory;
    /**
     * @var
     */
    private $modelRepository;


    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelFactory $modelFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelFactory $modelFactory,
        \Custom\Module\Model\ModelRepository $modelRepository
) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelFactory = $modelFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);


    }

    /**
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $data = [

            "product_id" => 201,
            "customer_name" => "Katrina",
            "customer_email" => "[email protected]",
            "spouse" => 1
        ];

        $obj = $this->modelFactory->create();
        $this->modelRepository->save($obj->addData($data)); // Service Contract


        //$obj->addData($data)->save(); // Model / Resource Model

        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Getlist.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Getlist extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelFactory;
    /**
     * @var
     */
    private $modelRepository;
    /**
     * @var
     */
    private $searchCriteriaBuilder;


    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelRepository $modelRepository,
        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelRepository = $modelRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        return parent::__construct($context);
    }

    /**
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $_filter = $this->searchCriteriaBuilder
            ->addFilter("customer_name", "%na%", "like")->create();
        $list = $this->modelRepository->getList($_filter);
        $results = $list->getItems();
        foreach ($results as $result) {
            echo $result->getCustomerName() . "<br>";
        }




        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Getbyid.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Getbyid extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelRepository;

    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelRepository $modelRepository

) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);
    }

    public function execute()
    {

        $search = $this->modelRepository->getById(1);
        print_r($search->getData());

        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Deletebyid.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Deletbyid extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelRepository;

    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelRepository $modelRepository

) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);
    }

    public function execute()
    {

        $this->modelRepository->deleteById(1);

        $this->resultFactory->create("raw");
    }
}

../Controller/Index/Del.php

<?php

namespace Custom\Module\Controller\Index;

use \Magento\Framework\Controller\Result\RawFactory;

class Del extends \Magento\Framework\App\Action\Action
{

    /**
     * Index resultPageFactory
     * @var PageFactory
     */
    private $resultPageFactory;
    /**
     * @var
     */
    private $modelRepository;

    /**
     * Index constructor.
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Custom\Module\Model\ModelFactory $modelFactory
     * @param \Custom\Module\Model\ModelRepository $modelRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Custom\Module\Model\ModelFactory $modelFactory,
        \Custom\Module\Model\ModelRepository $modelRepository

) {
        $this->resultPageFactory = $resultPageFactory;
        $this->modelFactory = $modelFactory;
        $this->modelRepository = $modelRepository;
        return parent::__construct($context);
    }

    public function execute()
    {
        $obj = $this->modelFactory->create()->load(2);
         $this->modelRepository->delete($obj);

        $this->resultFactory->create("raw");
    }
}
Asad Ullah
sumber