Cách tốt nhất để tải một mô hình tùy chỉnh trong Magento 2


15

Bởi vì thật khó để tôi tìm đúng cách, dưới đây bạn có thể tìm thấy cách thực hành tốt nhất mà tôi đã thực hiện. Hãy tận hưởng, sửa tiếng Anh của tôi nếu cần và nói tôi sai nếu tôi là. :)

Chỉnh sửa: ... và tôi phát hiện ra mình đã sai ở một khía cạnh nào đó. Vì vậy, tôi đã cập nhật bài viết gốc sau khi câu trả lời của Raphael giúp tôi hiểu thêm. Cảm ơn anh!

Khái niệm được sử dụng dưới đây :

Sẽ dễ dàng hơn cho bạn để hiểu các mã và giải thích bên dưới nếu bạn cảm thấy thoải mái với các khái niệm này:

  • Phụ thuộc tiêm (như mọi $this->variablebiến trong mã được tiêm)
  • Hợp đồng dịch vụ và kho lưu trữ
  • Nhà máy

Bối cảnh :

Để có thêm ngữ cảnh, hãy tưởng tượng chúng ta có một mô-đun xây dựng chính xác với:

  • một lớp CustomBlock chứa một phương thức getCustomModel($id),
  • phương thức này trả về một đối tượng CustomModel dựa trên id được truyền trong param,
  • Loại CustomModel tương ứng với mô hình trong \Vendor\Module\Model\CustomModel
  • Mô hình này đi kèm với mô hình tài nguyên của nó (trong \Vendor\Module\Model\ResourceModel\CustomModel)
  • và với kho lưu trữ của nó (trong \Vendor\Module\Model\CustomModelRepository).

Câu hỏi :

  • Cách tốt nhất để cho tất cả mọi thứ tải một đối tượng CustomModel là gì?

Bạn không thể sử dụng load()từ một đối tượng CustomModel vì phương thức này không được dùng nữa.

Thực tiễn tốt nói rằng bạn phải sử dụng Hợp đồng dịch vụ CustomModel. Hợp đồng dịch vụ là giao diện dữ liệu (ví dụ: CustomModelInterface) và giao diện dịch vụ (ví dụ: CustomModelRep repositoryInterface). Vì vậy, khối của tôi trông như thế này:

/ ** @var SlideRep repositoryInterface * /
được bảo vệ $ slideRep repository;

/ **
 * Trình xây dựng CustomBlock
 * ...
 * @param CustomModelRep repositoryInterface $ customModelRep repository
 * ...
 * /
chức năng công cộng __construct (
...
CustomModelRep repositoryInterface $ customModelRep repository
...
) {
    $ this-> customModelRep repository = $ customModelRep repository;
}

chức năng công khai getCustomModel ($ id) {
    trả về $ this-> customModelRep repository-> get ($ id);
}

Trước hết, chúng ta tiêm CustomModelRepositoryInterfaceđối tượng vào hàm tạo và chúng ta sử dụng nó trong getCustomModel()phương thức của chúng ta .

Trong lớp Api\CustomModelRepositoryInterfacekhông có nhiều. Nói chung (nhưng không có gì ngăn cản bạn làm cách khác nhau), bạn sẽ tuyên bố phương pháp cơ bản: get, getList, save, delete, deleteById. Vì mục đích của chủ đề này, dưới đây chỉ là getphương pháp kê khai:

/**
 * Get info by id
 *
 * @param int $id
 * @return Data\CustomModelInterface
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
public function get($id);

Ok, nhưng nếu Giao diện CustomModel của tôi được gọi bằng cách tiêm phụ thuộc trong hàm tạo khối của tôi, thì mã ở đâu? Để trả lời cho câu hỏi này, bạn phải giải thích cho Magento nơi tìm lớp thực hiện giao diện này. Trong tệp etc / di.xml của mô-đun, bạn phải thêm:

<preference for="Vendor\Module\Api\CustomModelRepositoryInterface" type="Vendor\Module\Model\CustomModelRepository" />

Vì vậy, CustomModelRepositoryInterfacelớp là một giao diện dịch vụ. Khi thực hiện nó, bạn sẽ phải thực hiện cả giao diện dữ liệu (ít nhất là Vendor\Module\Api\Data\CustomModelInterfaceVendor\Module\Api\Data\CustomModelSearchResultsInterface). Mô hình của bạn sẽ phải thực hiện Vendor\Module\Api\Data\CustomModelInterfacevà thêm <preference ... />các dòng cho mỗi một giao diện của bạn. Cuối cùng, bất cứ lúc nào bạn sử dụng hợp đồng dịch vụ, hãy suy nghĩ mySomethingInterfacekhông nữa mySomething: hãy để magento sử dụng di.xmlcơ chế ưu tiên.

Ok, điều gì đến tiếp theo? Khi chúng ta tiêm CustomModelRepositoryInterfacevào hàm tạo khối, chúng ta sẽ có một CustomModelRepositoryđối tượng. CustomModelRepositoryphải thực hiện phương thức khai báo trong CustomModelRepositoryInterface. Vì vậy, chúng tôi có điều này trong Vendor\Module\Model\CustomModelRepository:

chức năng công khai get ($ id) {
    $ customModel = $ this-> customModelFactory-> create ();
    $ customModel-> tải ($ id);
    if (! $ customModel-> getId ()) {
      ném NoSuchEntityException mới (__ ('CustomModel với id "% 1" không tồn tại.', $ id));
    }
    trả về $ customModel;
}

Chúng ta đang làm gì? Chúng tôi tạo ra một CustomModelđối tượng trống nhờ vào nhà máy. Tiếp theo chúng ta tải dữ liệu theo CustomModelphương pháp mô hình tải. Tiếp theo, chúng tôi trả về NoSuchEntityExceptionnếu chúng tôi không tải CustomModelđược id trong params. Nhưng nếu mọi thứ đều ổn, chúng tôi trả lại đối tượng mô hình và cuộc sống vẫn tiếp tục.

Nhưng wow ...! Trong ví dụ này đó là gì?

$customModel->load($id);

Không phải là loadphương pháp không dùng nữa so với lúc ban đầu sao? Vâng, đúng vậy. Tôi nghĩ đó là một sự xấu hổ, nhưng bạn phải sử dụng nó vì trong phương thức load () này có một số sự kiện được gửi đi và nhà phát triển có thể lắng nghe chúng (xem câu trả lời của Raphael bên dưới).

Trong tương lai, chúng tôi sẽ được lưu bởi Entity Manager. Đó là một câu chuyện khác như một khái niệm Magento 2 mới, nhưng nếu bạn muốn để mắt tới, Trình quản lý thực thể đã được triển khai trong Mô hình tài nguyên của trang CMS (v2.1):

public function load(AbstractModel $object, $value, $field = null)
{
    $pageId = $this->getPageId($object, $value, $field);
    if ($pageId) {
        $this->entityManager->load($object, $pageId);
    }
    return $this;
}

Câu trả lời:


15

Thực hành tốt nhất: thông qua hợp đồng dịch vụ

Thực tiễn tốt nhất là luôn luôn sử dụng hợp đồng dịch vụ bất cứ khi nào có thể. Bạn có thể tìm thấy danh sách các lý do tại đây: Magento 2: lợi ích của việc sử dụng hợp đồng dịch vụ là gì?

Để biết chi tiết về cách triển khai hợp đồng dịch vụ, tôi khuyên bạn nên kiểm tra chủ đề này: Cách triển khai hợp đồng dịch vụ cho một mô-đun tùy chỉnh trong Magento 2?

Nếu không có hợp đồng dịch vụ

Nếu không có hợp đồng dịch vụ có sẵn, bạn nên sử dụng getphương pháp lưu trữ mô hình . Sử dụng phương thức này, bạn được hưởng lợi từ hệ thống bộ nhớ đệm magento chẳng hạn cho CategoryRepositorylớp:

public function get($categoryId, $storeId = null)
{
    $cacheKey = null !== $storeId ? $storeId : 'all';
    if (!isset($this->instances[$categoryId][$cacheKey])) {
        /** @var Category $category */
        $category = $this->categoryFactory->create();
        if (null !== $storeId) {
            $category->setStoreId($storeId);
        }
        $category->load($categoryId);
        if (!$category->getId()) {
            throw NoSuchEntityException::singleField('id', $categoryId);
        }
        $this->instances[$categoryId][$cacheKey] = $category;
    }
    return $this->instances[$categoryId][$cacheKey];
}

load()Phương pháp không dùng nữa

Magento 2 đang dần rời khỏi hệ thống CRUD tiêu chuẩn bằng cách loại bỏ hệ thống kế thừa và triển khai nó thông qua thành phần bằng EntityManager 2.1 mới, bạn có thể tìm thấy chi tiết tại đây: Magento 2.1: sử dụng trình quản lý thực thể

Ngoài ra tôi đề nghị bạn đọc chủ đề thú vị này về các phương thức CRUD không dùng nữa: Các phương thức lưu và tải không dùng nữa trong Mô hình Trừu tượng

Tại sao không sử dụng tải mô hình tài nguyên

Lý do chính là nếu bạn sử dụng loadphương thức mô hình tài nguyên , bạn sẽ bỏ qua một số phần quan trọng của hệ thống tải được triển khai trong loadphương thức mô hình , xem Magento\Framework\Model\AbstractModel:

public function load($modelId, $field = null)
{
    $this->_beforeLoad($modelId, $field);
    $this->_getResource()->load($this, $modelId, $field);
    $this->_afterLoad();
    $this->setOrigData();
    $this->_hasDataChanges = false;
    $this->updateStoredData();
    return $this;
}

Gọi loadphương thức mô hình tài nguyên trực tiếp sẽ có tác động sau:

  • _beforeLoad không được gọi: do đó tải mô hình trước khi các sự kiện không được gửi đi
  • _afterLoad không được gọi: do đó tải mô hình sau khi các sự kiện không được gửi đi
  • dữ liệu được lưu trữ không được cập nhật có thể gây ra nhiều vấn đề khác nhau (ví dụ nếu bạn gọi prepareDataForUpdatetừ Magento\Framework\Model\ResourceModel\Db\AbstractDb)

Cảm ơn Raphael, mọi điều bạn nói đều có ý nghĩa và hoàn thành kiến ​​thức của tôi. Nhưng tôi không hiểu tại sao KAndy bình luận (theo câu trả lời của anh ấy) rằng Marius có thể sử dụng phương thức load () của mô hình tài nguyên mô-đun tùy chỉnh của mình? Đó là trong [ magento.stackexchange.com/questions/114929/ phương thức lưu và tải trong Mô hình trừu tượng). Có ý kiến ​​gì không?
Nicolas PERNOT

@NicolasPERNOT về cơ bản KAndy giải thích rằng mục tiêu là có SL (Lớp dịch vụ) cho mọi mô-đun và đây là thứ phải được sử dụng mỗi khi bạn cần tải một thực thể. Tôi đề nghị bạn nhận xét bằng cách đề cập đến anh ta, có lẽ anh ta sẽ có thể khai sáng cho bạn vì anh ta là nhân viên của Magento Inc
Raphael tại Digital Pianism

Vâng, cuối cùng tôi đã cập nhật bài viết gốc của tôi. Cảm ơn Raphael vì sự giúp đỡ của bạn.
Nicolas PERNOT

Tôi thấy rằng ít nhất trong Magento 2.2 quan trọng được đưa vào tải của ResourceModel, vì vậy không nên sử dụng trực tiếp các phương thức ResourceModel, phải không?
Jāni Elmeris

Hiện tại, chúng ta có thể tải Mô hình một cách an toàn bằng load()phương pháp Mô hình tài nguyên . Mô hình tài nguyên gọi các phương thức của mô hình từ phương thức riêng load(): $model->beforeLoad() { $this->_beforeLoad() }$model->afterLoad() { $this->_afterLoad() }
sergei.sss

-1

Tôi nghĩ rằng tuyên bố sau đây là không hợp lệ.

Why not using the resource model load

chúng ta có thể tìm thấy Magento\Framework\EntityManager\Observerthư mục tất cả các sự kiện.

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.