VirtualGroupedSelect

  • Published: 2019-07-25

  • Author: Nickolas Burr

Description

The VirtualSelect example illustrates how to create a select, multiselect source model with data populated from di.xml. That works well for flat arrays, but doesn’t work for multidimensional arrays.

In order to populate a select or multiselect in the same fashion, but with a multidimensional array, we’ll need to adjust the setOption method to recurse through the given subarrays and create the desired optgroup set.

Usage

<?xml version="1.0"?>
<!--
/**
 * system.xml
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="vendor" translate="label" sortOrder="100">
            <label>Vendor, Inc.</label>
        </tab>
        <section id="package" translate="label" sortOrder="100"
                 showInDefault="1" showInWebsite="1" showInStore="1">
            <class>separator-top</class>
            <label>Package</label>
            <tab>vendor</tab>
            <group id="general" translate="label" type="text" sortOrder="10"
                   showInDefault="1" showInWebsite="1" showInStore="1">
                <label>General Settings</label>
                <field id="default_status" translate="label" type="select" sortOrder="10"
                       showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Product Types</label>
                    <!-- The <virtualType> class -->
                    <source_model>Vendor\Package\Model\Source\Select\Grouped\ProductTypes</source_model>
                </field>
            </group>
        </section>
    </system>
</config>

Source

<?php
/**
 * Generic.php
 */
declare(strict_types=1);

namespace Vendor\Package\Model\Source\Select\Grouped;

use Magento\Framework\Option\ArrayInterface;

class Generic implements ArrayInterface
{
    /** @property array $options */
    protected $options = [];

    /**
     * @param array $data
     * @return void
     */
    public function __construct(array $data = [])
    {
        array_walk(
            $data,
            [
                $this,
                'setOption'
            ]
        );
    }

    /**
     * @param array $options
     * @return array
     */
    protected function getOptGroup(array $options): array
    {
        /** @var array $optgroup */
        $optgroup = [];

        foreach ($options as $key => $value) {
            if (is_array($value)) {
                $optgroup[] = $this->getOptGroup($value);
            } else {
              $optgroup[] = [
                  'label' => $value,
                  'value' => $key,
              ];
            }
        }

        return $optgroup;
    }

    /**
     * @param int|string|null $value
     * @param int|string $key
     * @return void
     */
    protected function setOption($value, $key): void
    {
        if (is_array($value)) {
            $value = $this->getOptGroup($value);
        }

        $this->options[] = [
            'label' => __($key),
            'value' => $value,
        ];
    }

    /**
     * @return array
     */
    public function toOptionArray()
    {
        return $this->options;
    }
}
<?xml version="1.0"?>
<!--
/**
 * di.xml
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Vendor\Package\Model\Source\Select\Grouped\ProductTypes"
                 type="Vendor\Package\Model\Source\Select\Grouped\Generic">
        <arguments>
            <argument name="data" xsi:type="array">
                <item name="shirts" xsi:type="array">
                    <item name="tshirt" xsi:type="string">T-shirt</item>
                    <item name="long_sleeve" xsi:type="string">Long Sleeve Shirt</item>
                </item>
                <item name="pants" xsi:type="array">
                    <item name="slacks" xsi:type="string">Slacks</item>
                    <item name="track_pants" xsi:type="string">Track Pants</item>
                </item>
                <item name="shoes" xsi:type="array">
                    <item name="leather" xsi:type="array">
                        <item name="loafers" xsi:type="string">Loafers</item>
                    </item>
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>