Làm cách nào để triển khai hợp đồng dịch vụ cho một mô-đun tùy chỉnh trong Magento 2?


42

Như đã thấy trong bài viết này: Deprecated lưu và phương pháp tải trong Tóm tắt mẫu các saveloadphương pháp được tán thành trong Magento 2 phát triển chi nhánh.

Vì vậy, thực tế tốt hiện nay là thực hiện các hợp đồng dịch vụ để đối phó với các thực thể CRUD.

Quy trình từng bước tôi cần tuân theo để thực hiện các hợp đồng dịch vụ cho các thực thể mô-đun tùy chỉnh của mình là gì?

Lưu ý: Tôi biết có thể có hàng ngàn phương thức trong các mô hình CRUD của mình, tôi chỉ yêu cầu các phương thức rõ ràng như đã nêu ở đây: http://devdocs.magento.com/guides/v2.0/extension-dev-guide /service-contuces/design-potypes.html :

  • get
  • save
  • getList
  • delete
  • deleteById

Câu trả lời:


89

Tôi muốn cung cấp thêm một chút chi tiết bên cạnh câu trả lời xuất sắc của @ryanF.

Tôi muốn tổng hợp các lý do để thêm kho lưu trữ cho các thực thể tùy chỉnh, đưa ra ví dụ về cách thực hiện và cũng giải thích cách hiển thị các phương thức lưu trữ đó như một phần của API Web.

Tuyên bố miễn trừ trách nhiệm: Tôi chỉ mô tả một cách tiếp cận thực tế về cách thực hiện điều này cho các mô-đun của bên thứ ba - các nhóm cốt lõi có các tiêu chuẩn riêng mà họ tuân theo (hoặc không).

Nói chung, mục đích của một kho lưu trữ là để ẩn logic liên quan đến lưu trữ.
Một khách hàng của kho lưu trữ không nên quan tâm liệu thực thể được trả về có được giữ trong bộ nhớ trong một mảng hay không, được truy xuất từ ​​cơ sở dữ liệu MySQL, được tìm nạp từ API từ xa hoặc từ tệp.
Tôi cho rằng nhóm nòng cốt Magento đã làm điều này để họ có thể thay đổi hoặc thay thế ORM trong tương lai. Trong Magento, ORM hiện bao gồm các Mô hình, Mô hình tài nguyên và Bộ sưu tập.
Nếu một mô-đun bên thứ ba chỉ sử dụng các kho lưu trữ, Magento có thể thay đổi cách thức và nơi lưu trữ dữ liệu và mô-đun sẽ tiếp tục hoạt động, bất chấp những thay đổi sâu sắc này.

Kho thường có các phương pháp như findById(), findByName(), put()hoặc remove().
Trong Magento những thường được gọi là getbyId(), save()delete(), thậm chí không giả vờ họ đang làm bất cứ điều gì khác ngoài hoạt động CRUD DB.

Các phương thức kho lưu trữ Magento 2 có thể dễ dàng được hiển thị dưới dạng tài nguyên API, làm cho chúng có giá trị để tích hợp với các hệ thống bên thứ ba hoặc các phiên bản Magento không đầu.

"Tôi có nên thêm một kho lưu trữ cho thực thể tùy chỉnh của mình không?".

Như mọi khi, câu trả lời là

"Nó phụ thuộc".

Để làm cho một câu chuyện dài ngắn, nếu các thực thể của bạn sẽ được sử dụng bởi các mô-đun khác, thì có, bạn có thể muốn thêm một kho lưu trữ.

Có một yếu tố khác được tính đến ở đây: trong Magento 2, các kho lưu trữ có thể dễ dàng được hiển thị dưới dạng API Web - đó là REST và SOAP - tài nguyên.

Nếu điều đó thú vị với bạn vì tích hợp hệ thống của bên thứ ba hoặc thiết lập Magento không đầu, thì một lần nữa, vâng, có lẽ bạn muốn thêm một kho lưu trữ cho thực thể của mình.

Làm cách nào để thêm kho lưu trữ cho thực thể tùy chỉnh của tôi?

Giả sử bạn muốn trưng bày thực thể của mình như một phần của API REST. Nếu điều đó không đúng, bạn có thể bỏ qua phần sắp tới để tạo giao diện và đi thẳng đến "Tạo kho lưu trữ và triển khai mô hình dữ liệu" bên dưới.

Tạo kho lưu trữ và giao diện mô hình dữ liệu

Tạo các thư mục Api/Data/trong mô-đun của bạn. Đây chỉ là quy ước, bạn có thể sử dụng một vị trí khác, nhưng bạn không nên.
Các kho lưu trữ đi vào Api/thư mục. Thư Data/mục con là để sau.

Trong Api/, tạo một giao diện PHP với các phương thức bạn muốn trưng ra. Theo quy ước Magento 2, tất cả các tên giao diện đều kết thúc bằng hậu tố Interface.
Ví dụ, đối với một Hamburgerthực thể, tôi sẽ tạo giao diện Api/HamburgerRepositoryInterface.

Tạo giao diện kho lưu trữ

Kho lưu trữ Magento 2 là một phần của logic miền của mô-đun. Điều đó có nghĩa là, không có bộ phương thức cố định nào mà kho lưu trữ phải thực hiện.
Nó phụ thuộc hoàn toàn vào mục đích của mô-đun.

Tuy nhiên, trong thực tế tất cả các kho lưu trữ đều khá giống nhau. Chúng là các hàm bao cho chức năng CRUD.
Hầu hết có những phương pháp getById, save, deletegetList.
Có thể có nhiều hơn, ví dụ như CustomerRepositorycó một phương thức get, tìm nạp khách hàng qua email, theo đó getByIdđược sử dụng để truy xuất một khách hàng bằng ID thực thể.

Dưới đây là một giao diện kho lưu trữ ví dụ cho một thực thể 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);

}

Quan trọng! Đây là khoảng thời gian!
Có một vài vấn đề khó giải quyết ở đây nếu bạn hiểu sai:

  1. KHÔNG sử dụng các kiểu đối số vô hướng PHP7 hoặc các kiểu trả về nếu bạn muốn nối cái này vào API REST!
  2. Thêm các chú thích PHPDoc cho tất cả các đối số và kiểu trả về cho tất cả các phương thức!
  3. Sử dụng Tên lớp đủ điều kiện trong khối PHPDoc!

Các chú thích được phân tích cú pháp bởi Khung Magento để xác định cách chuyển đổi dữ liệu sang và từ JSON hoặc XML. Nhập khẩu lớp (có nghĩa là, usebáo cáo) không được áp dụng!

Mọi phương thức phải có một chú thích với bất kỳ kiểu đối số và kiểu trả về. Ngay cả khi một phương thức không có đối số và không trả về gì, thì nó phải có chú thích:

/**
 * @return void
 */

Loại vô hướng ( string, int, floatbool) cũng phải được chỉ định, cả hai cho các đối số và như là một giá trị trả về.

Lưu ý rằng trong ví dụ trên, các chú thích cho các phương thức trả về các đối tượng cũng được chỉ định làm giao diện.
Các giao diện loại trả về là tất cả trong Api\Datakhông gian tên / thư mục.
Điều này là để chỉ ra rằng chúng không chứa bất kỳ logic kinh doanh nào. Chúng chỉ đơn giản là túi dữ liệu.
Chúng ta phải tạo ra các giao diện tiếp theo.

Tạo giao diện DTO

Tôi nghĩ Magento gọi các giao diện này là "mô hình dữ liệu", một cái tên tôi không thích chút nào.
Loại lớp này thường được gọi là Đối tượng truyền dữ liệu hoặc DTO .
Các lớp DTO này chỉ có getters và setters cho tất cả các thuộc tính của chúng.

Lý do tôi thích sử dụng DTO hơn mô hình dữ liệu là vì nó ít dễ nhầm lẫn với các mô hình dữ liệu ORM, mô hình tài nguyên hoặc mô hình xem ... quá nhiều thứ đã là mô hình trong Magento.

Các hạn chế tương tự liên quan đến việc gõ PHP7 áp dụng cho các kho lưu trữ cũng áp dụng cho các DTO.
Ngoài ra, mọi phương thức đều phải có chú thích với tất cả các kiểu đối số và kiểu trả về.

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

Nếu một phương thức truy xuất hoặc trả về một mảng, loại các mục trong mảng phải được chỉ định trong chú thích PHPDoc, theo sau là một dấu ngoặc vuông mở và đóng [].
Điều này đúng cho cả các giá trị vô hướng (ví dụ int[]) cũng như các đối tượng (ví dụ IngredientInterface[]).

Lưu ý rằng tôi đang sử dụng Api\Data\IngredientInterfacelàm ví dụ cho một phương thức trả về một mảng các đối tượng, tôi sẽ không thêm mã thành phần vào bài đăng này.

ExtensibleDataInterface?

Trong ví dụ trên, phần HamburgerInterfacemở rộng ExtensibleDataInterface.
Về mặt kỹ thuật, điều này chỉ được yêu cầu nếu bạn muốn các mô-đun khác có thể thêm thuộc tính vào thực thể của mình.
Nếu vậy, bạn cũng cần thêm một cặp getter / setter khác, theo quy ước được gọi getExtensionAttributes()setExtensionAttributes().

Việc đặt tên kiểu trả về của phương thức này rất quan trọng!

Khung công tác Magento 2 sẽ tạo ra giao diện, cách triển khai và nhà máy để thực hiện nếu bạn đặt tên cho chúng vừa phải. Các chi tiết của các cơ chế này nằm ngoài phạm vi của bài này mặc dù.
Chỉ cần biết, nếu giao diện của đối tượng bạn muốn mở rộng được gọi \VinaiKopp\Kitchen\Api\Data\HamburgerInterface, thì loại thuộc tính mở rộng phải có \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface. Vì vậy, từ Extensionphải được chèn sau tên thực thể, ngay trước Interfacehậu tố.

Nếu bạn không muốn thực thể của mình có thể mở rộng, thì giao diện DTO không phải mở rộng bất kỳ giao diện nào khác và các phương thức getExtensionAttributes()setExtensionAttributes()có thể được bỏ qua.

Bây giờ đủ về giao diện DTO, đã đến lúc quay lại giao diện kho lưu trữ.

Kiểu trả về getList () SearchResults

Phương thức kho lưu trữ getListtrả về một kiểu khác, đó là một SearchResultsInterfacethể hiện.

Phương thức getListtất nhiên có thể chỉ trả về một mảng các đối tượng khớp với chỉ định SearchCriteria, nhưng trả về một SearchResultsthể hiện cho phép thêm một số dữ liệu meta hữu ích vào các giá trị được trả về.

Bạn có thể thấy cách hoạt động bên dưới trong getList()triển khai phương thức kho lưu trữ .

Dưới đây là ví dụ về giao diện kết quả tìm kiếm 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);
}

Tất cả giao diện này làm là ghi đè các loại cho hai phương thức getItems()setItems()giao diện cha.

Tóm tắt các giao diện

Bây giờ chúng ta có các giao diện sau:

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

Kho kéo dài không có gì,
các HamburgerInterfacemở rộng \Magento\Framework\Api\ExtensibleDataInterface,
HamburgerSearchResultInterfacemở rộng \Magento\Framework\Api\SearchResultsInterface.

Tạo kho lưu trữ và triển khai mô hình dữ liệu

Bước tiếp theo là tạo ra các triển khai của ba giao diện.

Kho lưu trữ

Về bản chất, kho lưu trữ sử dụng ORM để thực hiện công việc của nó.

Các getById(), save()delete()phương pháp là khá thẳng về phía trước.
HamburgerFactoryđược đưa vào kho lưu trữ dưới dạng đối số của hàm tạo, như có thể thấy thêm một chút bên dưới.

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

Bây giờ đến phần thú vị nhất của một kho lưu trữ, getList()phương thức.
Các getList()phương pháp có để dịch các SerachCriteriađiều kiện vào các cuộc gọi phương pháp trên bộ sưu tập.

Phần khó khăn của điều đó là làm cho các điều kiện ANDORđiều kiện cho các bộ lọc trở nên đúng, đặc biệt vì cú pháp đặt các điều kiện trên bộ sưu tập là khác nhau tùy thuộc vào việc đó là EAV hay thực thể bảng phẳng.

Trong hầu hết các trường hợp, getList()có thể được thực hiện như được minh họa trong ví dụ dưới đây.

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

Các bộ lọc trong một FilterGroupphải được kết hợp bằng toán tử OR .
Các nhóm bộ lọc riêng biệt được kết hợp bằng toán tử AND logic .

Phew
Đây là phần lớn nhất của công việc. Các triển khai giao diện khác đơn giản hơn.

DTO

Magento ban đầu dự định các nhà phát triển triển khai DTO dưới dạng các lớp riêng biệt, khác biệt với mô hình thực thể.

Nhóm nòng cốt chỉ làm điều này cho mô đun khách hàng mặc dù ( \Magento\Customer\Api\Data\CustomerInterfaceđược thực hiện bởi \Magento\Customer\Model\Data\Customer, không phải \Magento\Customer\Model\Customer).
Trong tất cả các trường hợp khác, mô hình thực thể thực hiện giao diện DTO (ví dụ \Magento\Catalog\Api\Data\ProductInterfaceđược triển khai bởi \Magento\Catalog\Model\Product).

Tôi đã hỏi các thành viên của nhóm nòng cốt về vấn đề này tại các hội nghị, nhưng tôi không nhận được phản hồi rõ ràng về những gì được coi là thực hành tốt.
Ấn tượng của tôi là khuyến nghị này đã bị bỏ rơi. Nó sẽ là tốt đẹp để có được một tuyên bố chính thức về điều này mặc dù.

Hiện tại tôi đã đưa ra quyết định thực tế khi sử dụng mô hình làm triển khai giao diện DTO. Nếu bạn cảm thấy sạch hơn khi sử dụng một mô hình dữ liệu riêng biệt, hãy thoải mái làm điều đó. Cả hai phương pháp đều hoạt động tốt trong thực tế.

Nếu phần tử DTO mở rộng Magento\Framework\Api\ExtensibleDataInterface, mô hình phải mở rộng Magento\Framework\Model\AbstractExtensibleModel.
Nếu bạn không quan tâm đến khả năng mở rộng, mô hình có thể chỉ cần tiếp tục mở rộng lớp cơ sở mô hình ORM Magento\Framework\Model\AbstractModel.

Vì ví dụ HamburgerInterfacemở rộng ExtensibleDataInterfacemô hình bánh hamburger mở rộng AbstractExtensibleModel, như có thể thấy ở đây:

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

Trích xuất tên tài sản vào hằng số cho phép giữ chúng ở một nơi. Chúng có thể được sử dụng bởi cặp getter / setter và cũng bởi tập lệnh Setup tạo bảng cơ sở dữ liệu. Mặt khác, không có lợi ích trong việc trích xuất chúng vào hằng số.

SearchResult

Đây SearchResultsInterfacelà cách đơn giản nhất trong ba giao diện để thực hiện, vì nó có thể kế thừa tất cả các chức năng của nó từ một lớp khung.

<?php

namespace VinaiKopp\Kitchen\Model;

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

class HamburgerSearchResult extends SearchResults implements HamburgerSearchResultInterface
{

}

Định cấu hình tùy chọn ObjectManager

Mặc dù việc triển khai đã hoàn tất, chúng ta vẫn không thể sử dụng các giao diện làm phụ thuộc của các lớp khác, vì trình quản lý đối tượng Magento Framework không biết nên sử dụng các triển khai nào. Chúng ta cần thêm một etc/di.xmlcấu hình cho các tùy chọn.

<?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>

Làm thế nào để kho lưu trữ được hiển thị dưới dạng tài nguyên API?

Phần này thực sự đơn giản, đó là phần thưởng cho việc hoàn thành tất cả các công việc tạo ra các giao diện, việc triển khai và kết nối chúng lại với nhau.

Tất cả chúng ta cần làm là tạo một etc/webapi.xmltập tin.

<?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>

Lưu ý rằng cấu hình này không chỉ cho phép sử dụng kho lưu trữ làm điểm cuối REST, nó còn hiển thị các phương thức như một phần của API SOAP.

Trong tuyến ví dụ đầu tiên <route method="GET" url="/V1/vinaikopp_hamburgers/:id">, trình giữ chỗ :idphải khớp tên của đối số với phương thức được ánh xạ , public function getById($id).
Hai tên phải khớp nhau, ví dụ /V1/vinaikopp_hamburgers/:hamburgerIdsẽ không hoạt động, vì tên biến đối số phương thức là $id.

Trong ví dụ này, tôi đã đặt khả năng truy cập <resource ref="anonymous"/>. Điều này có nghĩa là tài nguyên được phơi bày công khai mà không có bất kỳ hạn chế nào!
Để làm cho một tài nguyên chỉ có sẵn cho một khách hàng đã đăng nhập, sử dụng <resource ref="self"/>. Trong trường hợp này, từ đặc biệt metrong URL điểm cuối tài nguyên sẽ được sử dụng để điền một biến đối số $idvới ID của khách hàng hiện đang đăng nhập.
Hãy nhìn vào Khách hàng Magento etc/webapi.xmlCustomerRepositoryInterfacenếu bạn cần điều đó.

Cuối cùng, <resources>cũng có thể được sử dụng để hạn chế quyền truy cập vào tài nguyên đối với tài khoản người dùng quản trị viên. Để làm điều này, đặt <resource>ref cho một định danh được xác định trong một etc/acl.xmltệp.
Ví dụ: <resource ref="Magento_Customer::manage"/>sẽ hạn chế quyền truy cập vào bất kỳ tài khoản quản trị viên nào có đặc quyền quản lý khách hàng.

Một truy vấn API ví dụ sử dụng curl có thể trông như thế này:

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

Lưu ý: viết bài này bắt đầu như một câu trả lời cho https://github.com/astorm/pestle/issues/195
Kiểm tra chày , mua Commercebug và trở thành một patreon của @alanstorm


1
Cảm ơn câu trả lời tuyệt vời này. Xin lỗi có thể tôi đang thiếu một cái gì đó, nhưng điểm quan trọng của việc có một giao diện sạch cho một thực thể là gì khi cuối cùng nó phải mở rộng từ AbstractModel có phương thức setData có nghĩa là bạn có thể thêm bất cứ thứ gì vào đối tượng bất kể giao diện là gì?
LDusan

Một lớp có thể thực hiện bất kỳ số lượng giao diện và thêm các phương thức bổ sung. Điều quan trọng là bất kỳ lớp nào khác chỉ phụ thuộc vào các phương thức giao diện và do đó không biết về bất kỳ lớp nào khác. Điều đó làm cho các chi tiết triển khai phương thức phi giao diện, có thể được thay đổi bất cứ lúc nào mà không phá vỡ các lớp bên ngoài. Đó là ý tưởng đằng sau sự đảo ngược phụ thuộc. Cả lớp và bất kỳ máy khách nào đều phụ thuộc vào giao diện và không biết về chi tiết triển khai. Điều đó có làm rõ không?
Vinai

Cảm ơn câu trả lời, tôi hiểu ý của bạn. Vấn đề là setData là một phương thức công khai, do đó tôi không chắc liệu nó có thể được coi là chi tiết triển khai hay không. Nếu nó được sử dụng như phương thức công cộng, làm sao chúng ta có thể chắc chắn rằng nó sẽ không phá vỡ bất cứ thứ gì bên ngoài khi thay đổi?
LDusan

3
Tôi xin lỗi. Những gì bạn đang mô tả là một quan điểm phổ biến. Các cơ chế của các phụ thuộc không trực quan và vì PHP cho phép gọi các phương thức không phải là một phần của giao diện và cũng vì nó không cần phải được biên dịch, nên làm cho cách thức phụ thuộc trở nên mờ hơn và khó nhìn rõ hơn . Điều đó cũng có thể được quan sát trong lõi Magento 2, nơi có nhiều nơi mà các phương thức thực hiện được gọi mà không phải là một phần của sự phụ thuộc vào giao diện. Chúng đóng vai trò là những ví dụ tồi tệ và làm cho việc hiểu rõ hơn và rõ ràng hơn.
Vinai


35

@Raphael tại Pianism kỹ thuật số:

Vui lòng tham khảo cấu trúc mô-đun mẫu sau:

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. Tạo giao diện kho lưu trữ (Hợp đồng dịch vụ)
    Namespace/Custom/Api/CustomRepositoryInterface.php: http://codepad.org/WognSKnH

  2. Tạo SearchResultsInterface
    Namespace/Custom/Api/Data/CustomSearchResultsInterface.php: http://codepad.org/zcbi8X4Z

  3. Tạo CustomInterface (Bộ chứa dữ liệu)
    Namespace/Custom/Api/Data/CustomInterface.php: http://codepad.org/Ze53eT4o

  4. Tạo kho lưu trữ tùy chỉnh (Kho lưu trữ cụ thể)
    Namespace/Custom/Model/CustomRepository.php: http://codepad.org/KNt5QAGZ
    Đây là nơi xảy ra "phép thuật". Thông qua hàm tạo DI, bạn chuyển vào nhà máy mô hình / bộ sưu tập tài nguyên cho mô-đun tùy chỉnh của bạn; Về phương thức lưu CRUD trong Kho lưu trữ này, do CustomRep repositoryInterface của bạn, bạn phải truyền vào một tham số của CustomInterface. Di.xml mô-đun của bạn có một ưu tiên để thay thế một giao diện loại này bằng một mô hình thực thể. Mô hình thực thể được chuyển vào Mô hình tài nguyên và được lưu.

  5. Đặt tùy chọn trong
    Namespace/Custom/etc/di.xml: http://codepad.org/KmcoOUeV

  6. Mô hình thực thể Giao diện tùy chỉnh (Bộ chứa dữ liệu)
    Namespace/Custom/Model/Custom.php: http://codepad.org/xQiBU7p7 .

  7. Mô hình tài nguyên
    Namespace/Custom/Model/ResourceModel/Custom.php: http://codepad.org/IOsxm9qW

Một số điều cần lưu ý:

  • Khước từ !!! Tôi đã sử dụng "Không gian tên" thay cho tên nhà cung cấp tùy chỉnh, tên đại lý, v.v ... bất kỳ tên nào bạn sử dụng để nhóm các mô-đun của mình lại với nhau ... việc sử dụng "Không gian tên" thực sự hoàn toàn không hợp lệ trong Php ... vì vậy hãy biết rằng tôi đã làm điều này vì mục đích thuận tiện và tôi không nghĩ rằng nó sẽ hoạt động, tôi cũng không đề xuất nó theo bất kỳ cách nào.

  • @Ryan Street đã dạy tôi điều này ... vì vậy tôi không muốn nhận tất cả tín dụng

  • Thay đổi rõ ràng việc triển khai Kho lưu trữ cho phù hợp với nhu cầu của bạn

  • Bạn thực hiện tương tác với các mô hình thực thể / mô hình tài nguyên / bộ sưu tập tùy chỉnh của mình trong Kho lưu trữ cụ thể ...

  • Tôi biết tôi đã không giải quyết tất cả các phương pháp mà bạn đã liệt kê trong câu hỏi của bạn, nhưng đây là một khởi đầu tuyệt vời và sẽ thu hẹp khoảng cách giữa các tài liệu và triển khai thực tế.


Ryan, các phương thức được đề cập trong Hợp đồng dịch vụ có bắt buộc đối với bất kỳ api xà phòng tùy chỉnh nào mà chúng tôi tạo không, ví dụ như lưu (), xóa (), v.v.?
Sushivam

Bạn có thể vui lòng cho tôi một ý tưởng về cách tạo api xà phòng tùy chỉnh trong magento 2 không?
Sushivam

@SachinS Thật không may, tôi không có cái nhìn sâu sắc nào để cung cấp về SOAP. Tôi chưa nhìn vào nó, tôi cũng chưa thực hiện nó. Điều tốt nhất mà tôi có thể đề xuất là mở ra một câu hỏi mới ở đây liên quan đến điều đó. Tôi cũng sẽ nói rằng hãy kiểm tra các tài liệu, nhưng thật đáng buồn, đó không phải lúc nào cũng là cách hành động tốt nhất (chúng có thể thiếu). Bạn luôn có thể xem qua cơ sở mã cơ sở hoặc phần mở rộng của bên thứ 3 và xem liệu có bất kỳ thông tin chi tiết nào ở đó không. Chúc may mắn! Nếu bạn tìm thấy câu trả lời của mình, có thể tốt hơn để thêm liên kết ở đây. Cảm ơn
ryanF

Cảm ơn bạn đã trả lời @ryan, dù sao tôi cũng đã triển khai mô-đun của mình bằng REST, vì nó nhẹ hơn so với SOAP ... Nếu tôi thực hiện tương tự trong SOAP, hãy đăng nó
Sushivam

3
@ryanF Cảm ơn câu trả lời rất hữu ích này. Tôi biết rằng nó không phải là sao chép / dán mã làm việc nhưng đây là một vài lỗi chính tả cho lợi ích của những người khác theo sau. Trong kho lưu trữ, CustomSearchResultsInterfaceFactory phải là CustomSearchResultsFactory. $ searchResults-> setCriteria phải là $ searchResults-> setSearchCriteria. $ Hải quan [] trong foreach nên là $ hải quan []. Tôi nghĩ đó là về nó.
tetranz

3

hoàn thành các tập tin sử dụng hợp đồng dịch vụ

Tùy chỉnh / Mô-đun / đăng ký.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/ModelRep repositoryInterface.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 / Dữ liệu / 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/ModelRep repository.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
{

}

../Controll/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" => "karina@kapoor.com",
            "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");
    }
}

../Controll/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");
    }
}

../Controll/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");
    }
}

../Controll/Index/Deletitherid.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");
    }
}

../Controll/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");
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.