bagisto-attribute-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAttribute Development
属性开发
Bagisto stores product data as EAV — entity, attribute, value — rather than
as columns on . A product row carries almost nothing; its name, price,
description and every custom field live in , one row
per attribute per locale per channel.
productsproduct_attribute_valuesThis is the concept most Bagisto mistakes trace back to, so it is worth reading
eav.md before changing anything that touches product data.
Bagisto采用EAV(实体-属性-值)模式存储产品数据,而非将数据作为表的列存储。产品表的行几乎不承载实际数据;产品名称、价格、描述及所有自定义字段都存储在表中,每个属性、每个区域、每个渠道对应一行数据。
productsproduct_attribute_values这是Bagisto多数问题的根源,因此在修改任何涉及产品数据的内容前,建议先阅读eav.md文档。
Reference files
参考文件
| File | Load when |
|---|---|
| eav.md | How values are stored and resolved — the column map, scope, the flat index |
| attributes.md | Creating attributes, families, groups, options, validation and swatches |
| 文件 | 适用场景 |
|---|---|
| eav.md | 值的存储与解析方式——列映射、范围、扁平索引 |
| attributes.md | 创建属性、属性族、属性组、选项、验证及色板(swatch) |
The shape
层级结构
attribute_families a product type's whole form (e.g. "Default")
└── attribute_groups a tab/section within it (e.g. "General")
└── attributes a field (e.g. "name")
└── attribute_options for select, multiselect and checkboxA product belongs to one family, and that family decides which attributes it
has. and
are the relations that walk it.
AttributeFamily::custom_attributes()AttributeGroup::custom_attributes()attribute_families 产品类型的完整表单(例如“默认”)
└── attribute_groups 表单内的标签页/分区(例如“常规”)
└── attributes 具体字段(例如“名称”)
└── attribute_options 用于单选、多选和复选框的选项一个产品属于一个属性族,该属性族决定了产品拥有哪些属性。和是遍历该层级的关联方法。
AttributeFamily::custom_attributes()AttributeGroup::custom_attributes()The column map
列映射
An attribute's decides which column of holds
its value:
typeproduct_attribute_values| type | column |
|---|---|
| |
| |
| |
| |
| |
| |
This map lives on , and the model exposes the
resolved name as . Never guess the column — read it
from the attribute, or a silently writes into and reads
back as null.
Attribute::$attributeTypeFields$attribute->column_nameselecttext_valueAttributeTypeEnumValidationEnumnumericemaildecimalurlregexSwatchTypeEnumdropdowncolorimagetext属性的决定了其值存储在表的哪一列:
typeproduct_attribute_values| 类型 | 列名 |
|---|---|
| |
| |
| |
| |
| |
| |
该映射定义在中,模型通过暴露解析后的列名。切勿猜测列名,应从属性中读取,否则单选框(select)会静默写入列,读取时返回null。
Attribute::$attributeTypeFields$attribute->column_nametext_valueAttributeTypeEnumValidationEnumnumericemaildecimalurlregexSwatchTypeEnumdropdowncolorimagetextScope: the two flags that cause most bugs
范围:引发最多bug的两个标志
Every attribute carries and . Together
they decide how many rows a single attribute has for one product, and which one
a read returns:
value_per_localevalue_per_channel | | Rows per product |
|---|---|---|
| false | false | 1 |
| false | true | one per locale |
| true | false | one per channel |
| true | true | one per channel per locale |
Product::getCustomAttributeValue()The table enforces this with a unique index on
, so writing the wrong scope
combination is a constraint violation rather than a silent duplicate.
(channel, locale, attribute_id, product_id)每个属性都带有和标志。它们共同决定单个产品的单个属性对应多少行数据,以及读取时返回哪一行:
value_per_localevalue_per_channel | | 每个产品的行数 |
|---|---|---|
| false | false | 1 |
| false | true | 每个区域一行 |
| true | false | 每个渠道一行 |
| true | true | 每个渠道每个区域一行 |
Product::getCustomAttributeValue()表中通过的唯一索引来强制该规则,因此错误的范围组合写入会触发约束冲突,而非静默生成重复数据。
(channel, locale, attribute_id, product_id)Non-negotiables
必须遵守的规则
- Go through the repository. ,
AttributeRepository,AttributeFamilyRepository,AttributeGroupRepository— never writeAttributeOptionRepositoryby hand.product_attribute_values - Read the column from the attribute, via or
column_name. A hard-coded column is a bug waiting for the first non-text attribute.$attributeTypeFields - Honour and
value_per_localeon every write, not just on read. Writing one row for an attribute scoped per locale loses every other locale's value.value_per_channel - A /
selectvalue is an option id, not the label.multiselectstores one id inselect;integer_valuestores comma-separated ids inmultiselect.text_value - Option labels are translatable — they live in
, so a label added in one locale must be added in all 22.
attribute_option_translations - Changing an attribute's orphans its existing values, because the new type reads a different column. Treat it as a data migration, not an edit.
type - Reindex after a change that affects listing. Filterable and listing
attributes are denormalised into by the flat indexer; until it runs, the grid and storefront show the old value.
product_flat
REQUIRED SUB-SKILL: Use bagisto-change-verification before calling any change done.
- 通过仓库操作:使用、
AttributeRepository、AttributeFamilyRepository、AttributeGroupRepository——切勿手动写入AttributeOptionRepository表。product_attribute_values - 从属性中读取列名:通过或
column_name获取。硬编码列名会在遇到第一个非文本类型属性时引发bug。$attributeTypeFields - 写入时必须遵循和
value_per_locale:不仅读取时要遵循,写入时也要。为按区域范围划分的属性只写入一行数据会丢失其他区域的值。value_per_channel - 单选/多选值是选项ID:而非标签。单选框(select)在中存储一个ID;多选框(multiselect)在
integer_value中存储逗号分隔的ID。text_value - 选项标签支持翻译:标签存储在表中,因此在一个区域添加的标签必须在所有22个区域中添加。
attribute_option_translations - 修改属性会导致现有值失效:因为新类型会读取不同的列。应将其视为数据迁移,而非简单编辑。
type - 修改影响列表的内容后需重新索引:可筛选和列表属性会被扁平索引器反规范化到表中;索引完成前,网格和店铺前台会显示旧值。
product_flat
必备子技能:在确认任何修改完成前,使用bagisto-change-verification工具。