Skip to content
intermediate Phase 41 · EAV Advanced

EAV Source Models

EAV source models for select attributes, option values, custom source models, and option arrays

45m
0 problems
Topic Progress 0%

What Are Source Models?

Source Model Purpose

Source models provide options for select and multiselect attributes:

-- Select attribute with source model
SELECT 
    a.attribute_code,
    a.source_model,
    a.frontend_input
FROM eav_attribute a
WHERE a.attribute_code IN ('status', 'visibility', 'tax_class_id')
AND a.entity_type_id = 4;
+----------------+------------------------------------------+----------------+
| attribute_code | source_model                            | frontend_input |
+----------------+------------------------------------------+----------------+
| status         | Magento\Catalog\Model\Product\Attribute\Source\Status | boolean |
| visibility     | Magento\Catalog\Model\Product\Attribute\Source\Visibility | select |
| tax_class_id   | Magento\Tax\Model\Calculation\Attribute\Source\TaxClass | select |
+----------------+------------------------------------------+----------------+

Built-in Source Models

// Boolean (Yes/No)
// Magento\Catalog\Model\Product\Attribute\Source\Status
// Options: 1=Yes, 2=No

// Visibility
// Magento\Catalog\Model\Product\Attribute\Source\Visibility
// Options: 1=Not Visible, 2=In Catalog, 3=In Search, 4=Catalog and Search

// Tax Class
// Magento\Tax\Model\Calculation\Attribute\Source\TaxClass
// Options from tax_class table

// Yes/No
// Magento\Eav\Model\Entity\Attribute\Source\Boolean
// Options: 1=Yes, 0=No

// Default
// Magento\Eav\Model\Entity\Attribute\Source\Default
// Options: Empty, Option 1, Option 2, etc.

Option Value Storage

Option Tables

-- Option definitions
SELECT * FROM eav_attribute_option WHERE attribute_id = 97;
+-----------+--------------+------------+
| option_id | attribute_id | sort_order |
+-----------+--------------+------------+
|         1 |           97 |          1 |
|         2 |           97 |          2 |
+-----------+--------------+------------+

-- Option values (multi-language)
SELECT * FROM eav_attribute_option_value WHERE option_id IN (1, 2);
+----------+-----------+----------+---------+
| value_id | option_id | store_id | value   |
+----------+-----------+----------+---------+
|        1 |         1 |        0 | Enabled |
|        2 |         2 |        0 | Disabled|
|        3 |         1 |        1 | Activé  |
|        4 |         2 |        1 | Désactivé|
+----------+-----------+----------+---------+

Option Storage Pattern

eav_attribute_option (metadata)
  ├── option_id (unique ID)
  ├── attribute_id (which attribute)
  └── sort_order (display order)

eav_attribute_option_value (labels)
  ├── value_id (unique ID)
  ├── option_id (links to option)
  ├── store_id (0=default, N=store-specific)
  └── value (translated label)

Querying Options

-- Get all options for an attribute with labels
SELECT 
    o.option_id,
    o.sort_order,
    v_default.value AS default_label,
    v_store.value AS store_label
FROM eav_attribute_option o
LEFT JOIN eav_attribute_option_value v_default 
    ON v_default.option_id = o.option_id AND v_default.store_id = 0
LEFT JOIN eav_attribute_option_value v_store 
    ON v_store.option_id = o.option_id AND v_store.store_id = 1
WHERE o.attribute_id = 97
ORDER BY o.sort_order;
+-----------+------------+---------------+------------+
| option_id | sort_order | default_label | store_label|
+-----------+------------+---------------+------------+
|         1 |          1 | Enabled       | Activé     |
|         2 |          2 | Disabled      | Désactivé  |
+-----------+------------+---------------+------------+

Custom Source Models

Creating a Custom Source Model

<?php
namespace Vendor\Module\Model\Product\Attribute\Source;

use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;
use Magento\Eav\Model\Entity\Attribute\Source\Interface as SourceInterface;

class CustomOptions extends AbstractSource implements SourceInterface
{
    /**
     * Return array of options as value-label pairs
     */
    public function toOptionArray(): array
    {
        return [
            ['value' => 'option1', 'label' => __('Option One')],
            ['value' => 'option2', 'label' => __('Option Two')],
            ['value' => 'option3', 'label' => __('Option Three')],
        ];
    }

    /**
     * Get option label by value
     */
    public function getOptionText($value): ?string
    {
        $options = $this->toOptionArray();
        foreach ($options as $option) {
            if ($option['value'] == $value) {
                return $option['label'];
            }
        }
        return null;
    }
}

Register Source Model

// In InstallData.php or data patch
$eavSetup->addAttribute(
    \Magento\Catalog\Model\Product::ENTITY,
    'custom_dropdown',
    [
        'type' => 'varchar',
        'input' => 'select',
        'label' => 'Custom Dropdown',
        'source' => 'Vendor\Module\Model\Product\Attribute\Source\CustomOptions',
        'required' => false,
        'sort_order' => 100,
        'group' => 'General',
    ]
);

Dynamic Source from Database

<?php
namespace Vendor\Module\Model\Product\Attribute\Source;

use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;

class DynamicOptions extends AbstractSource
{
    public function __construct(
        private \Vendor\Module\Model\ResourceModel\Option\Collection $optionCollection
    ) {}

    public function toOptionArray(): array
    {
        $options = [['value' => '', 'label' => __('-- Please Select --')]];
        
        foreach ($this->optionCollection as $option) {
            $options[] = [
                'value' => $option->getId(),
                'label' => $option->getName()
            ];
        }
        
        return $options;
    }
}

Using Options in Code

Getting Options in PHP

// Get attribute options
$attribute = $eavConfig->getAttribute('catalog_product', 'status');

// Get all options
$options = $attribute->getSource()->getAllOptions();
// Returns: [['value' => '', 'label' => ''], ['value' => 1, 'label' => 'Yes'], ['value' => 2, 'label' => 'No']]

// Get option by value
$label = $attribute->getSource()->getOptionText(1); // 'Yes'

// Get option value by label
$value = $attribute->getSource()->getOptionId('Yes'); // 1

Setting Option Values

// Set dropdown value
$product->setData('custom_dropdown', 'option1');
$product->save();

// Set multiselect value (comma-separated)
$product->setData('custom_multiselect', 'option1,option3');
$product->save();

// Get multiselect values
$values = $product->getData('custom_multiselect');
$array = explode(',', $values); // ['option1', 'option3']

Option Arrays in Templates

// In block class
public function getOptions(): array
{
    $attribute = $this->eavConfig->getAttribute('catalog_product', 'custom_dropdown');
    return $attribute->getSource()->toOptionArray();
}

// In template
<select name="custom_dropdown">
    <?php foreach ($block->getOptions() as $option): ?>
        <option value="<?= $escaper->escapeHtml($option['value']) ?>"
            <?php if ($product->getData('custom_dropdown') == $option['value']): ?>selected<?php endif; ?>>
            <?= $escaper->escapeHtml($option['label']) ?>
        </option>
    <?php endforeach; ?>
</select>

Multiselect Source Model

<?php
namespace Vendor\Module\Model\Product\Attribute\Source;

use Magento\Eav\Model\Entity\Attribute\Source\Table;

class MultiselectOptions extends Table
{
    public function toOptionArray(): array
    {
        return [
            ['value' => 'opt1', 'label' => __('Option 1')],
            ['value' => 'opt2', 'label' => __('Option 2')],
            ['value' => 'opt3', 'label' => __('Option 3')],
        ];
    }

    public function getOptionText($value)
    {
        $options = $this->toOptionArray();
        $labels = [];
        $values = explode(',', $value);
        foreach ($options as $option) {
            if (in_array($option['value'], $values)) {
                $labels[] = $option['label'];
            }
        }
        return implode(', ', $labels);
    }
}

Quiz

1. What is the purpose of a source model?

Question 1 options

2. Where are option labels stored?

Question 2 options

3. What does store_id=0 in option values mean?

Question 3 options

Flashcards

Question

What is a source model?

Answer

A class that provides options for select/multiselect EAV attributes

Question

Where are option labels stored?

Answer

eav_attribute_option_value with store_id for multi-language

Question

How to create a custom source model?

Answer

Extend AbstractSource and implement toOptionArray()

Question

What is the method to get all options?

Answer

$attribute->getSource()->toOptionArray()

Question

How are multiselect values stored?

Answer

Comma-separated option values in the value column

Revision Notes

Key Takeaways

  • 1. Source models provide options for select and multiselect attributes
  • 2. Option metadata in eav_attribute_option, labels in eav_attribute_option_value
  • 3. Custom source models extend AbstractSource and implement toOptionArray()
  • 4. store_id=0 is default, other stores have store-specific labels
  • 5. Multiselect values stored as comma-separated strings

Interview Tips

  • Explain how source models provide dropdown options
  • Discuss multi-language option storage
  • Describe creating custom source models from database

Cheat Sheet

Source Models:
  AbstractSource → Extend for custom options
  toOptionArray() → Returns [['value' => ..., 'label' => ...]]
  getOptionText($value) → Returns label for value

Option Storage:
  eav_attribute_option → option_id, attribute_id, sort_order
  eav_attribute_option_value → value_id, option_id, store_id, value

Built-in Sources:
  Status: Magento\Catalog\...\Status
  Visibility: Magento\Catalog\...\Visibility
  Boolean: Magento\Eav\...\Boolean