Magento 2: Erweiterungspool, Handler lesen und Handler speichern


9

Kann mir jemand erklären, wie man ReadHandler, SaveHandler und den EntityManager / ExtensionPool benutzt?

Ich versuche, meinen Kopf darum zu wickeln, aber ich kann nicht ganz verstehen, wie ich es implementieren soll. Wenn ich das richtig verstehe, können diese verwendet werden, um zusätzliche persistente Vorgänge für Objekte auszuführen, z. B. das Erstellen von Viele-zu-Viele-Beziehungen, wie sie im CMS-Modul zum Verknüpfen der Entität mit dem Geschäft verwendet werden.

Ich versuche das Gleiche zu tun, indem ich eine andere Entität mit CMS-Seiten verknüpfe, aber ich kann es anscheinend nicht zum Laufen bringen. Das heißt, wenn ich dieses Entwurfsmuster richtig verwende.

Kann jemand etwas Licht darauf geben? Es tut mir leid, dass ich derzeit keinen Code freigeben kann, da ich nicht bei meiner Arbeit bin.

EDIT: Dies ist der Code, den ich derzeit verwende:

Ich habe cms_page_form.xmlden view/adminhtml/ui_componentOrdner meiner Module hinzugefügt, sodass ich eine zusätzliche Registerkarte habe, auf der die Kundengruppen angezeigt werden:

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

Das funktioniert; Die Registerkarte wird gerendert und die Kundengruppen werden angezeigt. Standardmäßig sind keine ausgewählt.

Dies ist mein Eintrag in meinem Global di.xml, um meine Save- und Read-Handler zu registrieren. Meine Inspiration war, wie Geschäfte auf CMS-Seiten gespeichert werden:

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

Dies ist mein sicherer Handler:

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

Bis zu diesem Punkt funktioniert alles. Wenn ich im Administrator Kundengruppen auswähle, wird der Save Handler ausgeführt und die richtigen Zeilen zur Datenbank hinzugefügt.

Dies ist mein Lesehandler:

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

Hier stecke ich fest. Der Handler arbeitet und wird ausgeführt. Wenn ich ein var_dump()On durchführe, werden $customerGroupIdssie mit den richtigen Ergebnissen aus der Datenbank gefüllt.

In der Adminhtml ist jedoch keine der Kundengruppen in der Mehrfachauswahl ausgewählt. Ich denke, ich bin sehr nahe daran, dieses Problem zu lösen, aber ich kann nicht herausfinden, was ich falsch mache. Mein Mut sagt mir, dass es etwas damit zu tun haben könnte, wie ich die Mehrfachauswahl deklariert habe cms_page_form.xml, aber ich bin mir nicht sicher, was es ist.

Dies ist übrigens ein Beispiel für das Datenbankschema:

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

Jede Hilfe wäre sehr dankbar.


Ich verwende den Speicheransatz, wie Sie die Referenz aus dem CMS-Seitenmodul verwendet habe. Aber SaveHandler und ReadHandler funktionieren in meinem Fall nicht. Hast du eine Idee dazu?
Gaurav Khatri

Mein save handlerwird nicht angerufen. Read Handler wird aufgerufen. Nach dem gleichen Ansatz. Was vermisse ich?
Adarsh ​​Khatri

Antworten:


3

Ich habe eine Antwort auf meine eigene Frage gefunden (obwohl ich nicht sicher bin, ob es die Antwort ist):

Der Read Handler funktioniert wie erwartet und stellt sicher, dass die Daten meinem Modell hinzugefügt werden, wenn ich sie (zum Beispiel) über ein Repository lade.

Das hat mich nur mit dem Admingrid zurückgelassen. Nachdem cms_page_form.xmlich das Original durchgesehen hatte, bemerkte ich, dass die Daten des Formulars mit verwendet wurden Magento\Cms\Model\Page\DataProvider. Als ich mir diese Klasse ansah, bemerkte ich eine Methode namens getData(), die die Sammlung verwendet , um die Entitäten abzurufen, nicht das Repository. Wahrscheinlich, weil der Datenprovider ein allgemeines Konzept ist, das auch in Grids und anderen Dingen verwendet werden kann (bitte korrigieren Sie mich, wenn ich falsch liege).

Und die Sammlung ReadHandlerberücksichtigte dies nicht . Ich habe mir die Sammlung und die getItems()Methode und das Zeug angesehen, aber ich konnte keinen geeigneten Weg finden, um mein benutzerdefiniertes Attribut hinzuzufügen.

Also habe ich ein Plugin für geschrieben 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>

Und mein Plugin-Code:

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

Das funktioniert jetzt, aber ich bin mir nicht sicher, ob dies der richtige - Magento - Weg ist, wie man damit umgeht. Kann jemand einige Gedanken dazu teilen?


1
Ich denke, Sie vermissen HydratorPool :)
Keyur Shah

@KeyurShah Ich habe hydratorPoolso gut wie attributePool, lesen Handler wird aufgerufen, aber nicht speichern Handler. Irgendeine Idee?
Adarsh ​​Khatri

0

In Ihrem ResourceModel \ Page sollten Sie die Funktion save enitityManager hinzufügen. Das Problem funktionierte mit folgendem Code:

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;
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.