Magento 2: extensionpool, leer controladores y guardar controladores


9

¿Alguien puede explicarme cómo usar ReadHandler, SaveHandler y el uso de EntityManager / ExtensionPool?

Estoy tratando de entenderlo, pero no puedo entender cómo implementarlo. Si entiendo correctamente, estos se pueden usar para realizar operaciones persistentes adicionales en los objetos, como crear relaciones de muchos a muchos, como se usan en el módulo CMS para vincular la entidad a la tienda.

Estoy tratando de hacer lo mismo relacionando otra entidad con las páginas de CMS, pero parece que no puedo hacer que funcione. Es decir, si estoy usando este patrón de diseño correctamente.

¿Alguien puede compartir algo de luz sobre esto? Lo siento, no puedo compartir un código en este momento, ya que no estoy en mi trabajo.

EDITAR: Este es el código que estoy usando actualmente:

He agregado cms_page_form.xmla la view/adminhtml/ui_componentcarpeta de mis módulos , por lo que tengo una pestaña adicional que muestra los 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>

Esto funciona; la pestaña se representa y se muestran los grupos de clientes. Ninguno está seleccionado por defecto.

Esta es mi entrada en mi global di.xmlpara registrar mis controladores de guardar y leer. Mi inspiración fue ver cómo se guardan las tiendas en las páginas de 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 es mi controlador de guardado:

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

Hasta este punto todo funciona. Si selecciono grupos de clientes en el administrador, el controlador de guardado se ejecuta y las filas adecuadas se agregan a la base de datos.

Este es mi controlador de lectura:

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

Aquí es donde estoy atrapado. El controlador funciona y se ejecuta. Si realizo un var_dump()encendido $customerGroupIds, se rellenan con los resultados correctos de la base de datos.

Sin embargo, en adminhtml, ninguno de los grupos de clientes en la selección múltiple está seleccionado. Creo que estoy realmente cerca de resolver esto, pero no puedo entender qué estoy haciendo mal. Mis agallas me dicen que podría tener algo que ver con la forma en que declaró la selección múltiple cms_page_form.xml, pero no estoy seguro de qué es.

Por cierto, este es un ejemplo del esquema de base de datos:

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

Cualquier ayuda sería muy apreciada.


Estoy usando el enfoque de guardar, como usted usé la referencia del módulo de página CMS. Pero SaveHandler y ReadHandler no funcionan en mi caso. Tienes alguna idea sobre eso.
Gaurav Khatri

Mi save handlerno es llamado. Se llama a Read Handler. Siguiendo el mismo enfoque. ¿Qué me estoy perdiendo?
Adarsh ​​Khatri

Respuestas:


3

Encontré una respuesta en mi propia pregunta (aunque no estoy seguro de si es la respuesta):

El controlador de lectura funciona como se espera y se asegura de que los datos se agreguen a mi modelo si lo cargo (por ejemplo) usando un repositorio.

Entonces eso me dejó con el admingrid. Después de mirar el original cms_page_form.xml, noté que los datos del formulario se rellenaban mediante el uso Magento\Cms\Model\Page\DataProvider. Cuando miré esta clase, noté un método llamado getData()que usa la colección para buscar las entidades, no el repositorio. Probablemente porque el proveedor de datos es un concepto general que también se puede usar en cuadrículas y otras cosas (corríjame si me equivoco).

Y la colección no tuvo ReadHandleren cuenta. Miré la colección y el getItems()método y esas cosas, pero no pude encontrar una manera adecuada de agregar mi atributo personalizado.

Así que terminé escribiendo un complemento 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>

Y mi código de complemento:

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

Así que esto funciona ahora, pero no estoy seguro de si esta es la forma correcta, Magento, de cómo lidiar con esto. ¿Alguien puede compartir algunos pensamientos sobre esto?


1
Creo que te falta HydratorPool :)
Keyur Shah

@KeyurShah he conseguido hydratorPool, así como attributePool, manejador de lectura está recibiendo llamadas, pero no guardar manejador. ¿Alguna idea?
Adarsh ​​Khatri

0

En su ResourceModel \ Page, debe agregar la función save enitityManager; el problema funcionó con el siguiente 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;
    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.