magento2: Using a multiselect product attribute with a custom source model in the adminhtml doesn't render selected value.

Preconditions

Magento 2.4-develop

Issue Description

I’ve created a custom source model to use as a product attribute of the type ‘multiselect’. The Source model extends Magento\Eav\Model\Entity\Attribute\Source\AbstractSource and it shows up just fine. Saving the entities also work: the value gets stored in the database.

However, when the product page is loaded in the adminhtml, the proper values or not re-selected. I’ve tracked this down to the JavaScript configuration used for the attribute. If I create a multiselect product attribute from the adminhtml, I see in the JSON that the value of the options are strings:

{"value":"4","label":"Foo"},{"value":"5","label":"Bar"}

However, the values of my custom source model are rendered as integers:

{"value":4,"label":"Foo"},{"value":5,"label":"Bar"}

I’ve debugged the JavaScript by setting breakpoints in the inspector and everything is parsed correctly. That is: the values from the database are passed through to Magento. The only difference is the value in the JavaScript object:

screen shot 2016-11-23 at 17 30 27

screen shot 2016-11-23 at 17 30 40

So I’m guessing that when you use custom source models, the values are not passed as strings, causing Knockout to not set the proper values

Steps to reproduce

1. Generate a custom EAV source model.

For example:

use Magento\Customer\Api\GroupManagementInterface;

/**
 * Class CustomerGroup
 */
class CustomerGroup 
    extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
    implements \Magento\Framework\Option\ArrayInterface
{
    /**
     * @var GroupManagementInterface
     */
    protected $groupManagement;

    /**
     * CustomerGroup constructor.
     * @param GroupManagementInterface $groupManagement
     */
    public function __construct(
        GroupManagementInterface $groupManagement
    )
    {
        $this->groupManagement = $groupManagement;
    }

    /**
     * @return array
     */
    public function toArray()
    {
        $groups = [];

        foreach ($this->groupManagement->getLoggedInGroups() as $group) {
            $groups[$group->getId()] = $group->getCode();
        }

        return $groups;
    }

    /**
     * Options getter
     * @return array
     */
    final public function toOptionArray()
    {
        $arr = $this->toArray();
        $ret = [];

        foreach ($arr as $key => $value) {
            $ret[] = [
                'value' => $key,
                'label' => $value
            ];
        }

        return $ret;
    }

    /**
     * Get options in "key-value" format
     * @return array
     */
    public function toArray()
    {
        return [];
    }

    /**
     * @return array
     */
    public function getAllOptions()
    {
        return $this->toOptionArray();
    }
}

2. Create a product attribute and set the source model in the database to your custom source model.

3. Add it to an attribute set and save a product with some values

  • Check the database: values are stored.
  • Reload the product detail page: options are not selected, although they are present in the JS configuration / Knockout

It could be that I’m missing a step here with custom source models, but this always works with select-elements, but multiselect works different.

Actual Result:

values of my custom source model are rendered as integers

Expected Result:

values of my custom should be rendered as a string

Update:

I’m currently able to fix this by making sure that the toOptionArray()-method of my source model always returns a string:

/**
 * Options getter
 * @return array
 */
final public function toOptionArray()
{
    $arr = $this->toArray();
    $ret = [];

    foreach ($arr as $key => $value) {
        $ret[] = [
            // Always return a string:
            'value' => (string) $key,
            'label' => $value
        ];
    }

    return $ret;
}

However, in my opinion this issue can still be considered a bug, because for semantics it’s very strange I have to force my ID’s (which are integers) to strings, just to get the Knockout multiselect component working.

Besides that, I have no idea what other things might break from this ‘fix’, since source models are broadly accepted and it might throw exceptions when an integer is expected.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 3
  • Comments: 18 (10 by maintainers)

Most upvoted comments

Is there any news or at least some confirmation on this ticket?