Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.