DynamicRows (lub Associative Array) w Magento 2 REST API
Używam Magento 2 REST API do aplikacji mobilnej. Stoję w obliczu złożoności, więc potrzebuję twojej pomocy.
Mam komponent DynamicRows z dwoma polami w formularzu UI, nazwa pola to lokalizacja .
<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>
Dane wyjściowe DynamicRows znajdują się poniżej
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
)
)
W moim interfejsie zadeklarowałem metodę getLocalization ()
/**
* Return localized parameters for the application
*
* @return mixed[]
*/
public function getLocalization();
Następnie wdrożyłem metodę
/**
* @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;
}
W powyższej metodzie udoskonaliłem dane wyjściowe tablicy DynamicRows zgodnie z wymaganiami.
Array
(
[tmp_dir] => temp
[main_dir] => APD
)
Kiedy trafiam w punkt końcowy interfejsu API REST, otrzymuję następującą odpowiedź.
<localization>
<item>temp</item>
<item>APD</item>
</localization>
Podczas gdy oczekuję następującej odpowiedzi
<localization>
<tmp_dir>temp</tmp_dir>
<main_dir>APD</main_dir>
</localization>
Przeszukałem różne artykuły, ale nie mogłem znaleźć najlepszej odpowiedzi, która spełniłaby moje wymagania.
Pytanie: Jak uzyskam oczekiwany wynik, pamiętając o tym, że dane DynamicRows nie zawsze będą takie same, czy inny rekord może mieć więcej niż dwa pola z różnymi etykietami_opcji i wartością_opcji ?
Odpowiedzi
Udało mi się dojść do następujących rzeczy:
Myślę, że będziesz miał trudności, aby uzyskać więcej z tego. Zasadniczo klucze pozycji pochodzą z podstawowej metody analizowania Magento, dzięki czemu wynik jest dostarczany jako plik XML.
Mogę szczegółowo opisać moje kroki, ale oznacza to 2 dodatkowe interfejsy i trochę analizy. Daj mi znać, jeśli to wyjście jest czymś, z czym mógłbyś pójść na kompromis.
Odpowiedź Józefa jest prostsza niż moja (bardziej elegancka). Ale poniżej jest rdzeń mojego rozwiązania. Umieściłem również link do repozytorium bitbucket, abyś mógł sam wypróbować.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;
}
}
Aby uzyskać pożądany efekt, musisz utworzyć więcej klas.
W takim przypadku getLocalizationnależy zwrócić instancję klasy, na przykład:
/**
* @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']
]);
});
}
Gdzie $this->localizationFactoryjest: \MyCompany\MyModule\Model\LocalizationFactory.
LocalizationFactory powinien mieć dwie metody:
getLabelgetValue
Może się to wydawać rozwlekłe i tak jest. Jednak ta trasa zapewnia 100% kontrolę nad wyjściem. Testowalność to bonus.