Magento 2에서 커스텀 모듈에 대한 서비스 계약을 구현하는 방법은 무엇입니까?


42

이 게시물에서 볼 수 있듯이 : Abstract Model 에서 더 이상 사용되지 않는 저장 및로드 방법saveloadMagento 2 개발 지점에서 사용되지 않습니다.

따라서 이제는 CRUD 엔티티를 처리하기위한 서비스 계약을 구현하는 것이 좋습니다.

사용자 지정 모듈 엔터티에 대한 서비스 계약을 구현하기 위해 따라야하는 단계별 프로세스는 무엇입니까?

NB : CRUD 모델에는 수천 가지 방법이있을 수 있다는 것을 알고 있습니다. http://devdocs.magento.com/guides/v2.0/extension-dev-guide /service-contracts/design-patterns.html :

  • get
  • save
  • getList
  • delete
  • deleteById

답변:


89

@ryanF의 탁월한 답변 외에도 약간 더 자세하게 설명하고 싶습니다.

사용자 지정 엔터티에 대한 리포지토리를 추가해야하는 이유를 요약하고이를 수행하는 방법을 설명하고 해당 리포지토리 메서드를 웹 API의 일부로 노출하는 방법도 설명하고 싶습니다.

면책 조항 : 제 3 자 모듈에 대해이 작업을 수행하는 방법에 대한 실용적인 접근 방식 만 설명하고 있습니다. 핵심 팀에는 자체 표준이 있습니다 (또는 그렇지 않음).

일반적으로 저장소의 목적은 스토리지 관련 논리를 숨기는 것입니다.
리포지토리의 클라이언트는 반환 된 엔터티가 배열의 메모리에 유지되는지, MySQL 데이터베이스에서 검색되는지, 원격 API 또는 파일에서 가져 왔는지 상관하지 않습니다.
나는 Magento 핵심 팀이 나중에 ORM을 변경하거나 교체 할 수 있도록 이것을했다고 가정합니다. Magento에서 ORM은 현재 모델, 리소스 모델 및 컬렉션으로 구성되어 있습니다.
타사 모듈이 리포지토리 만 사용하는 경우 Magento는 데이터 저장 방법 및 위치를 변경할 수 있으며 이러한 깊은 변경에도 불구하고 모듈은 계속 작동합니다.

저장소는 일반적으로 같은 방법이 findById(), findByName(), put()또는 remove().
마 젠토에서이 일반적이라고합니다 getbyId(), save()그리고 delete()심지어 그들이 무엇을하고 있지만, CRUD DB 작업을하는 척.

Magento 2 리포지토리 방법은 API 리소스로 쉽게 노출 될 수 있으므로 타사 시스템 또는 헤드리스 Magento 인스턴스와의 통합에 유용합니다.

"사용자 지정 엔터티에 대한 리포지토리를 추가해야합니까?".

언제나 그렇듯이 대답은

"그것은 달려있다".

간단히 말해서, 다른 모듈에서 엔티티를 사용한다면 저장소를 추가하고 싶을 것입니다.

마 젠토 2에서 리포지토리는 웹 API, 즉 REST 및 SOAP 리소스로 쉽게 노출 될 수 있습니다.

타사 시스템 통합 또는 헤드리스 Magento 설정으로 인해 이것이 흥미로울 경우, 다시 엔터티에 대한 리포지토리를 추가하고 싶을 것입니다.

사용자 지정 엔터티에 대한 리포지토리를 어떻게 추가합니까?

REST API의 일부로 엔티티를 노출한다고 가정하십시오. 그렇지 않은 경우, 인터페이스 작성에 대한 다음 부분을 건너 뛰고 바로 아래의 "저장소 및 데이터 모델 구현 작성"으로 이동할 수 있습니다.

저장소 및 데이터 모델 인터페이스 작성

Api/Data/모듈 에서 폴더 를 만듭니다 . 이것은 단지 컨벤션이므로 다른 위치를 사용할 수는 있지만 그렇게해서는 안됩니다.
저장소는 Api/폴더 로 이동 합니다. Data/하위 디렉토리는 나중에이다.

에서 Api/, 노출 할 방법과 PHP 인터페이스를 만들 수 있습니다. Magento 2 규칙에 따르면 모든 인터페이스 이름은 접미사로 끝납니다 Interface.
예를 들어 Hamburger엔터티의 경우 인터페이스를 만듭니다 Api/HamburgerRepositoryInterface.

리포지토리 인터페이스 만들기

마 젠토 2 리포지토리는 모듈의 도메인 로직의 일부입니다. 즉, 저장소가 구현해야하는 고정 된 메소드 세트가 없습니다.
전적으로 모듈의 목적에 달려 있습니다.

그러나 실제로 모든 리포지토리는 매우 유사합니다. CRUD 기능을위한 래퍼입니다.
대부분의 방법이 getById, save, deletegetList.
예를 들어 CustomerRepositoryhas 메소드 가있을 수 있습니다. 이 메소드 get는 이메일 getById로 고객을 가져 와서 엔티티 ID로 고객을 검색하는 데 사용됩니다.

햄버거 엔터티에 대한 예제 리포지토리 인터페이스는 다음과 같습니다.

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

}

중대한! 여기에 타임 싱크가 있습니다!
여기에 잘못되면 디버깅하기 어려운 몇 가지 문제가 있습니다.

  1. REST API에 연결하려는 경우 PHP7 스칼라 인수 유형 또는 리턴 유형을 사용 하지 마십시오 !
  2. 모든 인수에 대한 PHPDoc 주석과 모든 메소드에 리턴 유형을 추가하십시오!
  3. PHPDoc 블록에서 정규화 된 클래스 이름 을 사용하십시오 !

주석은 Magento Framework에서 구문 분석하여 JSON 또는 XML과의 데이터 변환 방법을 결정합니다. 클래스 가져 오기 (즉, use명령문)는 적용되지 않습니다!

모든 메소드에는 인수 유형과 리턴 유형이있는 주석이 있어야합니다. 메소드가 인수를 취하지 않고 아무것도 리턴하지 않더라도 주석이 있어야합니다.

/**
 * @return void
 */

스칼라 유형 ( string, int, floatbool)도 인수와 반환 값으로 모두 지정해야합니다.

위의 예에서 객체를 반환하는 메서드에 대한 주석도 인터페이스로 지정됩니다.
리턴 유형 인터페이스는 모두 Api\Data네임 스페이스 / 디렉토리에 있습니다.
이는 비즈니스 로직이 포함되어 있지 않음을 나타냅니다. 그들은 단순히 데이터의 가방입니다.
다음에 이러한 인터페이스를 만들어야합니다.

DTO 인터페이스 생성

Magento는 이러한 인터페이스를 "데이터 모델"이라고 부릅니다.
이 유형의 클래스는 일반적으로 데이터 전송 개체 또는 DTO라고 합니다.
이 DTO 클래스에는 모든 속성에 대한 getter 및 setter 만 있습니다.

데이터 모델보다 DTO를 선호하는 이유는 ORM 데이터 모델, 리소스 모델 또는 뷰 모델과 혼동하기가 쉽지 않기 때문입니다. 이미 너무 많은 것이 Magento의 모델입니다.

리포지토리에 적용되는 PHP7 타이핑과 관련하여 동일한 제한 사항이 DTO에도 적용됩니다.
또한 모든 메소드에는 모든 인수 유형과 리턴 유형이있는 주석이 있어야합니다.

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

메소드가 배열을 검색하거나 리턴하는 경우 배열의 항목 유형을 PHPDoc 주석에 지정하고 여는 닫는 대괄호를 지정해야 []합니다.
이는 스칼라 값 (예 :) int[]과 객체 (예 :) 모두에 해당됩니다 IngredientInterface[].

Api\Data\IngredientInterface객체 배열을 반환하는 메소드에 대한 예제로를 사용하고 있습니다.이 포스트 터프에 재료 코드를 추가하지는 않습니다.

ExtensibleDataInterface?

위의 예 HamburgerInterface에서 ExtensibleDataInterface.
기술적으로 이것은 다른 모듈이 엔티티에 속성을 추가 할 수있게하려는 경우에만 필요합니다.
그렇다면 getExtensionAttributes()and 라는 규칙에 따라 다른 getter / setter 쌍을 추가해야합니다 setExtensionAttributes().

이 메소드의 리턴 유형 이름은 매우 중요합니다!

Magento 2 프레임 워크는 인터페이스의 이름, 구현 및 팩토리를 생성합니다. 이러한 메커니즘의 세부 사항은이 게시물의 범위를 벗어납니다.
확장 가능하게 만들려는 객체의 인터페이스가 호출 \VinaiKopp\Kitchen\Api\Data\HamburgerInterface되면 확장 속성 유형은이어야 \VinaiKopp\Kitchen\Api\Data\HamburgerExtensionInterface합니다. 따라서 단어 Extension는 엔터티 이름 Interface뒤에 접미사 바로 앞에 삽입해야합니다 .

엔터티를 확장 할 수 없게하려면 DTO 인터페이스가 다른 인터페이스를 확장 할 필요가 없으며 getExtensionAttributes()setExtensionAttributes()메소드를 생략 할 수 있습니다.

지금은 DTO 인터페이스에 대한 정보가 충분합니다. 이제 리포지토리 인터페이스로 돌아갑니다.

getList () 리턴 유형 SearchResults

저장소 메소드 getList는 또 다른 유형, 즉 SearchResultsInterface인스턴스 를 리턴 합니다.

이 메소드 getList는 물론 지정된와 일치하는 객체 배열을 SearchCriteria반환 SearchResults할 수 있지만 인스턴스를 반환하면 유용한 메타 데이터를 반환 된 값에 추가 할 수 있습니다.

저장소 getList()메소드 구현 에서 아래에서 작동 방식을 확인할 수 있습니다 .

햄버거 검색 결과 인터페이스의 예는 다음과 같습니다.

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

이 인터페이스는 두 가지 메소드 getItems()setItems()상위 인터페이스 의 유형을 대체합니다 .

인터페이스 요약

이제 다음과 같은 인터페이스가 있습니다.

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

저장소는 아무것도 확장하지
(가) HamburgerInterface를 확장 \Magento\Framework\Api\ExtensibleDataInterface,
그리고는 HamburgerSearchResultInterface을 확장합니다 \Magento\Framework\Api\SearchResultsInterface.

저장소 및 데이터 모델 구현 작성

다음 단계는 세 가지 인터페이스의 구현을 만드는 것입니다.

리포지토리

본질적으로 리포지토리는 ORM을 사용하여 작업을 수행합니다.

getById(), save()delete()방법은 매우 정직하고 있습니다.
HamburgerFactory이하에서 좀 알 수있는 바와 같이, 생성자 인수 저장소로 주입된다.

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

이제 저장소의 가장 흥미로운 부분 인 getList()방법입니다. 방법은 번역하는 컬렉션에 메소드 호출에 조건.
getList()SerachCriteria

그 까다로운 부분은 점점 ANDOR수집에 조건을 설정하기위한 구문 그것이 EAV 또는 평평한 테이블 엔티티인지 여부에 따라 상이하다 특히 이후, 우측 필터에 대한 조건.

대부분의 경우 getList()아래 예와 같이 구현할 수 있습니다.

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

안의 연산자 FilterGroupOR 연산자를 사용하여 결합해야합니다 .
논리 AND 연산자를 사용하여 별도의 필터 그룹을 결합합니다 .


이것은 가장 큰 일이었습니다. 다른 인터페이스 구현이 더 간단합니다.

DTO

Magento는 원래 개발자가 DTO를 엔터티 모델과 별개의 별도 클래스로 구현하도록 의도했습니다.

핵심 팀은 비록 고객 모듈 (위해 이런 짓을 \Magento\Customer\Api\Data\CustomerInterface하여 구현됩니다 \Magento\Customer\Model\Data\Customer,하지 \Magento\Customer\Model\Customer).
다른 모든 경우 엔터티 모델은 DTO 인터페이스를 구현합니다 (예 : \Magento\Catalog\Api\Data\ProductInterface로 구현 \Magento\Catalog\Model\Product).

나는 핵심 팀원들에게 회의에서 이것에 대해 물었지만, 좋은 연습으로 여겨 질 것이 무엇인지에 대한 명확한 대답을 얻지 못했습니다.
내 추천은이 추천이 취소되었다는 것입니다. 그래도 공식적인 진술을 얻는 것이 좋을 것입니다.

지금은 모델을 DTO 인터페이스 구현으로 사용하기위한 실용적인 결정을 내 렸습니다. 별도의 데이터 모델을 사용하는 것이 더 깨끗하다고 ​​생각되면 자유롭게 사용하십시오. 두 방법 모두 실제로 잘 작동합니다.

DTO 인터페이스 Magento\Framework\Api\ExtensibleDataInterface가를 확장하면 모델이 확장되어야 Magento\Framework\Model\AbstractExtensibleModel합니다.
확장성에 신경 쓰지 않으면 모델은 단순히 ORM 모델 기본 클래스를 계속 확장 할 수 있습니다 Magento\Framework\Model\AbstractModel.

예제가 있기 때문에 HamburgerInterface확장 ExtensibleDataInterface햄버거 모델은 확장 AbstractExtensibleModel여기에서 알 수있는 바와 같이, :

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

속성 이름을 상수로 추출하면 한 곳에 유지할 수 있습니다. getter / setter 쌍과 데이터베이스 테이블을 작성하는 Setup 스크립트에서도 사용할 수 있습니다. 그렇지 않으면 상수로 추출 할 때 이점이 없습니다.

SearchResult

이것은 SearchResultsInterface프레임 워크 클래스에서 모든 기능을 상속 할 수 있기 때문에 구현할 세 가지 인터페이스 중 가장 단순합니다.

<?php

namespace VinaiKopp\Kitchen\Model;

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

class HamburgerSearchResult extends SearchResults implements HamburgerSearchResultInterface
{

}

ObjectManager 환경 설정 구성

구현이 완료되었지만 Magento Framework 개체 관리자가 사용할 구현을 알지 못하므로 인터페이스를 다른 클래스의 종속성으로 계속 사용할 수 없습니다. 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="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>

리포지토리를 API 리소스로 어떻게 노출 할 수 있습니까?

이 부분은 정말 간단합니다. 인터페이스, 구현 및 인터페이스를 만드는 모든 작업을 수행 한 것에 대한 보상입니다.

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

이 구성은 저장소를 REST 엔드 포인트로 사용할 수있을뿐만 아니라 메소드를 SOAP API의 일부로 노출합니다.

첫 번째 경로 예 <route method="GET" url="/V1/vinaikopp_hamburgers/:id">에서 자리 표시 :id자는 인수 이름과 매핑 된 메서드를 일치시켜야합니다 public function getById($id). 메소드 인수 variable name이 (가) 있으므로
두 이름이 일치해야합니다 (예 : /V1/vinaikopp_hamburgers/:hamburgerId작동하지 않음) $id.

이 예제에서는 접근성을로 설정했습니다 <resource ref="anonymous"/>. 즉, 리소스가 제한없이 공개적으로 노출됩니다!
로그인 한 고객 만 리소스를 사용할 수있게하려면을 사용하십시오 <resource ref="self"/>. 이 경우 me자원 엔드 포인트 URL 의 특수 단어 를 사용 $id하여 현재 로그인 한 고객의 ID로 인수 변수를 채 웁니다 .
젠토 고객에서보세요 etc/webapi.xml그리고 CustomerRepositoryInterface당신이 필요합니다.

마지막으로을 <resources>사용하여 리소스에 대한 액세스를 관리자 계정으로 제한 할 수도 있습니다. 이를 위해 <resource>ref를 etc/acl.xml파일에 정의 된 식별자로 설정 하십시오.
예를 들어 <resource ref="Magento_Customer::manage"/>고객 관리 권한이있는 모든 관리자 계정에 대한 액세스를 제한합니다.

curl을 사용하는 예제 API 쿼리는 다음과 같습니다.

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

참고 :이 글을 https://github.com/astorm/pestle/issues/195에 대한 답변으로 시작
했습니다. pestle을 확인하고 Commercebug를 구입 하여 @alanstorm 의 후원자가 되십시오.


1
이 위대한 답변에 감사드립니다. 미안하지만 뭔가 빠졌을 수도 있지만 결국 엔 setData 메소드가있는 AbstractModel에서 확장해야 할 때 엔티티에 대한 깨끗한 인터페이스를 갖는 요점은 인터페이스에 관계없이 객체에 무엇이든 추가 할 수 있다는 것을 의미합니까?
LDusan

클래스는 여러 인터페이스를 구현하고 추가 메소드를 추가 할 수 있습니다. 중요한 것은 다른 클래스는 인터페이스 메소드에만 의존하므로 다른 클래스에 대해서는 모른다는 것입니다. 인터페이스가 아닌 메소드 구현 세부 사항을 작성하여 외부 클래스를 중단하지 않고 언제든지 변경할 수 있습니다. 이것이 의존성 역전의 아이디어입니다. 클래스와 클라이언트는 모두 인터페이스에 의존하며 구현 세부 정보를 모릅니다. 그것은 명확합니까?
Vinai

답변 주셔서 감사합니다, 무슨 말인지 알 겠어요. 문제는 setData가 공개 메소드이므로 구현 세부 사항으로 간주 될 수 있는지 확실하지 않습니다. 퍼블릭 메서드처럼 사용하기 위해 변경되었을 때 외부가 손상되지 않도록하려면 어떻게해야합니까?
LDusan

3
죄송합니다. 당신이 묘사하는 것은 일반적인 관점입니다. 의존성의 역학은 직관적이지 않으며 PHP는 인터페이스에 의존하지 않는 메소드를 호출 할 수 있으며, 컴파일 할 필요가 없기 때문에 의존성을 명확하게보기 어려워지고 어려워집니다 . 인터페이스에 의존하지 않는 구현 메소드가 호출되는 곳이 많은 Magento 2 코어에서도 확인할 수 있습니다. 이것들은 나쁜 예가되고 명확하고 건전한 이해를 얻는 것을 더욱 어렵게 만듭니다.
Vinai


35

디지털 피아니즘의 @Raphael :

다음 샘플 모듈 구조를 참조하십시오.

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. 리포지토리 인터페이스 만들기 (서비스 계약)
    Namespace/Custom/Api/CustomRepositoryInterface.php: http://codepad.org/WognSKnH

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

  3. CustomInterface (데이터 컨테이너) 생성
    Namespace/Custom/Api/Data/CustomInterface.php: http://codepad.org/Ze53eT4o

  4. CustomRepository 작성 (콘크리트 저장소)
    Namespace/Custom/Model/CustomRepository.php: http://codepad.org/KNt5QAGZ
    "마법"이 발생하는 위치입니다. 생성자 DI를 통해 사용자 정의 모듈에 대한 자원 모델 / 수집 팩토리를 전달합니다. 이 저장소의 CRUD 저장 메소드와 관련하여 CustomRepositoryInterface로 인해 CustomInterface 매개 변수를 전달 해야합니다 . 모듈의 di.xml에는이 유형의 인터페이스를 엔티티 모델로 바꾸는 환경 설정이 있습니다. 엔티티 모델이 자원 모델로 전달되어 저장됩니다.

  5. 환경 설정
    Namespace/Custom/etc/di.xml: http://codepad.org/KmcoOUeV

  6. 사용자 정의 인터페이스 (데이터 컨테이너)를 구현하는 엔티티 모델
    Namespace/Custom/Model/Custom.php: http://codepad.org/xQiBU7p7 .

  7. 자원 모델
    Namespace/Custom/Model/ResourceModel/Custom.php: http://codepad.org/IOsxm9qW

몇 가지 참고할 사항 :

  • 기권!!! 사용자 지정 공급 업체 이름, 대행사 이름 등을 대신하여 "네임 스페이스"를 사용했습니다. 모듈을 그룹화하는 데 사용하는 이름에 관계없이 ... "네임 스페이스"의 실제 사용은 Php에서 완전히 유효 하지 않습니다. 편의상 이 작업을 수행했으며 이것이 효과가 있다고 생각 하지 않으며 어떤 식 으로든 제안하지 않습니다.

  • @Ryan Street는 이것을 가르쳐주었습니다 ... 그래서 나는 모든 크레딧을 받고 싶지 않습니다.

  • 필요에 맞게 리포지토리 구현을 명확하게 변경하십시오.

  • 구체적인 리포지토리에서 사용자 지정 엔터티 모델 / 자원 모델 / 컬렉션과의 상호 작용을 구현합니다.

  • 귀하의 질문에 나열된 모든 방법을 다루지 않았다는 것을 알고 있지만 이것은 훌륭한 시작이며 문서와 실제 구현 간의 격차를 해소해야합니다.


Ryan, 우리가 만든 사용자 정의 비누 API (예 : save (), delete () 등)에 대해 서비스 계약에 언급 된 방법이 있습니까?
Sushivam

magento 2에서 맞춤형 비누 API를 만드는 방법에 대한 아이디어를 제공해 주시겠습니까?
Sushivam

@SachinS 불행히도, 나는 SOAP에 관해 제공 할 통찰력이 없다. 아직 조사하지 않았으며 아직 구현하지 않았습니다. 내가 제안 할 수있는 최선은 여기에 관한 새로운 질문을 여는 것입니다. 나는 문서도 확인한다고 말하지만 슬프게도 항상 최선의 행동 과정은 아닙니다 (아마도 부족할 수 있습니다). 언제든지 핵심 코드베이스 또는 타사 확장을 살펴보고 통찰력이 있는지 확인할 수 있습니다. 행운을 빕니다! 답을 찾으면 여기에 링크를 추가하는 것이 좋습니다. 감사합니다
ryanF

답장 @ryan에 감사합니다. 어쨌든 SOAP에 비해 가볍기 때문에 REST를 사용하여 모듈을 구현했습니다 ... SOAP에서 동일하게 구현하면 게시하십시오
Sushivam

3
@ryanF이 유용한 답변에 감사드립니다. 복사 / 붙여 넣기 작업 코드가 아니라는 것을 알고 있지만 다음과 같은 다른 사람들의 이익을 위해 오타가 있습니다. 저장소에서 CustomSearchResultsInterfaceFactory는 CustomSearchResultsFactory 여야합니다. $ searchResults-> setCriteria는 $ searchResults-> setSearchCriteria 여야합니다. foreach의 $ Customs []는 $ customs [] 여야합니다. 나는 그것이 그것에 관한 것이라고 생각합니다.
tetranz

3

서비스 계약 사용에 대한 완전한 파일

커스텀 / 모듈 /registration.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" => "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");
    }
}

../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");
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.