Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

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 der entity_id aus catalog_product_entity.
  • attribute_set_id - Fremdschlüssel auf eav_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 Beispiel reward-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.
app/code/Mironsoft/Loyalty/etc/db_schema.xml
<?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.

app/code/Mironsoft/Loyalty/etc/db_schema.xml (Ausschnitt: _varchar-Tabelle)
    <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.

app/code/Mironsoft/Loyalty/etc/module.xml
<?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:flush

Tipp: 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.