EAV и атрибуты товара
У товаров в Magento нет общей таблицы со столбцами «цвет», «размер», «гарантия». Каждое свойство — атрибут, и новые атрибуты добавляются без изменения структуры базы. Такой способ хранения называют EAV: сущность (entity), атрибут (attribute), значение (value).
Как это устроено
| Таблица | Что хранит |
|---|---|
catalog_product_entity | Сами товары: номер, артикул, тип |
eav_attribute | Описания атрибутов: код, тип, подпись |
catalog_product_entity_varchar, _int, _decimal, _text, _datetime | Значения: номер товара, номер атрибута, витрина, значение |
Благодаря столбцу витрины название или описание товара может отличаться на разных языках. Работать с этими таблицами напрямую не нужно — значения читают и записывают через товар.
Атрибут можно создать в панели: «Магазины → Атрибуты → Товар» (Stores → Attributes → Product). Но тогда он появится только на этом сервере. Чтобы атрибут был частью модуля, его создают заплаткой данных.
Заплатка с атрибутом
Добавим товарам срок гарантии в месяцах:
// app/code/Acme/Hello/Setup/Patch/Data/AddWarrantyAttribute.php
namespace Acme\Hello\Setup\Patch\Data;
use Magento\Catalog\Model\Product;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
class AddWarrantyAttribute implements DataPatchInterface
{
public function __construct(
private ModuleDataSetupInterface $setup,
private EavSetupFactory $eavSetupFactory,
) {}
public function apply(): self
{
$eavSetup = $this->eavSetupFactory->create(['setup' => $this->setup]);
$eavSetup->addAttribute(Product::ENTITY, 'warranty_months', [
'type' => 'int',
'label' => 'Warranty, months',
'input' => 'text',
'required' => false,
'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
'user_defined' => true,
'visible_on_front' => true,
'used_in_product_listing' => true,
'group' => 'General',
]);
return $this;
}
public static function getDependencies(): array
{
return [];
}
public function getAliases(): array
{
return [];
}
}Выполните bin/magento setup:upgrade. Откройте любой товар в панели управления: в форме появится поле Warranty, months. Подпись атрибута пишут по-английски, а переводят в панели или файлом перевода.
Параметры атрибута
| Параметр | Что задаёт |
|---|---|
type | В какой таблице значений хранить: int, varchar, decimal, text, datetime |
input | Поле в форме: text, textarea, select, boolean, date, price |
global | Уровень значения: общий, для сайта или для витрины |
user_defined | Атрибут создан не ядром, и его можно удалить в панели |
visible_on_front | Показывать в таблице характеристик на странице товара |
used_in_product_listing | Загружать значение в списках товаров |
group | Раздел формы товара, в который попадёт поле |
Чтение значения
// app/code/Acme/Hello/Model/ShopInfo.php
public function warranty(string $sku): int
{
$product = $this->productRepository->get($sku);
return (int) $product->getData('warranty_months');
}Метод возвращает срок гарантии товара или ноль, если поле не заполнено. Товар, полученный из репозитория, содержит все атрибуты.
Запись значения
// app/code/Acme/Hello/Model/ShopInfo.php
public function setWarranty(string $sku, int $months): void
{
$product = $this->productRepository->get($sku);
$product->setCustomAttribute('warranty_months', $months);
$this->productRepository->save($product);
}После сохранения значение видно в форме товара в панели, а благодаря visible_on_front — на странице товара во вкладке с характеристиками.
Частая ошибка
Параметры type и input не согласованы: например, выпадающий список select объявлен с типом varchar или цена — с типом int. Значения сохраняются не в ту таблицу, а фильтры и сортировка в каталоге работают неверно. Для select и boolean берите int, для price — decimal, для короткой строки — varchar.