Skip to content

DynamicRows in product_form.xml. Issue with saving data to database

I have this layout defined in my custom module that is supposed to handle rules that in the future will limit the stock availability based on customer group.
I have a db_schema with similar fields.

I can see the values in the payload, but it goes nowhere

product[customer_group_stock_limits][customer_group_stock_limit_rules][0][record_id]
0
product[customer_group_stock_limits][customer_group_stock_limit_rules][0][customer_group_id]
19
product[customer_group_stock_limits][customer_group_stock_limit_rules][0][mode]
absolute
product[customer_group_stock_limits][customer_group_stock_limit_rules][0][value]
90
product[customer_group_stock_limits][customer_group_stock_limit_rules][0][is_active]
1
<?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_group_stock_limits" sortOrder="100">
        <settings>
            <label translate="true">Customer Group Stock Limits</label>
            <collapsible>true</collapsible>
            <opened>false</opened>
            <dataScope>data.product.customer_group_stock_limits</dataScope>
        </settings>

        <container name="add_rule_container" component="Magento_Ui/js/form/components/group" sortOrder="10">
            <container name="add_rule_button" component="Magento_Ui/js/form/components/button">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="formElement" xsi:type="string">container</item>
                        <item name="title" xsi:type="string" translate="true">Add Rule</item>
                        <item name="additionalForGroup" xsi:type="boolean">true</item>
                        <item name="additionalClasses" xsi:type="string">admin__field-medium</item>
                        <item name="actions" xsi:type="array">
                            <item name="0" xsi:type="array">
                                <item name="targetName" xsi:type="string">
                                    product_form.product_form.customer_group_stock_limits.customer_group_stock_limit_rules
                                </item>
                                <item name="actionName" xsi:type="string">addChild</item>
                            </item>
                        </item>
                    </item>
                </argument>
            </container>
        </container>

        <dynamicRows name="customer_group_stock_limit_rules"
                     component="Magento_Ui/js/dynamic-rows/dynamic-rows-grid"
                     template="ui/dynamic-rows/templates/grid"
                     sortOrder="20">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="columnsHeaderAfterRender" xsi:type="boolean">true</item>
                    <item name="renderDefaultRecord" xsi:type="boolean">false</item>
                    <item name="deleteButtonLabel" xsi:type="string">Delete</item>
                    <item name="dataProvider" xsi:type="string">
                        data.customer_group_stock_limits.customer_group_stock_limit_rules_grid
                    </item>

                    <item name="map" xsi:type="array">
                        <item name="rule_id" xsi:type="string">rule_id</item>
                        <item name="customer_group_id" xsi:type="string">customer_group_id</item>
                        <item name="mode" xsi:type="string">mode</item>
                        <item name="value" xsi:type="string">value</item>
                        <item name="is_active" xsi:type="string">is_active</item>
                    </item>

                    <item name="identificationDRProperty" xsi:type="string">rule_id</item>
                </item>
            </argument>
            <settings>
                <additionalClasses>
                    <class name="admin__field-wide">true</class>
                </additionalClasses>
                <defaultRecord>false</defaultRecord>
                <addButton>false</addButton>
                <deleteProperty>true</deleteProperty>
                <recordTemplate>record</recordTemplate>
                <identificationProperty>rule_id</identificationProperty>
                <links>
                    <link name="insertData">${ $.provider }:${ $.dataProvider }</link>
                </links>
                <dndConfig>
                    <param name="enabled" xsi:type="boolean">false</param>
                </dndConfig>
                <columnsHeader>true</columnsHeader>
            </settings>
            <container name="record" component="Magento_Ui/js/dynamic-rows/record">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="isTemplate" xsi:type="boolean">true</item>
                        <item name="is_collection" xsi:type="boolean">true</item>
                        <item name="dataScope" xsi:type="string"/>
                    </item>
                </argument>

                <!-- Customer Group -->
                <field name="customer_group_id" formElement="select" sortOrder="10">
                    <settings>
                        <dataType>text</dataType>
                        <dataScope>customer_group_id</dataScope>
                        <label translate="true">Customer Group</label>
                        <validation>
                            <rule name="required-entry" xsi:type="boolean">true</rule>
                        </validation>
                    </settings>
                    <formElements>
                        <select>
                            <settings>
                                <!-- core customer group source -->
                                <options class="MagentoCustomerModelCustomerSourceGroup"/>
                            </settings>
                        </select>
                    </formElements>
                </field>

                <!-- Mode -->
                <field name="mode" formElement="select" sortOrder="20">
                    <settings>
                        <dataType>text</dataType>
                        <dataScope>mode</dataScope>
                        <label translate="true">Mode</label>
                        <validation>
                            <rule name="required-entry" xsi:type="boolean">true</rule>
                        </validation>
                    </settings>
                    <formElements>
                        <select>
                            <settings>
                                <options
                                    class="SamSolutionsCustomerGroupStockLimitModelOptionSourceStockLimitMode"/>
                            </settings>
                        </select>
                    </formElements>
                </field>

                <!-- Value -->
                <field name="value" formElement="input" sortOrder="30">
                    <settings>
                        <dataType>number</dataType>
                        <dataScope>value</dataScope>
                        <label translate="true">Value</label>
                        <validation>
                            <rule name="required-entry" xsi:type="boolean">true</rule>
                            <rule name="validate-digits" xsi:type="boolean">true</rule>
                            <rule name="greater-than-equals-to" xsi:type="number">0</rule>
                        </validation>
                    </settings>
                </field>

                <!-- Active -->
                <field name="is_active" formElement="checkbox" sortOrder="40">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="fit" xsi:type="boolean">true</item>
                            <item name="prefer" xsi:type="string">toggle</item>
                            <item name="valueMap" xsi:type="array">
                                <item name="true" xsi:type="number">1</item>
                                <item name="false" xsi:type="number">0</item>
                            </item>
                            <item name="default" xsi:type="number">1</item>
                        </item>
                    </argument>
                    <settings>
                        <dataType>boolean</dataType>
                        <dataScope>is_active</dataScope>
                        <label translate="true">Active</label>
                    </settings>
                </field>

                <!-- Actions (Delete) -->
                <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">Actions</item>
                            <item name="sortOrder" xsi:type="string">60</item>
                            <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>
        </dynamicRows>
    </fieldset>
</form>

What is wrong with my layout? It isn’t very clear to me. Right now I can add rows, but they are not deletable for some reason.

How do I save the data from this kind of grid? Observer/Plugin?
What do I do after it’s saved? How do I retrieve it from the database? I assume I need the product form modifier, but I don’t understand what to write there.