Skip to end of metadata
Go to start of metadata

You are viewing an old version of this content. View the current version.

Compare with Current View Version History

« Previous Version 10 Current »

https://devdocs.magento.com/guides/v2.4/extension-dev-guide/service-contracts/service-contracts.html

https://devdocs.magento.com/guides/v2.4/extension-dev-guide/api-concepts.html

Lý thuyết

Hợp đồng dịch vụ (Service Contracts)

Magento là một hệ thống cho phép các nhà lập trình bên thứ ba có thể tùy chỉnh và ghi đè lên phần core của nó. Sự linh hoạt này khiến cho magento dễ tùy biến hơn, tuy nhiên, đi kèm theo nó là một số vấn đề gặp phải.

-Logic xử lí có xu hướng bị rò rỉ trên các class của Magento, mà biểu hiện như sự trùng lặp và không nhất quán trong code.

-Người chủ website có thể lưỡng lự khi nâng cấp Magento vì các extension mà họ đã mua có thể không tương thích với các phiên bản mới của Magento. Ngoài ra, Magento và nhà phát triển bên thứ ba có thể gặp khó khăn để theo dõi sự phụ thuộc vào những extension khác với nhau.

Để giải quyết những vấn đề này, Magento đã đề ra "Hợp đồng dịch vụ" (Service Contracts).

Một hợp đồng dịch vụ (Service Contract) là gì?

"Hợp đồng dịch vụ" là một bộ PHP Interface được định nghĩa cho một module. Hợp đồng dịch vụ bao gồm các data interfaces dùng để bảo tồn tính toàn vẹn dữ liệu và service interfaces để cung cấp các xử lí. Chi tiết logic xử lí được ẩn đi với các phần sử dụng dịch vụ (như controller, web services và các module khác).

Nếu developer định nghĩa data và service interfaces theo một mẫu thiết kế, API của các modules khác và các extension bên thứ ba có thể implement nó thông qua Magento models và resource models.

Dưới đây là hình ảnh mô tả về cấu trúc của Magento 2 tuân theo Service Contract:

Trong hình ảnh trên, các bạn có thể thấy Controllers, Web Services, Other modules không thao tác trực tiếp với thành phần Model và Resource Model mà giao tiếp thông qua interface. Logic xử lí được ẩn đi, các thành phần sử dụng service chỉ quan tâm đến đầu ra và đầu vào chứ không cần quan tâm đến logic xử lí.

Ví dụ Interface: Magento\Catalog\Api\ProductRepositoryInterface

public function delete(\Magento\Catalog\Api\Data\ProductInterface $product);

Ví dụ Model implements Interface: Magento\Catalog\Model\ProductRepository

public function delete(\Magento\Catalog\Api\Data\ProductInterface $product)
{
    $sku = $product->getSku();
    $productId = $product->getId();
    try {
        unset($this->instances[$product->getSku()]);
        unset($this->instancesById[$product->getId()]);
        $this->resourceModel->delete($product);
    } catch (ValidatorException $e) {
        throw new CouldNotSaveException(__($e->getMessage()));
    } catch (\Exception $e) {
        throw new \Magento\Framework\Exception\StateException(
            __('Unable to remove product %1', $sku)
        );
    }
    unset($this->instances[$sku]);
    unset($this->instancesById[$productId]);
    return true;
}

Việc model nào ứng với interface nào được cấu hình trong file etc/di.xml của magento 2.

<preference for="Magento\Catalog\Api\ProductRepositoryInterface" 
type="Magento\Catalog\Model\ProductRepository" />

Lợi ích của hợp đồng dịch vụ (Service Contracts)

Để giải thích dễ hiểu hơn về lợi ích của Service Contract, mình sẽ đưa ra ví dụ sau:

Giả sử có 2 công ty A và B. Công ty A yêu cầu công ty B làm cho mình một chiếc xe ô tô. Công ty A sẽ kí với công ty B một bản hợp đồng cam kết là sẽ ô tô phải có đủ tính năng và đặc điểm như: màu vàng, chạy êm, 20 chỗ ngồi, … . Công ty B sẽ giao dự án này cho team Eden thực hiện.

ở đây ta có thể hiểu: - Công ty A ứng với Module A - Công ty B ứng với Module B - Hợp đồng ứng với Interface (data interface và service interface) - Team Eden ứng với Model và Resource Model của Magento

Như chúng ta thấy, Công ty A sẽ không giao tiếp trực tiếp với team Eden mà thông qua công ty và đại diện cho nó là bản hợp đồng đã được ký kết. Việc ai thực hiện dự án này sẽ do nội bộ công ty B quyết định, và công ty A sẽ không can thiệp và cũng không biết tới nó. Giả dụ, nếu team Eden không thực hiện dự án, thì công ty B sẽ giao cho một team khác (team Eagle). Sự thay đổi này chỉ diễn ra trong nội bộ công ty B và công ty A không phải chịu ảnh hương gì cả.

Ưng với Magento và service contract, ta có thể thấy, sự thay đổi về Model và Resource Model trong Module B sẽ không gây ảnh hưởng đến Module A. Giả dụ có sự thay đổi, Module B chỉ cần đổi trong file di.xml để thay thế thôi và không gây ảnh hưởng tới các thành phần sử dụng service.

Service Contracts tăng cường khả năng module hóa của Magento. Chúng cho phép Magento và các nhà phát triển bên thứ ba có thể theo dõi sự phụ thuộc hệ thống thông qua những file composer.json và, do đó, đảm bảo tương thích giữa các phiên bản Magento. Điều này đảm bảo rằng người dùng Magento có thể dễ dàng nâng cấp lên các phiên bản Magento mới nhất.

Các service interface này được xác định rõ để các API của module khác và extension bên thứ ba có thể implement nó được.

Các loại Interface và nơi định nghĩa

Có hai loại interface trong mô hình service contracts, đó là Data Interfaces và Service Interfaces.

Data interfaces

Data interfaces được dùng để bảo tồn tính toàn vẹn dữ liệu. Data interfaces định nghĩa các hàm mà trả lại thông tin về các thực thể dữ liệu (data entities), kết quả tìm kiếm, và xác thực kết quả. Bạn phải định nghĩa các data interface cho một service contract trong thư mục Api/Data.

Ví dụ, data interfaces cho module Customer nằm trong thư mục /app/code/Magento/Customer/Api/Data.

Ví dụ về trả về kết quả tìm kiếm (data search results interfaces):

Khi bạn truyền các tiêu chí tìm kiếm và gọi hàm getList (), một search results interface được trả về với kết quả tìm kiếm. Trong một search results interface thường chứa hàm getItems trả về một mảng các data entites (thực thể dữ liệu). Ví dụ, Hàm getItems () trong CustomerSearchResultsInterface trả về một mảng của các thực thể dữ liệu CustomerInterface. GroupSearchResultsInterface, hàm getItems () trả về một mảng các thực thể dữ liệu GroupInterface.

/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Magento\Customer\Api\Data;

/**
 * Interface for customer search results.
 * @api
 */
interface CustomerSearchResultsInterface extends \Magento\Framework\Api\SearchResultsInterface
{
    /**
     * Get customers list.
     *
     * @return \Magento\Customer\Api\Data\CustomerInterface[]
     */
    public function getItems();

    /**
     * Set customers list.
     *
     * @param \Magento\Customer\Api\Data\CustomerInterface[] $items
     * @return $this
     */
    public function setItems(array $items);
}

Service interfaces

Service interfaces được dùng để ẩn logic xử lí từ các bên yêu cầu dịch vụ (service requestors). Bạn phải định nghĩa các service interfaces cho một service contract trong thư mục con Api của một module. Service interface bao gồm:

  • Repository interfaces

  • Management interfaces

  • Metadata interfaces

Cách đặt tên cần tuân theo chuẩn code của Magento. Mình sẽ mô tả cụ thể về các loại service interface ngay sau đây.

– Repository interfaces

Repository Interfaces cung cấp quyền truy cập vào một thực thể dữ liệu (Data entity). Chúng ta thường dùng Repository Interfaces trong trường hợp cần cung cấp các thao tác thêm, sửa, xóa, lấy dữ liệu.

Ví dụ, các thực thể dữ liệu (data entities) cho module Customer bao gồm Customer, Address, và Group. Do đó, các Repository Interfaces cho module Customer là: CustomerRepositoryInterface, AddressRepositoryInterface, GroupRepositoryInterface

Một Repository Interfaces phải cung cấp các chức năng:

  • save (data entity interface): Nếu ID chưa có, tạo một bản ghi mới. Nếu có rồi, cập nhật dữ liệu cho bản ghi đó

  • get(id): tìm kiếm trong database theo ID. Sẽ trả về một data entity interface. Ví dụ như CustomerInterface

  • getList(search criteria): Tìm kiếm tất cả các data entites phù hợp với yêu cầu tìm kiếm. Sẽ trả về một search results interface

  • delete(data entity interface): Xóa một entity cụ thể. Entity này phải chứa ID.

  • deleteById(id): Xóa một entity theo ID

Sau đây là một ví dụ về CustomerRepositoryInterface:

<?php
/**
 *
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Magento\Customer\Api;

/**
 * Customer CRUD interface.
 * @api
 */
interface CustomerRepositoryInterface
{
    /**
     * Create or update a customer.
     *
     * @param \Magento\Customer\Api\Data\CustomerInterface $customer
     * @param string $passwordHash
     * @return \Magento\Customer\Api\Data\CustomerInterface
     * @throws \Magento\Framework\Exception\InputException If bad input is provided
     * @throws \Magento\Framework\Exception\State\InputMismatchException If the provided email is already used
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $passwordHash = null);

    /**
     * Retrieve customer.
     *
     * @param string $email
     * @param int|null $websiteId
     * @return \Magento\Customer\Api\Data\CustomerInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException If customer with the specified email does not exist.
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function get($email, $websiteId = null);

    /**
     * Get customer by customer ID.
     *
     * @param int $customerId
     * @return \Magento\Customer\Api\Data\CustomerInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException If customer with the specified ID does not exist.
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getById($customerId);

    /**
     * Retrieve customers which match a specified criteria.
     *
     * This call returns an array of objects, but detailed information about each object’s attributes might not be
     * included. See http://devdocs.magento.com/codelinks/attributes.html#CustomerRepositoryInterface to determine
     * which call to use to get detailed information about all attributes for an object.
     *
     * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
     * @return \Magento\Customer\Api\Data\CustomerSearchResultsInterface
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria);

    /**
     * Delete customer.
     *
     * @param \Magento\Customer\Api\Data\CustomerInterface $customer
     * @return bool true on success
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function delete(\Magento\Customer\Api\Data\CustomerInterface $customer);

    /**
     * Delete customer by ID.
     *
     * @param int $customerId
     * @return bool true on success
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function deleteById($customerId);
}

– Management interfaces

Management interfaces cung cấp chức năng quản lý mà không liên quan đến các Repository Interfaces. Ví dụ:

  • AccountManagementInterface: cung cấp chức năng như tạo tài khoản createAccount(), đổi password changePassword() ...

  • AddressManagementInterface: cung cấp chức năng validate() để xác thực một address.

  • Metadata interfaces

Metadata interface cung cấp thông tin về những gì thuộc tính (attributes) được định nghĩa cho một thực thể. Metadata interface thường dùng để định nghĩa thêm các custom attributes cho một entity cho Magento. Ví dụ như customer entity cần thêm các custom attribute, do đó sẽ có CustomerMetadataInterface:

Sau đây là ví dụ về CustomerMetadataInterface:

    <?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Magento\Customer\Api;

/**
 * Interface for retrieval information about customer attributes metadata.
 * @api
 */
interface CustomerMetadataInterface extends MetadataInterface
{
    const ATTRIBUTE_SET_ID_CUSTOMER = 1;

    const ENTITY_TYPE_CUSTOMER = 'customer';

    const DATA_INTERFACE_NAME = 'Magento\Customer\Api\Data\CustomerInterface';

}

Như vậy mình đã trình bày xong về mô hình Service Contracts trong Magento 2. Đây là một mẫu design pattern khá quan trọng trong Magento 2 mà mọi developer Magento 2 đều cần phải biết. Hiện tại, mô hình này đang được áp dụng rất phổ biến trong các module của Magento 2. Các bạn có thể tự xem thêm trong code core của Magento 2, cụ thể là 2 module Customer và Checkout để biết sâu thêm về các loại Data Interfaces và Service Interfaces trong mô hình này.

API:

Tạo file etc/webapi.xml

url: tên đường dẫn khi gọi api

method: POST, PUT, GET, DELETE: phương thức gửi data lên api

service class: trỏ tới interface thực hiện api

service method: hàm xử lí của api

resource: dùng để xác thực, anonymous là bỏ qua xác thực

Ví dụ:

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">

    <route url="/V1/webpos/website/information" method="GET">
        <service class="Magestore\Webpos\Api\Website\WebsiteInformationRepositoryInterface" method="getInformation"/>
        <resources>
            <resource ref="anonymous" />
        </resources>
    </route>

</routes>

Call api:

Gọi đường dẫn:

http://[domain]/rest/default/V1/webpos/website/information với method là GET

để thực thi API

Bài tập:

  • Create database to store student data, design the table structure by yourself

  • Use service contract, write repository with the function getList, delete, deleteById,, getById, save

  • Create REST API to CRUD (Create, read , update, delete) student with resource anonymous.

  • No labels