Magento 2: conjunto de extensões, leia manipuladores e salve manipuladores

9

Alguém pode me explicar como usar o ReadHandler, SaveHandler e o uso do EntityManager / ExtensionPool?

Estou tentando entender, mas não consigo entender como implementá-lo. Se bem entendi, elas podem ser usadas para executar operações persistentes adicionais em objetos, como a criação de relações muitos-para-muitos, como são usadas no módulo CMS para vincular a entidade à loja.

Estou tentando fazer a mesma coisa relacionando outra entidade às páginas do CMS, mas não consigo fazê-lo funcionar. Ou seja, se eu estiver usando esse padrão de design corretamente.

Alguém pode compartilhar alguma luz sobre isso? Sinto muito, não posso compartilhar algum código neste momento, pois não estou no meu trabalho.

Edição: Este é o código que estou usando atualmente:

Eu adicionei cms_page_form.xmlà view/adminhtml/ui_componentpasta dos meus módulos , por isso tenho uma guia extra que exibe os grupos de clientes:

<?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>

Isso funciona; a guia é renderizada e os grupos de clientes são exibidos. Nenhum é selecionado por padrão.

Esta é a minha entrada no meu global di.xmlpara registrar meus manipuladores de salvar e ler. Minha inspiração foi ver como as lojas são salvas nas páginas do 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>

Este é o meu manipulador de salvamento:

<?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;
    }
}

Até este ponto, tudo funciona. Se eu selecionar grupos de clientes no administrador, o manipulador de salvamento será executado e as linhas apropriadas serão adicionadas ao banco de dados.

Este é o meu manipulador de leitura:

<?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;
    }
}

É aqui que estou preso. O manipulador trabalha e é executado. Se eu executar uma var_dump()em $customerGroupIdsque eles são preenchidos com os resultados corretos do banco de dados.

No entanto, no adminhtml, nenhum dos grupos de clientes na seleção múltipla é selecionado. Acho que estou muito perto de resolver esse problema, mas não consigo entender o que estou fazendo de errado. Minha coragem me diz que pode ter algo a ver com como eu declarei a seleção múltipla cms_page_form.xml, mas não tenho certeza do que é.

A propósito, este é um exemplo do esquema de banco de dados:

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

Qualquer ajuda seria muito apreciada.

Giel Berkers
fonte
Estou usando a abordagem de salvamento, como você, usei a referência do módulo CMS Page. Mas SaveHandler e ReadHandler não estão funcionando no meu caso. Você tem alguma idéia sobre isso?
Gaurav Khatri
Meu save handlernão está sendo chamado. O manipulador de leitura está sendo chamado. Seguindo a mesma abordagem. o que estou perdendo?
Adarsh ​​Khatri

Respostas:

3

Encontrei uma resposta na minha própria pergunta (embora não tenha certeza se é a resposta):

O manipulador de leitura funciona conforme o esperado e garante que os dados sejam adicionados ao meu modelo se eu o carregar (por exemplo) usando um repositório.

Então isso me deixou com o admingrid. Depois de examinar o original cms_page_form.xml, notei que os dados do formulário foram preenchidos usando Magento\Cms\Model\Page\DataProvider. Quando olhei para essa classe, notei um método chamado getData()que usa a coleção para buscar as entidades, não o repositório. Provavelmente porque o provedor de dados é um conceito geral que também pode ser usado em grades e outras coisas (me corrija se estiver errado).

E a coleção não levou isso ReadHandlerem consideração. Eu olhei para a coleção, o getItems()método e outras coisas, mas não consegui encontrar uma maneira adequada de adicionar meu atributo personalizado.

Então acabei escrevendo um plugin para 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>

E meu código de plug-in:

/**
 * @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;
}

Portanto, isso funciona agora, mas não tenho certeza se essa é a maneira correta - Magento - de como lidar com isso. Alguém pode compartilhar algumas idéias sobre isso?

Giel Berkers
fonte
11
Eu acho que você está sentindo falta do HydratorPool :)
Keyur Shah
@KeyurShah eu entendi hydratorPoolbem attributePool, o manipulador de leitura está sendo chamado, mas não o manipulador de salvamento. Qualquer ideia?
Adarsh ​​Khatri
0

Em seu ResourceModel \ Page, você deve adicionar a função save enitityManager; o problema funcionou com o seguinte código:

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;
    }
huuthai tran
fonte