DynamicRows (oder assoziatives Array) in der Magento 2-REST-API

Oct 02 2020

Ich verwende die Magento 2 REST-API für die mobile Anwendung. Ich bin mit einer gewissen Komplexität konfrontiert, daher brauche ich Ihre Hilfe.

Ich habe DynamicRows-Komponente mit zwei Feldern in UI Form, der Name des Feldes ist Lokalisierung .

<container name="localization" sortOrder="9" >
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="component" xsi:type="string">Magento_Ui/js/dynamic-rows/dynamic-rows</item>
            <item name="template" xsi:type="string">ui/dynamic-rows/templates/default</item>
            <item name="componentType" xsi:type="string">dynamicRows</item>
            <item name="label" xsi:type="string" translate="true">Data</item>
            <item name="recordTemplate" xsi:type="string">record</item>
            <item name="addButtonLabel" xsi:type="string">Add Parameter</item>
            <item name="deleteProperty" xsi:type="boolean">false</item>
            <item name="enabled" xsi:type="boolean">false</item>
        </item>
    </argument>

    <container name="record">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="label" xsi:type="string" translate="true" />
                <item name="component" xsi:type="string" translate="true">Magento_Ui/js/dynamic-rows/record</item>
                <item name="isTemplate" xsi:type="boolean">true</item>
                <item name="is_collection" xsi:type="boolean">true</item>
                <item name="showFallbackReset" xsi:type="boolean">false</item>
            </item>
        </argument>

        <field name="option_label">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Parameter</item>
                    <item name="formElement" xsi:type="string">input</item>
                    <item name="dataScope" xsi:type="string">option_label</item>
                    <item name="showFallbackReset" xsi:type="boolean">false</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">true</item>
                    </item>
                    <item name="sortOrder" xsi:type="string">10</item>
                </item>
            </argument>
        </field>

        <field name="option_value">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Value</item>
                    <item name="formElement" xsi:type="string">input</item>
                    <item name="dataScope" xsi:type="string">option_value</item>
                    <item name="showFallbackReset" xsi:type="boolean">false</item>
                    <item name="additionalClasses" xsi:type="array">
                        <item name="cirklestudio_color_picker" xsi:type="boolean">true</item>
                    </item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">true</item>
                    </item>
                    <item name="sortOrder" xsi:type="string">20</item>
                </item>
            </argument>
        </field>

        <actionDelete>
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="componentType" xsi:type="string">actionDelete</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="fit" xsi:type="boolean">false</item>
                    <item name="label" xsi:type="string" />
                    <item name="additionalClasses" xsi:type="string">data-grid-actions-cell</item>
                    <item name="template" xsi:type="string">Magento_Backend/dynamic-rows/cells/action-delete</item>
                </item>
            </argument>
        </actionDelete>
        
    </container>

</container>

Die Ausgabe der DynamicRows ist unten

Array
(
    [0] => Array
        (
            [row_id] => 
            [option_label] => tmp_dir
            [option_value] => temp
            [position] => 1
            [record_id] => 0
            [initialize] => true
        )

    [1] => Array
        (
            [record_id] => 1
            [row_id] => 
            [option_label] => main_dir
            [option_value] => APD
            [position] => 2
            [initialize] => true
        )
)

Ich habe eine Methode getLocalization () in meiner Schnittstelle deklariert

/**
 * Return localized parameters for the application
 *
 * @return mixed[]
 */
public function getLocalization();

Dann habe ich die Methode implementiert

/**
 * @inheritdoc
 */
public function getLocalization()
{
    // Unserialize array
    $data = $this->_getData('localization') ? unserialize($this->_getData('localization')) : ""; $output = [];
    foreach ($data as $param) {
        $output[$param['option_label']] =  $param['option_value']; } return $output;
}

Bei der obigen Methode habe ich die Ausgabe des DynamicRows-Arrays gemäß den Anforderungen verfeinert.

Array
(
    [tmp_dir] => temp
    [main_dir] => APD
)

Wenn ich den REST-API-Endpunkt erreiche, erhalte ich die folgende Antwort.

<localization>
    <item>temp</item>
    <item>APD</item>
</localization>

Ich erwarte die folgende Antwort

<localization>
    <tmp_dir>temp</tmp_dir>
    <main_dir>APD</main_dir>
</localization>

Ich habe in verschiedenen Artikeln gesucht, aber nicht die beste Antwort gefunden, die meinen Anforderungen entspricht.

Frage: Wie erhalte ich mein erwartetes Ergebnis, wenn ich bedenke, dass DynamicRows-Daten nicht immer gleich sind. Möglicherweise enthält ein anderer Datensatz mehr als zwei Felder mit unterschiedlichen option_label und option_value .

Antworten

4 HerveTribouilloy Oct 03 2020 at 19:52

Ich habe es geschafft, Folgendes zu erreichen:

Ich denke, Sie werden Schwierigkeiten haben, mehr daraus zu machen. Grundsätzlich stammen die Elementschlüssel aus der Magento-Kernanalyse, sodass Ihr Ergebnis als XML zu Ihnen kommt.

Ich kann meine Schritte detailliert beschreiben, aber es sind 2 weitere Schnittstellen und ein bisschen Parsing. Lassen Sie mich wissen, ob Sie mit dieser Ausgabe Kompromisse eingehen könnten.

Josephs Antwort ist einfacher als meine (eleganter). Aber unten ist der Kern meiner Lösung. Ich habe auch einen Link zum Bitbucket-Repository eingefügt, den Sie selbst ausprobieren können.https://bitbucket.org/magstaging/apiparser/src/master/

    $output = []; foreach ($data as $param) { $output[$param['option_label']] = $param['option_value'];
            }
    
            return $this->parsedDataInterfaceFactory->create([ 'itemsData' => $output
            ]);


class ParsedResult implements ParsedDataInterface
{
    /**
     * @var \Mbs\Calculator\Api\Data\ParsedDataItemInterface[]
     */
    private $items = []; /** * OperationResult constructor. * @param array $itemsData
     * @param \Mbs\Calculator\Api\Data\ParsedDataItemInterfaceFactory $dataItemInterfaceFactory */ public function __construct( $itemsData,
        \Mbs\Calculator\Api\Data\ParsedDataItemInterfaceFactory $dataItemInterfaceFactory ) { foreach ($itemsData as $itemLabel => $itemValue) {
            $this->items[] = $dataItemInterfaceFactory->create([
                'label' => $itemLabel, 'value' => $itemValue
            ]);
        }
    }

    /**
     * @return \Mbs\Calculator\Api\Data\ParsedDataItemInterface[]
     */
    public function getLocalization()
    {
        return $this->items; } } class Item implements ParsedDataItemInterface { /** * @var string */ private $label;

    /**
     * @var string
     */
    private $value; /** * @inheritdoc */ public function __construct( string $label,
        string $value ) { $this->label = $label; $this->value = $value; } /** * @inheritdoc */ public function getLabel() { return $this->label;
    }

    /**
     * @inheritdoc
     */
    public function getValue()
    {
        return $this->value;
    }
}
2 JosephatSwiftOtter Oct 03 2020 at 20:38

Um das gewünschte Ergebnis zu erzielen, müssen Sie weitere Klassen erstellen.

In diesem Fall getLocalizationsollte eine Instanz einer Klasse zurückgegeben werden, z.

/**
 * @return \MyCompany\MyModule\Model\Localization[]
 **/
public function getLocalization(): array
{
    // Unserialize array
    $data = $this->_getData('localization') ? unserialize($this->_getData('localization')) : ""; return array_map(function($option) {
        return $this->localizationFactory->create([ 'label' => $param['option_label'],
            'value' => $param['option_value']
        ]);
    });
}

Wo $this->localizationFactoryist : \MyCompany\MyModule\Model\LocalizationFactory.

LocalizationFactory sollte zwei Methoden haben:

  • getLabel
  • getValue

Dies mag ausführlich erscheinen, und das ist es auch. Diese Route gibt Ihnen jedoch 100% Kontrolle über die Ausgabe. Testbarkeit ist ein Bonus.