C’est quelle clé que je dois mettre pour la propriété is_user_defined dans mon setup ??

Il arrive fréquemment que pour un site Magento 2 la création d’attributs produits supplémentaires devient nécessaire. On va donc commencer par créer son petit module pour y mettre un joli Setup dont le contenu devrait ressembler grosso modo à :

<?php
/* ... */
$eavSetup->addAttribute(
    Product::ENTITY,
    'joli_attribut',
    [
        'label' => 'Mon joli attribut',
        'required' => false,
        'visible_on_front' => true,
        'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
        'searchable' => true,
        'filterable' => RenderLayered::FILTERABLE_WITH_RESULTS,
        'comparable' => false,
        'type' => 'varchar',
        'input' => 'select',
        'unique' => false,
        'is_used_in_grid' => true,
        'is_filterable_in_grid' => true,
        'filterable_in_search' => true,
        'used_for_promo_rules' => true,
        'is_html_allowed_on_front' => false,
        'used_in_product_listing' => false,
        'used_for_sort_by' => false,
        'user_defined' => true,
        'group' => 'my_group'
    ]
);
/* ... */

On définit l’entité sur laquelle l’attribut sera créé, le code de l’attribut, et un tableau de configuration de l’attribut. Mais comment on connait les clés à mettre dans ce tableau ?

En base de données, certaines de ces clés se trouvent dans la table eav_attribute, les autres dans catalog_eav_attribute. Par exemple on retrouve is_user_defined. Par contre si vous avez fait attention, dans le tableau que j’ai passé à la fonction addAttribute, c’est bien la clé user_defined que j’ai défini à true. Comment expliquer la disparition du is_ ? Et comment expliquer que d’autres clés possèdent bien le is_ (is_html_allowed_on_front) ?

Mapping

Cela se fait en fait via un système de mapping de clés. Pour l’entité Product, la classe responsable du mapping est \Magento\Catalog\Model\ResourceModel\Setup\PropertyMapper, ainsi que \Magento\Eav\Model\Entity\Setup\PropertyMapper.
Pour l’entité Customer, il faudra plutôt aller voir du côté de \Magento\Customer\Model\ResourceModel\Setup\PropertyMapper.

<?php
/* \Magento\Eav\Model\Entity\Setup\PropertyMapper */
class PropertyMapper extends PropertyMapperAbstract
{
    /**
     * Map input attribute properties to storage representation
     */
    public function map(array $input, $entityTypeId)
    {
        return [
            'backend_model' => $this->_getValue($input, 'backend'),
            'backend_type' => $this->_getValue($input, 'type', 'varchar'),
            'backend_table' => $this->_getValue($input, 'table'),
            'frontend_model' => $this->_getValue($input, 'frontend'),
            'frontend_input' => $this->_getValue($input, 'input', 'text'),
            'frontend_label' => $this->_getValue($input, 'label'),
            'frontend_class' => $this->_getValue($input, 'frontend_class'),
            'source_model' => $this->_getValue($input, 'source'),
            'is_required' => $this->_getValue($input, 'required', 1),
            'is_user_defined' => $this->_getValue($input, 'user_defined', 0),
            'default_value' => $this->_getValue($input, 'default'),
            'is_unique' => $this->_getValue($input, 'unique', 0),
            'note' => $this->_getValue($input, 'note'),
            'is_global' => $this->_getValue(
                $input,
                'global',
                \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL
            )
        ];
    }
}

Ces classes de mapping servent à définir des valeurs par défaut pour certaines propriétés d’attributs. Et comme vous le voyez, elles servent également à changer user_defined en is_user_defined pour le stockage en bdd. Ne cherchez pas, à mon avis il n’y a aucune logique, il faut juste faire attention de définir les bonnes clés lors de la création de l’attribut…

Type Swatch Text et Swatch Image

Magento 2 introduit des nouveaux types d’attributs intitulés Swatch.
Pour créer un attribut de ce type via un setup, il faut ruser un petit peu. En effet, on ne peut pas définir l’attribut de type swatch_text par exemple directement avec la fonction addAttribute, ça ne fonctionnera pas. Après une petite recherche, la définition d’un attribut de type swatch se trouve dans les additional_data de l’attribut.
Cependant, si vous essayez de définir la clé additional_data dans la création de l’attribut, les données ne seront pas prises en compte car le mapping (qu’on a vu juste au-dessus) va supprimer la clé. L’astuce est de créer son attribut puis de mettre à jour la propriété additional_data :

<?php
/* ... */
$eavSetup->addAttribute(
    Product::ENTITY,
    'size',
    [
        'label' => 'Size',
        'type' => 'int',
        'input' => 'select',
        /* ... */
    ]
);
$additionalData = [
    Swatch::SWATCH_INPUT_TYPE_KEY => Swatch::SWATCH_INPUT_TYPE_TEXT,
    'update_product_preview_image' => '0',
    'use_product_image_for_swatch' => 0
];
$eavSetup->updateAttribute(
    Product::ENTITY,
    'size',
    'additional_data',
    serialize($additionalData)
);
/* ... */

Vous pouvez regarder la différence entre la fonction addAttribute et updateAttribute de \Magento\Eav\Setup\EavSetup. La première fait appel aux mappers alors que la deuxième non.