Magento 2:扩展池,读取处理程序和保存处理程序


9

谁能向我解释如何使用ReadHandler,SaveHandler以及EntityManager / ExtensionPool的使用?

我正在努力解决这个问题,但是我不太了解如何实现它。如果我理解正确,它们可以用于在对象上执行其他持久性操作,例如创建多对多关系,就像在CMS模块中使用它们将实体链接到商店一样。

我正在尝试通过将另一个实体与CMS页面相关联来做同样的事情,但是我似乎无法使其正常工作。也就是说,如果我正确使用此设计模式。

谁能对此发表一些看法?很抱歉,由于我不在上班时间,目前无法共享一些代码。

编辑:这是我当前正在使用的代码:

我已将添加cms_page_form.xml到模块的-文件view/adminhtml/ui_component夹中,因此我还有一个附加选项卡,用于显示客户组:

<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="customer_groups">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="collapsible" xsi:type="boolean">true</item>
                <item name="label" xsi:type="string" translate="true">Customer Groups</item>
                <item name="sortOrder" xsi:type="number">100</item>
            </item>
        </argument>
        <field name="customer_groups">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Magento\Customer\Model\Config\Source\Group\Multiselect</item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">int</item>
                    <item name="label" xsi:type="string" translate="true">Customer Groups</item>
                    <item name="formElement" xsi:type="string">multiselect</item>
                    <item name="source" xsi:type="string">page</item>
                    <item name="dataScope" xsi:type="string">customer_group</item>
                    <item name="default" xsi:type="string">0</item>
                </item>
            </argument>
        </field>
    </fieldset>
</form>

这有效;将显示该选项卡,并显示客户组。默认情况下未选择任何内容。

这是我在全局di.xml变量中注册我的保存和读取处理程序的条目。我的灵感来自查看如何在CMS页面上保存商店:

<type name="Magento\Framework\EntityManager\Operation\ExtensionPool">
    <arguments>
        <argument name="extensionActions" xsi:type="array">
            <item name="Magento\Cms\Api\Data\PageInterface" xsi:type="array">
                <item name="read" xsi:type="array">
                    <item name="customerGroupReader"
                          xsi:type="string">Vendor\Module\Model\ResourceModel\Page\Relation\CustomerGroup\ReadHandler</item>
                </item>
                <item name="create" xsi:type="array">
                    <item name="customerGroupCreator"
                          xsi:type="string">Vendor\Module\Model\ResourceModel\Page\Relation\CustomerGroup\SaveHandler</item>
                </item>
                <item name="update" xsi:type="array">
                    <item name="customerGroupUpdater"
                          xsi:type="string">Vendor\Module\Model\ResourceModel\Page\Relation\CustomerGroup\SaveHandler</item>
                </item>
            </item>
        </argument>
    </arguments>
</type>

这是我的保存处理程序:

<?php

namespace Vendor\Module\Model\ResourceModel\Page\Relation\CustomerGroup;

use Magento\Framework\EntityManager\Operation\ExtensionInterface;
use Magento\Cms\Model\ResourceModel\Page as PageResource;

/**
 * Class SaveHandler
 */
class SaveHandler implements ExtensionInterface
{
    /**
     * @var PageResource
     */
    protected $pageResource;

    /**
     * SaveHandler constructor.
     * @param PageResource $pageResource
     */
    public function __construct(
        PageResource $pageResource
    )
    {
        $this->pageResource = $pageResource;
    }

    /**
     * @param \Magento\Cms\Model\Page $entity
     * @param array $arguments
     */
    public function execute($entity, $arguments = [])
    {
        $connection = $this->pageResource->getConnection();

        // First delete all existing relations:
        $connection->delete('cms_page_customer_group', sprintf('page_id = %d', (int) $entity->getId()));

        // Re-create the relations:
        foreach ($entity->getData('customer_group') as $customerGroupId) {
            $connection->insert('cms_page_customer_group', [
                'page_id' => (int) $entity->getId(),
                'customer_group_id' => (int) $customerGroupId
            ]);
        }

        return $entity;
    }
}

到目前为止,一切正常。如果我在管理员中选择客户组,则将执行保存处理程序,并将适当的行添加到数据库中。

这是我的读取处理程序:

<?php

namespace Vendor\Module\Model\ResourceModel\Page\Relation\CustomerGroup;

use Magento\Framework\EntityManager\Operation\ExtensionInterface;
use Magento\Cms\Model\ResourceModel\Page as PageResource;

/**
 * Class ReadHandler
 */
class ReadHandler implements ExtensionInterface
{
    /**
     * @var PageResource
     */
    protected $pageResource;

    /**
     * SaveHandler constructor.
     * @param PageResource $pageResource
     */
    public function __construct(
        PageResource $pageResource
    ) {
        $this->pageResource = $pageResource;
    }

    /**
     * @param \Magento\Cms\Model\Page $entity
     * @param array $arguments
     */
    public function execute($entity, $arguments = [])
    {
        if ($entity->getId()) {
            $connection = $this->pageResource->getConnection();

            $customerGroupIds = $connection
                ->fetchCol(
                    $connection
                        ->select()
                        ->from('cms_page_customer_group', ['customer_group_id'])
                        ->where('page_id = ?', (int)$entity->getId())
                );

            $entity->setData('customer_group', $customerGroupIds);
        }

        return $entity;
    }
}

这就是我卡住的地方。处理程序工作并执行。如果我执行var_dump()$customerGroupIds则会从数据库中填充正确的结果。

但是,在adminhtml中,没有选择多选中的任何客户组。我想我真的很想解决这个问题,但是我不知道自己在做什么错。我的胆量告诉我,这可能与我在中声明multiselect的方式有关cms_page_form.xml,但是我不确定它是什么。

顺便说一下,这是数据库方案的示例:

|page_id|customer_group_id|
|-------|-----------------|
|29     |1                |
|29     |2                |

任何帮助将不胜感激。


我使用的是保存方法,就像您使用CMS页面模块中的引用一样。但是SaveHandler和ReadHandler都无法正常工作。您对此有任何想法吗?
Gaurav Khatri

save handler没有接到电话。读取处理程序被调用。遵循相同的方法。我想念什么?
Adarsh Khatri

Answers:


3

我针对自己的问题找到了答案(尽管不确定是否答案):

读取处理程序按预期工作,并且确保在我使用存储库加载(例如)数据时将其添加到模型中。

这样就让我离开了admingrid。查看原始cms_page_form.xml文档后,我注意到使用填充了表单数据Magento\Cms\Model\Page\DataProvider。当我查看此类时,我注意到一个名为的方法getData(),该方法使用集合来获取实体,而不是存储库。可能是因为数据提供者是一个通用概念,也可以用在网格和其他东西中(如果我错了,请纠正我)。

并且集合没有考虑ReadHandler到这一点。我查看了集合以及getItems()-method和相关内容,但是找不到添加自定义属性的正确方法。

因此,我最终为编写了一个插件Magento\Cms\Model\Page\DataProvider::getData

di.xml

<!--
    Plugin to add customer_group to dataprovider:
-->
<type name="Magento\Cms\Model\Page\DataProvider">
    <plugin name="private_pages_cms_dataprovider"
            type="Vendor\Module\Plugin\Magento\Cms\Model\Page\DataProvider"/>
</type>

和我的插件代码:

/**
 * @param \Magento\Cms\Model\Page\DataProvider $subject
 * @param array $result
 * @return array
 */
public function afterGetData(\Magento\Cms\Model\Page\DataProvider $subject, array $result)
{
    foreach ($result as $pageId => &$data) {
        $data['customer_group'] = ...
    }
    return $result;
}

因此,这现在可行,但是我不确定这是否正确-Magento-如何处理此问题。谁能对此发表一些想法?


1
我认为您缺少
HydratorPool了

@KeyurShah我有hydratorPoolattributePool,读处理程序获取调用,但不保存处理。任何的想法?
Adarsh Khatri

0

在您的ResourceModel \ Page中,您应该添加功能保存enitityManager;该问题与以下代码一起工作:

namespace <your namespace>
use Magento\Framework\Model\AbstractModel;
use Magento\Framework\EntityManager\EntityManager;

     ...

    /**
     * @var EntityManager
     */
    protected $entityManager;


public function __construct(
        ...
        EntityManager $entityManager
    )
    {
        ...
        $this->entityManager = $entityManager;
        ...
    }
...
...

 /**
     * @param AbstractModel $object
     * @return $this
     * @throws \Exception
     */
    public function save(AbstractModel $object)
    {
        $this->entityManager->save($object);
        return $this;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.