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?
2. Where are option labels stored?
3. What does store_id=0 in option values mean?
Flashcards
Question
What is a source model?
Click to reveal answer
Answer
A class that provides options for select/multiselect EAV attributes
Question
Where are option labels stored?
Click to reveal answer
Answer
eav_attribute_option_value with store_id for multi-language
Question
How to create a custom source model?
Click to reveal answer
Answer
Extend AbstractSource and implement toOptionArray()
Question
What is the method to get all options?
Click to reveal answer
Answer
$attribute->getSource()->toOptionArray()
Question
How are multiselect values stored?
Click to reveal answer
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