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_component
pasta 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.xml
para 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 $customerGroupIds
que 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.
fonte
save handler
não está sendo chamado. O manipulador de leitura está sendo chamado. Seguindo a mesma abordagem. o que estou perdendo?Respostas:
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 usandoMagento\Cms\Model\Page\DataProvider
. Quando olhei para essa classe, notei um método chamadogetData()
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
ReadHandler
em consideração. Eu olhei para a coleção, ogetItems()
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
:E meu código de plug-in:
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?
fonte
hydratorPool
bemattributePool
, o manipulador de leitura está sendo chamado, mas não o manipulador de salvamento. Qualquer ideia?Em seu ResourceModel \ Page, você deve adicionar a função save enitityManager; o problema funcionou com o seguinte código:
fonte