Magento 2: tworzenie tabeli za pomocą db_schema.xml
Od Magento 2.3 mamy dodatkowy sposób na dokonywanie operacji na tabeli w bazie danych. W tym wpisie omówię tworzenie tabeli za pomocą db_schema.xml w Magento 2. Dzięki odpowiedniej deklaracji w xml, nie potrzebujemy pisać kodu skryptów dla poszczególnych wersji, gdy chcemy choćby dodać nową/usunąć starą kolumnę w tabeli. Magento priorytezuje declarative schema i uruchamia je przed skryptami typu patch data i patch schema.
Korzystanie ze schematów bazy danych
Aby stworzyć nową tabelę dla naszego modułu, potrzebujemy:
- Utworzyć plik db_schema.xml w katalogu etc modułu z odpowiednią definicją
- Wygenerować plik db_schema_whitelist.json za pomocą:
1 |
bin/magento setup:db-declaration:generate-whitelist --module-name=Anna_Guestbook |
- Zastosować nowy schemat do bazy danych:
1 |
bin/magento setup:upgrade |
- Ostatnim krokiem jest wyczyszczenie cache’a.
Baza danych do utworzenia
W notce o install, upgrade skryptach został przedstawiony przykład z księgą gości, gdzie została utworzona tabela guestbook. Tabela posiadała następujące kolumny:
- entry_id
- jako klucz główny,
- typ int, liczba całkowita bez znaku (unsigned),
- nie może być wartością pustą (null).
- customer_id
- jako klucz obcy,
- może być null,
- typu int, liczba całkowita bez znaku (unsigned),
- nadajmy też tej kolumnie index.
- user_name
- maks 255 znaków,
- jako string,
- może być null.
- subject
- maks 255 znaków,
- jako string,
- nie może być null.
- content
- typu tekstowego,
- nie może być null.
- created_at
- pole typu data z czasem,
- nie może być null.
- update_at
- pole typu data z czasem,
- nie może być null,
- ustawiane podczas aktualizacji wpisu.
Stwórzmy do tego odpowiednią konfiguracje.
Przykładowy plik schema_db.xml
Do stworzenia tabeli guestbook i jej kolumny potrzebujemy utworzyć plik schema_db.xml w katalogu etc naszego modułu o następującej zawartości:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?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"> <table name="guestbook" resource="default" engine="innodb" comment="Guestbook"> <column xsi:type="int" name="entry_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Guestbook Entry Id"/> <column xsi:type="int" name="customer_id" unsigned="true" nullable="true" identity="false" comment="Customer Id"/> <column xsi:type="varchar" name="user_name" nullable="true" length="255" comment="Username"/> <column xsi:type="varchar" name="subject" nullable="false" length="255" comment="Entry message"/> <column xsi:type="text" name="content" nullable="false" comment="Entry message"/> <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="entry_id"/> </constraint> <constraint xsi:type="foreign" referenceId="GUESTBOOK_CUSTOMER" table="guestbook" column="customer_id" referenceTable="customer_entity" referenceColumn="entity_id" onDelete="CASCADE"/> <index referenceId="GUESTBOOK_CUSTOMER_ID_CUSTOMER_ENTITY_ID" indexType="btree"> <column name="customer_id"/> </index> </table> </schema> |
Powinniśmy mieć na uwadzę, że wszelkie operacje/modyfikacje w ramach deklaracji schematu możemy wykonywać tylko względem tabel/kolumn stworzonych w db_schema.xml. Jeśli chcemy na przykład usunąć kolumnę, to powinna ona być stworzona przez konfigurację w db_schema.xml. Przyjrzyjmy się bliżej dostępny opcjom tworzenia/manipulowania tabeli/kolumny.
Dostępne opcje konfiguracyjne w db_schema.xml
Magento 2 udostępnia nam łatwą możliwość stworzenia/modyfikacji tabeli/kolumny. Poniżej lista dostępnych elementów do ustawienia.
<table>
Węzeł <table> posiada takie atrybuty jak:
- name — nazwa tabeli,
- engine — jaki rodzaj silnika bazy danych. Dozwolone wartości to innodb lub memory,
- resource — fragment bazy danych, na której ma być zainstalowana tabela. Dozwolone wartości to: ’default’, ’checkout’ lub ’sales’,
- comment — komentarz do tabeli.
- onCreate — jest to wyzwalacz (ang. trigger) DML, który umożliwia przeniesienie danych z istniejącej tabeli do nowo utworzonej tabeli. Ten rodzaj wyzwalacza działa tylko podczas tworzenia tabeli.
Wewnątrz węzła <table> mogą występować takie węzły jak:
- <column> — konfiguracja dotycząca kolumny,
- <constraint> — zależnie od typu możemy stworzyć klucze. Dostępne opcje to: primary, unique i foreign,
- <index> — pozwala nam zdefiniować indeks. Dostępne typy to: btree, fulltext lub hash.
<column>
Węzeł <column> posiada następujące atrybuty:
- xsi:type — określamy typ kolumny, który może być:
- blob,
- mediumblob,
- longblob,
- boolean,
- date,
- datetime,
- decimal,
- float,
- int,
- smallint,
- bigint,
- tinyint,
- json,
- real,
- double,
- text,
- mediumtext,
- longtext,
- timestamp,
- varbinary,
- varchar.
- default — pozwala na inicjalizację kolumny z określoną domyślną wartością.
- disabled — wyłącza lub usuwa zadeklarowaną tablicę, kolumnę lub indeks,
- identity — określenie, czy kolumna jest typu autoinrement czy nie,
- length — określa ilość znaków w kolumnie. Może być użyta dla typów char, varchar lub varbinary,
- nullable — określa czy dana kolumna może posiadać wartość pustą,
- onCreate — jest to wyzwalacz (ang. trigger) DML, która umożliwia przeniesienie danych z istniejącej kolumny do tej nowo utworzonej. Ten rodzaj wyzwalacza działa tylko podczas tworzenia kolumny,
- padding — określa rozmiar kolumny typów int, smallint, bigint, tinyint,
- precision — liczba dozwolonych cyfr w typach real, decimal, float, double,
- scale — liczba dozwolonych cyfr po przecinku w typach real, decimal, float, double,
- unsigned — określamy, czy kolumna typu numerycznego, może zawierać wartości dodanie i ujemne, czy tylko wartości dodanie.
<contraint>
Węzeł <constraint> posiada następujące atrybuty:
- type (wymagany) — typ ograniczenia, tutaj jedna z wartości: primary, unique lub foreign,
- referenceId (wymagany) — niestandardowy identyfikator, który jest używany do mapowania relacji w zakresie plików db_schema.xml. Rzeczywista encja w bazie danych ma wygenerowaną nazwę.
- Dla type określonego jako foreign wymagane jest zdefiniowanie poniższych atrybutów:
- table — nazwa tabeli, dla której definiujemy klucz obcy,
- column — nazwa kolumny w bieżącej tabeli, która odnosi się do określonej kolumny w innej tabeli,
- referenceTable — nazwa tabeli, do której się odwołujemy,
- referenceColumn — kolumna tabeli określonej w atrybucie referenceTable,
- onDelete — wyzwalacz klucza obcego. Dozwolone wartości: CASCADE, SET NULL lub NO ACTION.
- Dla ograniczenia schemat deklaratywny nie obsługuje wyzwalacza typu ON UPDATE, aby zachować wartości dla klucza jako niezmienne.
- Dla type określonego jako index potrzebujemy określić atrybut:
- indexType — wartość powinna być jedną z: btree, fulltext lub hash.
Skąd nazwa referenceId dla Indeksu?
W przykładzie mamy również referencję do indeksu:
1 2 3 |
<index referenceId="GUESTBOOK_CUSTOMER_ID_CUSTOMER_ENTITY_ID" indexType="btree"> <column name="customer_id"/> </index> |
Nazwa GUESTBOOK_CUSTOMER_ID_CUSTOMER_ENTITY_ID została utworzona przez konwencję
NAZWA_GŁÓWNEJ_TABELI_NAZWA_KLUCZA_OBCEGO_NAZWA_DRUGIEJ_TABELA_NAZWA_KLUCZA_GŁÓWNEGO. W zasadzie nie musimy sami budować nazwy indeksu, samo Magento nam to wygeneruje. Wystarczy wygenerować plik db_schema_whitelist.json, gdzie będzie informacja o nazwie wygenerowanej referencji. Nic nie stoi na przeszkodzie, aby ponownie potem wygenerować ten plik. Ostateczna wersja pliku db_schema_whitelist.json dla naszego przykładu wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "guestbook": { "column": { "entry_id": true, "customer_id": true, "user_name": true, "subject": true, "content": true, "created_at": true, "updated_at": true }, "constraint": { "PRIMARY": true, "GUESTBOOK_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID": true }, "index": { "GUESTBOOK_CUSTOMER_ID": true } } } |
Dodanie kolumny visible
W przykładzie do tabeli guestbook powstał odpowiedni plik db_schema.xml. Brakuje w niej kolumny visible, która w oryginalnym kodzie została dodana przez skrypt typu upgrade.
Kolumna visible:
- Typu boolean,
- Nie może być pusta (null),
- Ma domyślną wartość, która określa, aby jej nie pokazywać: 0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?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"> <table name="guestbook" resource="default" engine="innodb" comment="Guestbook"> <column xsi:type="int" name="entry_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Guestbook Entry Id"/> <column xsi:type="int" name="customer_id" unsigned="true" nullable="true" identity="false" comment="Customer Id"/> <column xsi:type="varchar" name="user_name" nullable="true" length="255" comment="Username"/> <column xsi:type="varchar" name="subject" nullable="false" length="255" comment="Entry message"/> <column xsi:type="text" name="content" nullable="false" comment="Entry message"/> <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"/> <column xsi:type="boolean" name="visible" nullable="false" default="0" comment="Entry visibility"/> <constraint xsi:type="primary" referenceId="PRIMARY"> <column name="entry_id"/> </constraint> <constraint xsi:type="foreign" referenceId="GUESTBOOK_CUSTOMER" table="guestbook" column="customer_id" referenceTable="customer_entity" referenceColumn="entity_id" onDelete="CASCADE"/> <index referenceId="GUESTBOOK_CUSTOMER_ID_CUSTOMER_ENTITY_ID" indexType="btree"> <column name="customer_id"/> </index> </table> </schema> |
Ponownie potrzebujemy wygenerować plik db_schema_whitelist.json za pomocą:
1 |
bin/magento setup:db-declaration:generate-whitelist --module-name=Anna_Guestbook |
- Zastosować zaktualizowany schemat do bazy danych:
1 |
bin/magento setup:upgrade |
- Wyczyścić cache
Magento porówna różnice pomiędzy bazą a obecnym schematem i zastosuje odpowiednie zmiany.
Możemy zobaczyć, że wygenerowany na nowo plik db_schema_whitelist.json nie ma on informacji czy coś zostało dodane, zawiera po prostu dodatkową linijkę:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{ "guestbook": { "column": { "entry_id": true, "customer_id": true, "user_name": true, "subject": true, "content": true, "created_at": true, "updated_at": true, "visible": true }, "constraint": { "PRIMARY": true, "GUESTBOOK_CUSTOMER_ID_CUSTOMER_ENTITY_ENTITY_ID": true }, "index": { "GUESTBOOK_CUSTOMER_ID": true } } } |
Powinniśmy mieć na uwadzę, że wszelkie operacje/modyfikacje w ramach deklaracji schematu możemy wykonywać tylko względem tabel/kolumn stworzonych w db_schema.xml. Jeśli chcemy na przykład usunąć kolumnę, to powinna ona być stworzona przez konfigurację w db_schema.xml.
Automatyczna konwersja starych skryptów do db_schema.xml
W przestawionym przykładzie pokazano, w jaki sposób przejść ze starego skryptu do użytkowania db_schema.xml. Istnieje również opcja, aby zrobić to automatycznie.
1 |
bin/magento setup:install --convert-old-scripts=1 |
1 |
bin/magento setup:upgrade --convert-old-scripts=1 |
Nie jest to całkiem bezproblematyczne, ponieważ wiąże się to z usunięciem wpisu modułu z tabeli setup_module. Trzeba zadbać o to, żeby była wykonana kopia danych.
Magento 2: Tworzenie grida w adminie za pomocą komponentu UI - Web Porgramming
15 października 2020 @ 20:47
[…] Wpisy na temat tworzenia tabel za pomocą skrptów jak i db_schema.xml. […]
Magento 2: tworzenie modeli CRUD - Web Programming
25 października 2023 @ 21:44
[…] Magento 2: tworzenie tabeli za pomocą db_schema.xml (od Magento 2.3). […]