วิธีที่ดีที่สุดในการโหลดโมเดลที่กำหนดเองใน Magento 2


15

เพราะมันยากสำหรับฉันที่จะหาวิธีที่ถูกต้องด้านล่างคุณจะได้พบกับแนวปฏิบัติที่ดีที่สุดที่ฉันสร้างขึ้นมา สนุกแก้ไขภาษาอังกฤษของฉันถ้าจำเป็นและบอกฉันฉันผิดถ้าฉันเป็น :)

แก้ไข: ... และฉันพบว่าฉันผิดในบางแง่มุม ดังนั้นฉันจึงอัพเดทโพสต์ต้นฉบับหลังจากคำตอบของราฟาเอลช่วยให้ฉันเข้าใจมากขึ้น ขอบคุณเขา!

แนวคิดที่ใช้ด้านล่าง :

มันจะง่ายขึ้นสำหรับคุณที่จะเข้าใจรหัสและคำอธิบายด้านล่างหากคุณพอใจกับแนวคิดเหล่านี้:

  • การฉีดขึ้นอยู่กับ (เป็นทุก ๆ $this->variableตัวแปรในรหัสจะถูกฉีด)
  • สัญญาบริการและพื้นที่เก็บข้อมูล
  • โรงงาน

บริบท :

เพื่อให้มีบริบทมากขึ้นลองจินตนาการว่าเรามีโมดูลที่สร้างอย่างถูกต้องด้วย:

  • คลาสบล็อก CustomBlock ที่มีเมธอด getCustomModel($id) ,
  • เมธอดนี้ส่งคืนออบเจกต์ CustomModel โดยอิงจาก id ที่ส่งเป็น param
  • ประเภท CustomModel สอดคล้องกับรูปแบบใน \Vendor\Module\Model\CustomModel
  • โมเดลนี้มาพร้อมกับโมเดลทรัพยากร (ใน \Vendor\Module\Model\ResourceModel\CustomModel )
  • และด้วยที่เก็บ (ใน\Vendor\Module\Model\CustomModelRepository)

คำถาม :

  • แนวปฏิบัติที่ดีที่สุดในการปล่อยให้ทุกสิ่งโหลดวัตถุ CustomModel คืออะไร

คุณไม่สามารถใช้load()จากวัตถุ CustomModel เนื่องจากวิธีนี้เลิกใช้แล้ว

แนวปฏิบัติที่ดีบอกว่าคุณต้องใช้ CustomModel Service Contract สัญญาบริการคือส่วนต่อข้อมูล (เช่น CustomModelInterface) และส่วนต่อประสานบริการ (เช่น CustomModelRepositoryInterface) ดังนั้นบล็อกของฉันมีลักษณะดังนี้:

/ ** @var SlideRepositoryInterface * /
ป้องกัน $ slideRepository;

/ **
 * ตัวสร้าง CustomBlock
 * ...
 * @param CustomModelRepositoryInterface $ customModelRepository
 * ...
 * /
ฟังก์ชั่นสาธารณะ __ โครงสร้าง (
...
CustomModelRepositoryInterface $ customModelRepository
...
) {
    $ this-> customModelRepository = $ customModelRepository;
}

ฟังก์ชั่นสาธารณะ getCustomModel ($ id) {
    ส่งคืน $ this-> customModelRepository-> get ($ id);
}

ก่อนอื่นเราจะฉีดCustomModelRepositoryInterfaceวัตถุในตัวสร้างและเราใช้มันในgetCustomModel()วิธีการของเรา

ในชั้นเรียนApi\CustomModelRepositoryInterfaceมีไม่มาก โดยทั่วไป ( แต่ไม่มีอะไรที่ทำให้คุณไม่สามารถที่จะทำแตกต่างกัน) คุณจะบอกวิธีการขั้นพื้นฐาน: get, getList, save, ,delete deleteByIdสำหรับจุดประสงค์ของหัวข้อนี้ด้านล่างเป็นเพียงgetการประกาศวิธีการ:

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

ตกลง แต่ถ้า CustomModel Interface ของฉันถูกเรียกโดยการฉีดพึ่งพาในตัวสร้างบล็อกของฉันรหัสอยู่ที่ไหน สำหรับคำตอบของคำถามนี้คุณต้องอธิบายให้ Magento ทราบว่าชั้นเรียนใดที่ใช้อินเทอร์เฟซนี้ ในไฟล์ etc / di.xml ของโมดูลคุณต้องเพิ่ม:

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

ดังนั้นCustomModelRepositoryInterfaceระดับเป็นอินเตอร์เฟซให้บริการ ในการดำเนินการนั้นคุณจะต้องนำไปใช้กับ data interface (อย่างน้อยVendor\Module\Api\Data\CustomModelInterfaceและVendor\Module\Api\Data\CustomModelSearchResultsInterface) โมเดลของคุณจะต้องใช้งานVendor\Module\Api\Data\CustomModelInterfaceและเพิ่ม<preference ... />บรรทัดสำหรับแต่ละอินเตอร์เฟสของคุณ ในที่สุดเมื่อใดก็ตามที่คุณใช้สัญญาบริการคิดในmySomethingInterfaceอีกต่อไปในmySomething: ให้วีโอไอพีใช้di.xmlกลไกการตั้งค่า

ตกลงจะเกิดอะไรขึ้นต่อไป เมื่อเราฉีดCustomModelRepositoryInterfaceตัวสร้างบล็อกเราจะได้รับCustomModelRepositoryวัตถุ มีการใช้วิธีการประกาศในCustomModelRepository CustomModelRepositoryInterfaceดังนั้นเรามีสิ่งนี้ในVendor\Module\Model\CustomModelRepository:

ฟังก์ชั่นสาธารณะได้รับ ($ id) {
    $ customModel = $ this-> customModelFactory-> create ();
    $ customModel-> โหลด ($ ID);
    if (! $ customModel-> getId ()) {
      โยน NoSuchEntityException ใหม่ (__ ('CustomModel ที่มี id "% 1" ไม่มีอยู่', $ id));
    }
    ส่งกลับ $ customModel;
}

เรากำลังทำอะไร เราสร้างCustomModelวัตถุเปล่าด้วยโรงงาน ต่อไปเราจะโหลดข้อมูลCustomModelโดยใช้วิธีการโหลดโมเดล ต่อไปเราจะคืนค่า a NoSuchEntityExceptionหากเราไม่สามารถโหลดCustomModelด้วย id ใน params แต่ถ้าทุกอย่างโอเคเราคืนวัตถุต้นแบบและชีวิตดำเนินต่อไป

แต่ว้าว ... ! ในตัวอย่างนี้คืออะไร

$customModel->load($id);

ไม่ใช่loadวิธีการที่เลิกใช้แล้วมากกว่าตอนต้นใช่ไหม? ใช่แล้ว. ฉันคิดว่ามันน่าละอาย แต่คุณต้องใช้มันตั้งแต่วิธีการโหลด () นี้มีกิจกรรมบางอย่างที่จัดส่งและนักพัฒนาสามารถฟังพวกเขา (ดูคำตอบของราฟาเอลด้านล่าง)

ในอนาคตเราจะได้รับการช่วยเหลือจาก Entity Manager นี่เป็นอีกเรื่องหนึ่งที่เป็นแนวคิดใหม่ของ Magento 2 แต่หากคุณต้องการจับตาดู Entity Manager จะถูกนำไปใช้ใน Resource Model ของ CMS Page (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;
}

คำตอบ:


16

การปฏิบัติที่ดีที่สุด: ผ่านสัญญาบริการ

แนวปฏิบัติที่ดีที่สุดคือการใช้สัญญาบริการทุกครั้งที่ทำได้ คุณสามารถค้นหารายการเหตุผลได้ที่นี่: วีโอไอพี 2: ประโยชน์ของการใช้สัญญาบริการคืออะไร

สำหรับรายละเอียดเกี่ยวกับวิธีการใช้สัญญาบริการฉันขอแนะนำให้คุณตรวจสอบหัวข้อนี้: วิธีการใช้สัญญาบริการสำหรับโมดูลที่กำหนดเองใน Magento 2

หากไม่มีสัญญาบริการ

หากไม่มีสัญญาการให้บริการคุณควรใช้getวิธีการที่เก็บแบบจำลอง เมื่อใช้วิธีนี้คุณจะได้รับประโยชน์จากระบบแคชวีโอไอพีตัวอย่างเช่นในCategoryRepositoryชั้นเรียน

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()วิธีการเลิก

Magento 2 กำลังเคลื่อนตัวออกจากระบบ CRUD มาตรฐานอย่างช้าๆโดยการวางระบบการสืบทอดและการนำมันไปใช้ผ่านการประพันธ์โดยใช้ 2.1 EntityManager ใหม่คุณสามารถหารายละเอียดได้ที่นี่: Magento 2.1: การใช้ตัวจัดการเอนทิตี

นอกจากนี้ฉันขอแนะนำให้คุณอ่านหัวข้อที่น่าสนใจเกี่ยวกับวิธีการ CRUD ที่เลิกใช้แล้ว: วิธีการบันทึกและโหลดที่คัดค้านในรูปแบบนามธรรม

ทำไมไม่ใช้โหลดโมเดลทรัพยากร

เหตุผลหลักคือถ้าคุณใช้loadวิธีการโมเดลทรัพยากรคุณจะข้ามส่วนสำคัญของระบบการโหลดที่ใช้ในloadวิธีการแบบดู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;
}

การเรียกใช้loadเมธอดโมเดลรีซอร์สโดยตรงจะมีผลกระทบต่อไปนี้:

  • _beforeLoad ไม่ได้เรียกว่า: ดังนั้นโมเดลโหลดก่อนที่เหตุการณ์จะไม่ถูกส่ง
  • _afterLoad ไม่ถูกเรียกใช้: ดังนั้นโมเดลโหลดหลังจากเหตุการณ์ไม่ถูกส่ง
  • ข้อมูลที่เก็บไว้จะไม่ได้รับการปรับปรุงซึ่งอาจทำให้เกิดปัญหาต่าง ๆ (เช่นถ้าคุณโทรprepareDataForUpdateจากMagento\Framework\Model\ResourceModel\Db\AbstractDb)

ขอบคุณกราฟิลส์ทุกสิ่งที่คุณพูดมีเหตุผลและทำให้ความรู้ของฉันสมบูรณ์ แต่ฉันไม่เข้าใจว่าทำไม KAndy แสดงความคิดเห็น (ภายใต้คำตอบของเขา) ที่ Marius สามารถใช้วิธีโหลด () ของโมเดลโมดูลทรัพยากรที่กำหนดเองของเขา มันอยู่ใน [ magento.stackexchange.com/questions/114929/…บันทึกและโหลดเมธอดในรูปแบบนามธรรม) ความคิดใด ๆ
Nicolas PERNOT

@NicolasPERNOT โดยทั่วไป KAndy อธิบายว่าเป้าหมายคือมี SL (Service Layer) สำหรับทุกโมดูลและนี่คือสิ่งที่ต้องใช้ทุกครั้งที่คุณต้องโหลดเอนทิตี ฉันแนะนำให้คุณแสดงความคิดเห็นโดยกล่าวถึงเขาบางทีเขาอาจจะสามารถสอนคุณได้เพราะเขาเป็นพนักงาน Magento Inc ที่ฉันคิดว่า
Raphael ที่ Digital Pianism

ในที่สุดฉันก็อัพเดตโพสต์ดั้งเดิมของฉัน ขอบคุณกราฟิลส์สำหรับความช่วยเหลือของคุณ
Nicolas PERNOT

ฉันเห็นว่าอย่างน้อยใน Magento 2.2 ที่สำคัญรวมอยู่ในการโหลดของ ResourceModel ดังนั้นจึงไม่เป็นไรที่จะใช้วิธีการ ResourceModel โดยตรงใช่ไหม?
Jānis Elmeris

ขณะนี้เราได้อย่างปลอดภัยสามารถโหลดรูปแบบการใช้ทรัพยากรแบบload()วิธีการ ตัวแบบทรัพยากรเรียกวิธีการของตัวแบบจากวิธีของตัวเองload(): $model->beforeLoad() { $this->_beforeLoad() }และ$model->afterLoad() { $this->_afterLoad() }
sergei.sss

-2

ฉันคิดว่าข้อความต่อไปนี้ไม่ถูกต้องในขณะนี้

Why not using the resource model load

เราสามารถค้นหาMagento\Framework\EntityManager\Observerโฟลเดอร์เหตุการณ์ทั้งหมด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.