DynamicRows (o Array associativo) nell'API REST di Magento 2
Sto usando l'API REST di Magento 2 per l'applicazione mobile. Sto affrontando una certa complessità quindi ho bisogno del tuo aiuto.
Ho un componente DynamicRows con due campi nel modulo dell'interfaccia utente, il nome del campo è la localizzazione .
<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>
L'output di DynamicRows è sotto
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
)
)
Ho dichiarato un metodo getLocalization () nella mia interfaccia
/**
* Return localized parameters for the application
*
* @return mixed[]
*/
public function getLocalization();
Quindi ho implementato il metodo
/**
* @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;
}
Nel metodo sopra, ho perfezionato l'output dell'array DynamicRows secondo i requisiti.
Array
(
[tmp_dir] => temp
[main_dir] => APD
)
Quando raggiungo l'endpoint dell'API REST, ottengo la seguente risposta.
<localization>
<item>temp</item>
<item>APD</item>
</localization>
Invece mi aspetto la seguente risposta
<localization>
<tmp_dir>temp</tmp_dir>
<main_dir>APD</main_dir>
</localization>
Ho cercato in diversi articoli ma non sono riuscito a trovare la risposta migliore per soddisfare le mie esigenze.
Domanda: come otterrò il risultato atteso tenendo presente che i dati di DynamicRows non saranno sempre gli stessi, potrebbe essere un altro record con più di due campi con opzioni_label e option_value differenti ?
Risposte
Sono riuscito a trovare quanto segue:
Penso che farai fatica a ottenere di più da esso. Fondamentalmente, le chiavi degli elementi provengono dal metodo di analisi principale di Magento in modo che il risultato venga da te come xml.
Posso dettagliare i miei passaggi ma ammonta a 2 interfacce in più e un po 'di analisi .. Fammi sapere se questo output è qualcosa con cui potresti scendere a compromessi.
La risposta di Joseph è più semplice della mia (più elegante). Ma di seguito è il nucleo della mia soluzione. Ho anche inserito un collegamento al repository di bitbucket per farti provare da solo.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;
}
}
Per ottenere il risultato desiderato, è necessario creare più classi.
In questo caso, getLocalizationdovrebbe restituire un'istanza di una classe, come:
/**
* @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']
]);
});
}
Dove $this->localizationFactorysi trova: \MyCompany\MyModule\Model\LocalizationFactory.
LocalizationFactory dovrebbe avere due metodi:
getLabelgetValue
Questo potrebbe sembrare prolisso, e lo è. Tuttavia, questo percorso ti dà il controllo al 100% sull'output. La testabilità è un bonus.