Die Reward-EAV-Entity-Tabellen anlegen (entity + attribute tables)
Die Reward-EAV-Entity-Tabellen anlegen (entity + attribute tables)
~8 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Mit dem Vokabular aus Kapitel 10 im Rücken baut dieses Kapitel das, was Kapitel 3 für den Punkte-Ledger war: die Tabellen selbst, über db_schema.xml. Sechs Tabellen insgesamt - eine Haupttabelle und fünf Wertetabellen, eine pro PHP-Skalartyp.
Die Haupttabelle: mironsoft_loyalty_reward_entity
entity_id- Primärschlüssel, Autoincrement, entspricht derentity_idauscatalog_product_entity.attribute_set_id- Fremdschlüssel aufeav_attribute_set.attribute_set_id; Kapitel 13 legt automatisch ein "Default"-Set an, sobald der Entity Type registriert wird.type_id- siehe Kasten unten.identifier- eine eindeutige, SKU-artige Kennung pro Prämie (zum Beispielreward-10-euro-gutschein), die spätere Blöcke für URLs und API-Referenzen nutzen.created_at/updated_at- automatisch von der Datenbank gepflegte Zeitstempel.
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<!-- unveraendert aus Kapitel 3: mironsoft_loyalty_points_ledger -->
<table name="mironsoft_loyalty_reward_entity" resource="default" engine="innodb"
comment="Mironsoft Loyalty Reward EAV Entity">
<column xsi:type="int" name="entity_id" padding="10" unsigned="true"
nullable="false" identity="true" comment="Entity ID"/>
<column xsi:type="smallint" name="attribute_set_id" padding="5" unsigned="true"
nullable="false" identity="false" default="0" comment="Attribute Set ID"/>
<column xsi:type="varchar" name="type_id" nullable="false" length="32"
default="mironsoft_loyalty_reward" comment="Entity Type ID"/>
<column xsi:type="varchar" name="identifier" nullable="false" length="64"
comment="Unique, SKU-like Reward Identifier"/>
<column xsi:type="timestamp" name="created_at" on_update="false" nullable="false"
default="CURRENT_TIMESTAMP" comment="Created At"/>
<column xsi:type="timestamp" name="updated_at" on_update="true" nullable="false"
default="CURRENT_TIMESTAMP" comment="Updated At"/>
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="entity_id"/>
</constraint>
<constraint xsi:type="unique" referenceId="MIRONSOFT_LOYALTY_REWARD_ENTITY_IDENTIFIER">
<column name="identifier"/>
</constraint>
<constraint xsi:type="foreign"
referenceId="MIRONSOFT_LOYALTY_REWARD_ENTITY_ATTRIBUTE_SET_ID_EAV_ATTRIBUTE_SET_ATTRIBUTE_SET_ID"
table="mironsoft_loyalty_reward_entity" column="attribute_set_id"
referenceTable="eav_attribute_set" referenceColumn="attribute_set_id"
onDelete="CASCADE"/>
</table>
</schema>Warum type_id, obwohl es nur einen Typ gibt?
catalog_product_entity.type_id speichert, ob ein Produkt simple, configurable oder ein anderer Produkttyp ist (Block 9 dieser Serie baut sogar einen eigenen). Die Prämie hat keine solche Typ-Variation - trotzdem gehört type_id zur Spalte, weil Magentos AbstractEntity-Basisklasse (Kapitel 12) diese Spalte als festen Bestandteil des klassischen EAV-Entity-Musters erwartet. Für Reward bleibt sie schlicht konstant auf mironsoft_loyalty_reward stehen - ein Beispiel dafür, dass ein geerbtes Muster nicht jede einzelne Eigenschaft der Basis auch wirklich braucht, aber trotzdem konsistent mitgeführt wird.
Die Attribut-Wertetabellen: eine pro PHP-Skalartyp
Alle fünf Wertetabellen folgen demselben Muster wie catalog_product_entity_varchar & Co.: ein technischer value_id-Primärschlüssel, ein Verweis auf das Attribut (attribute_id), ein Verweis auf die Store View (store_id, 0 = Default/alle Stores), ein Verweis auf die Entität (entity_id) - und der eigentliche value. Die Kombination aus entity_id, attribute_id und store_id ist eindeutig: pro Entität und Attribut gibt es höchstens einen Wert je Store View.
<table name="mironsoft_loyalty_reward_entity_varchar" resource="default" engine="innodb"
comment="Mironsoft Loyalty Reward Varchar Attribute Values">
<column xsi:type="int" name="value_id" padding="10" unsigned="true"
nullable="false" identity="true" comment="Value ID"/>
<column xsi:type="smallint" name="attribute_id" padding="5" unsigned="true"
nullable="false" identity="false" default="0" comment="Attribute ID"/>
<column xsi:type="smallint" name="store_id" padding="5" unsigned="true"
nullable="false" identity="false" default="0" comment="Store ID"/>
<column xsi:type="int" name="entity_id" padding="10" unsigned="true"
nullable="false" identity="false" comment="Entity ID"/>
<column xsi:type="varchar" name="value" nullable="true" length="255" comment="Value"/>
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="value_id"/>
</constraint>
<constraint xsi:type="foreign"
referenceId="MIRONSOFT_LOYALTY_REWARD_ENTITY_VARCHAR_ENTITY_ID_MIRONSOFT_LOYALTY_REWARD_ENTITY_ENTITY_ID"
table="mironsoft_loyalty_reward_entity_varchar" column="entity_id"
referenceTable="mironsoft_loyalty_reward_entity" referenceColumn="entity_id"
onDelete="CASCADE"/>
<constraint xsi:type="unique"
referenceId="MIRONSOFT_LOYALTY_REWARD_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_STORE_ID">
<column name="entity_id"/>
<column name="attribute_id"/>
<column name="store_id"/>
</constraint>
<index referenceId="MIRONSOFT_LOYALTY_REWARD_ENTITY_VARCHAR_ATTRIBUTE_ID" indexType="btree">
<column name="attribute_id"/>
</index>
</table>Die übrigen vier Tabellen (_int, _decimal, _text, _datetime) sind strukturell identisch - Primärschlüssel, Fremdschlüssel, Unique-Constraint und Index bleiben exakt gleich, nur referenceId und Tabellenname ersetzen varchar durch den jeweiligen Typnamen. Es ändert sich ausschließlich die value-Spalte:
<!-- _int -->
<column xsi:type="int" name="value" nullable="true" identity="false" comment="Value"/>
<!-- _decimal -->
<column xsi:type="decimal" name="value" nullable="true" scale="4" precision="20" comment="Value"/>
<!-- _text -->
<column xsi:type="text" name="value" nullable="true" comment="Value"/>
<!-- _datetime -->
<column xsi:type="datetime" name="value" nullable="true" comment="Value"/>Achtung: Bewusst keine Fremdschlüssel-Beziehung von attribute_id auf eav_attribute.attribute_id - genau wie bei Magentos eigenen catalog_product_entity_*-Tabellen. Der Grund: eav_attribute wird von potenziell vielen verschiedenen Entity Types gemeinsam genutzt, und eine zu strikte referenzielle Integrität an dieser Stelle würde Performance kosten, ohne einen praktischen Sicherheitsgewinn zu bringen - der reguläre Attribut-Lebenszyklus läuft ohnehin ausschließlich über EAV-Setup-Code, nie über manuelles Löschen.
module.xml um Magento_Eav ergänzen
Die Fremdschlüssel auf eav_attribute_set in der Haupttabelle erfordern, dass Magento_Eav garantiert vor Mironsoft_Loyalty installiert ist - exakt dieselbe Überlegung wie in Kapitel 2 für Magento_Customer und Magento_Sales.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Mironsoft_Loyalty">
<sequence>
<module name="Magento_Customer"/>
<module name="Magento_Sales"/>
<module name="Magento_Eav"/>
</sequence>
</module>
</config>bin/magento setup:upgrade
bin/magento cache:flushTipp: Die referenceId-Konvention aus Kapitel 3 (<TABELLE>_<SPALTE>_<ZIELTABELLE>_<ZIELSPALTE>) gilt unverändert weiter - bei fünf fast identischen Wertetabellen ist sie sogar noch wichtiger, weil sich sonst Tippfehler zwischen den Tabellen kaum auffallen würden.
Sechs Tabellen ohne eine einzige Zeile PHP-Code - Kapitel 12 baut jetzt Model und ResourceModel, damit auf diese Tabellen überhaupt zugegriffen werden kann.