อะไรและทำไมเป็นวิธีที่เหมาะสมในการโหลดแบบจำลอง


9

ฉันมีประสบการณ์ค่อนข้างมากกับ Magento แต่ฉันรู้ว่าฉันไม่เข้าใจวิธีการโหลดแบบจำลองที่ถูกต้องและทำไม ฉันได้อ่านทุกสิ่งที่ฉันสามารถทำได้เกี่ยวกับหัวข้อนี้ แต่ผู้คนอธิบายสิ่งต่าง ๆ เช่นนี้ไม่เคยลึกพอที่จะอธิบายได้ทำไมต้องใช้วิธีการเฉพาะนี้แทนวิธีอื่น สมมติว่าไม่มีที่เก็บสำหรับรุ่นที่ฉันต้องการโหลด

จนถึงตอนนี้ฉันมักจะใช้ model ในตัวสร้างแล้วก็โหลดมัน

public function __construct(
    \Vendor\Module\Model\Something $somethingModel
) {
    $this->somethingModel = $somethingModel;
}

public function getTestById($id) {
    return $this->somethingModel->load($id);
}

และมันก็ใช้งานได้ตามปกติฉันก็ค่อนข้างแน่ใจว่ามันหรืออย่างน้อยก็ถูกใช้ในแกนกลางทั่วไป

แต่ฉันเห็นเพื่อนร่วมงานคนหนึ่งของฉันใช้

modelFactory->create()->load($id)

เท่าที่ฉันเข้าใจโรงงานกำลังถูกใช้เพื่อสร้างเอนทิตีใหม่ตัวอย่างเช่นถ้าฉันต้องการสร้างผลิตภัณฑ์ใหม่จากนั้นฉันสามารถสร้างโรงงานเติมข้อมูลด้วยข้อมูลแล้วบันทึก แต่แล้วอีกครั้งฉันเริ่มค้นคว้าหัวข้อและฉันเห็นตัวอย่างจาก Fabian Schmengler ( เมื่อเราควรใช้ Repository และ Factory ใน Magento 2? ) ผู้โหลดแบบจำลองด้วยวิธีนี้และไม่สนับสนุนคนอื่นจากการโหลดแบบจำลองเขาไม่ได้ทำ ไม่อธิบายว่าทำไมนอกจากบอกว่ามันไม่ใช่ส่วนหนึ่งของสัญญาการบริการ เท่าที่ฉันเข้าใจที่เก็บข้อมูลเป็นส่วนหนึ่งของสัญญาบริการดังนั้นฉันจึงไม่เห็นการเชื่อมต่อใด ๆ ที่นี่เมื่อพูดถึงการโหลดรุ่นที่ไม่สามารถใช้งานได้ผ่านที่เก็บข้อมูล

เพื่อเพิ่มความสับสนให้มากขึ้นฉันได้ค้นพบวิธีการโหลดโมเดลโดยรับ resourceModel จาก modelFactory ที่สร้างขึ้นมันถูกนำเสนอโดย Vinai Kopp ( วิธีการใช้สัญญาบริการสำหรับโมดูลที่กำหนดเองใน Magento 2 ) และตอนนี้ฉัน สูญเสียไปอย่างสิ้นเชิงเนื่องจากฉันได้อ่านเสมอว่าฉันไม่ควรใช้โมเดลทรัพยากรโดยตรง

ใช่มีใครบอกฉันว่าวิธีไหนที่ถูกต้องและทำไมฉันจึงควรใช้วิธีนี้แทนวิธีอื่นทั้งหมด


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

1
เป็นคำถามที่ดีฉันจะพยายามหาเวลาตอบรายละเอียดในภายหลัง ฉันสามารถบอกคุณได้มากว่า: มันเป็นกรณีที่แตกต่างกันถ้าคุณโหลดรุ่นของคุณเอง (ตัวอย่างโดย Vinai) หรือโมเดลของโมดูลหลักหรือโมดูลของบุคคลที่สาม (คำตอบของฉัน) นอกจากนี้การฉีดโมเดลผ่าน Constructor จะให้อินสแตนซ์เดียวกันทุกครั้งซึ่งอาจทำให้เกิดผลข้างเคียงที่ไม่พึงประสงค์
Fabian Schmengler

คำตอบ:


12

ขั้นตอนแรกที่คุณควรตรวจสอบโมเดลที่เป็นปัญหาคือ: มีสัญญาบริการพื้นที่เก็บข้อมูลหรือไม่? ถ้าเป็นเช่นนั้นให้ใช้เพราะสัญญาบริการนั้นผูกมัดกับการกำหนดเวอร์ชันแบบ semantic และจะยังคงทำตัวเหมือนที่ควรทำจนกว่า Magento 3.x จะออกมา ไม่จำเป็นต้องพูดเมื่อคุณสร้างโมดูลของคุณเองด้วยโมเดลที่ต้องมีการคงอยู่คุณควรเขียนที่เก็บสำหรับสิ่งนั้น

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->productRepository = $productRepository;
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $this->productRepository->save($product);
}

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

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product $productResource,
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productResource = $productResource;
    $this->productFactory = $productFactory;
    ...
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $product = $this->productFactory->create();
    $this->productResource->save($product);
}

"ดังนั้นประโยชน์ใดที่นำสัญญาบริการ / พื้นที่เก็บข้อมูลมาเหนือรูปแบบทรัพยากร" คุณอาจถาม ในทางทฤษฎีแล้วตัวแบบทรัพยากรควรจะรับผิดชอบต่อการคงอยู่ของตัวแบบข้อมูลเท่านั้นในขณะที่ที่เก็บข้อมูลยังคำนึงถึงงานเพิ่มเติมที่เกี่ยวข้องกับการบันทึกเอนทิตี คิดเกี่ยวกับการอัปเดตดัชนีการสร้างความสัมพันธ์กับเอนทิตีอื่น ๆ ฯลฯ นี่คือทฤษฎีแม้ว่าในชีวิตจริงเส้นเหล่านี้มักจะเบลอค่อนข้างบ่อย แต่เป็นการดีสำหรับตัวคุณเองที่จะต้องคำนึงถึงเรื่องนี้

คุณไม่ควรใช้โมเดลโดยตรงsave()- load()วิธีการ มีการคัดค้านเนื่องจากความหมายไม่ถูกต้อง คิดในลักษณะที่เป็นของแข็ง:

  • (ข้อมูล) โมเดลควรรับผิดชอบเฉพาะการเก็บข้อมูลเท่านั้น
  • แบบจำลองทรัพยากรควรรับผิดชอบต่อการคงอยู่ของข้อมูลดังกล่าว
  • ที่เก็บควรรับผิดชอบการสื่อสารทั้งภายในและภายนอกโมดูลสำหรับการดำเนินการเก็บรักษา

และนั่นคือจุดสุดท้ายที่สร้างความแตกต่าง: เมื่อสื่อสารกับโมดูลอื่น ๆ ในโลกอุดมคติไม่ควรต้องพึ่งพาตรรกะถาวรของโมดูลนั้น (หรือวิธีการสาธารณะใด ๆ สำหรับเรื่องนั้น แต่เป็นการอภิปรายอื่น) แต่ใช้ฟังก์ชั่นที่ให้ไว้โดยสัญญาบริการของโมดูลเท่านั้น

สรุปแล้ว

เพื่อตอบคำถามของคุณ: ตามลำดับที่ต้องการ วิธีที่ถูกต้องในการโหลดแบบจำลองคือ:

  • หากมี Repository ให้โหลดโดยใช้ Repository
  • เฉพาะในกรณีที่ไม่มีพื้นที่เก็บข้อมูลใช้โมเดลทรัพยากร (รวมกับโรงงาน)

1
ตกลงดังนั้นถ้าฉันทำตามถูกต้อง - เมื่อฉันต้องการแก้ไข / เพิ่มข้อมูลใหม่และบันทึกลงในฐานข้อมูลแล้วฉันควรใช้ Resource Model และฉันต้องการโหลดข้อมูลไปยังหน่วยความจำแล้วฉันควรใช้ Factory? ดังนั้นมีสถานการณ์ใดบ้างที่ฉันควรใช้โมเดลปกติโดยตรง (เช่นเดียวกับการใช้คลาสโมเดลในคอนสตรัคเตอร์)?
czs

@czs คุณถูกต้องฉันได้เพิ่มตัวอย่างอธิบายเพิ่มเติมสำหรับการโหลดแบบจำลองสำหรับเดียวกัน
Milind Singh

2
  • ModelsData Interface นั้นใช้เพื่อเก็บข้อมูลในวัตถุเช่นsetและ getข้อมูลสำหรับแถว
  • ResourceModelsเป็นกลไกที่รับผิดชอบในการเก็บรักษาข้อมูลเช่นดำเนินการแบบสอบถาม SQL เพื่อจริงsaveหรือloadข้อมูลลงในModelวัตถุ

วิธีที่ถูกต้องในการloadและsaveควรเป็นโดยการสร้างที่เก็บหรือโหลดจากทรัพยากรดังต่อไปนี้:

namespace MyVendor\MyModule\Model;

class QueueRepository impliments \MyVendor\MyModule\Api\QueueRepositoryInterface
{

    /** @var \MyVendor\MyModule\Model\ResourceModel\Queue  */
    public $resource;

    /** @var \MyVendor\MyModule\Model\QueueFactory  */
    public $modelFactory;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Queue $resource,
        \MyVendor\MyModule\Model\QueueFactory $modelFactory
    ) {
        $this->resource = $resource;
        $this->modelFactory = $modelFactory;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @return $queue
     * @throws \Exception
     */
    public function save(\MyVendor\Integrator\Api\Data\QueueInterface $queue)
    {
        $this->resource->save($queue);
        return $queue;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @param int $id
     * @return $queue
     * @throws \Exception
     */
    public function load(\MyVendor\MyModule\Api\Data\QueueInterface $queue, $id)
    {
        $this->resource->load($queue, $id);
        return $queue;
    }

    public function getById($id)
    {
        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
    }
}

ที่นี่\MyVendor\MyModule\Api\Data\QueueInterfaceมีQueueรุ่นของimplimented

ดังนั้นเบื้องหลังเรากำลังสร้างModelวัตถุจากนั้นloadingตามResourceModelวัตถุ นี่เป็นวิธีที่ถูกต้องในการโหลดหรือบันทึก

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.