declarative schema

Requirements

Demonstrate use of schema. How to manipulate columns and keys using declarative schema? What is the purpose of whitelisting? How to use Data and Schema patches? How to manage dependencies between patch files?

Experiments

using db_schema.xml to add a new table

Based on 2.3.1, create a new module named VendorName_TestModule

create 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">
  <table name="order_custom_attribute" resource="default" engine="innodb" comment="order_custom_attribute">
    <column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity ID"/>
    <column xsi:type="varchar" name="foo" nullable="true" length="255" comment="foo"/>
    <column xsi:type="varchar" name="bar" nullable="true" length="255" comment="bar"/>
    <constraint xsi:type="primary" referenceId="PRIMARY">
      <column name="entity_id"/>
    </constraint>
  </table>
</schema>

If you already have install or upgrade script,you can convert them to db_schema.xml files.
To convert your install or upgrade script, run one of the following commands:

bin/magento setup:install --convert-old-scripts=1
bin/magento setup:upgrade --convert-old-scripts=1

To enable dry run mode, run one of the following commands:

bin/magento setup:install --dry-run=1
bin/magento setup:upgrade --dry-run=1

As a result of specifying the —dry-run=1 flag, Magento writes a log file at /var/log/dry-run-installation.log. This file contains all the DDL SQL statements that are generated during installation. You can use these SQL statements for debugging and optimizing performance processes.

Next,we will create a schema whitelist.

run:

bin/magento setup:db-declaration:generate-whitelist --module-name=VendorName_TestModule

We should get a file etc/db_schema_whitelist.json

{
    "order_custom_attribute": {
        "column": {
            "entity_id": true,
            "foo": true,
            "bar": true
        },
        "constraint": {
            "PRIMARY": true
        }
    }
}

Our module’s current version is 2.1.7

Now, run:

bin/magento setup:upgrade

Check the databse, now we have the table order_custom_attribute, it has three columns (entity_id, foo, bar)

delete column by edit db_schema.xml

Let’s edit 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">
  <table name="order_custom_attribute" resource="default" engine="innodb" comment="order_custom_attribute">
    <column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity ID"/>
    <column xsi:type="varchar" name="foo" nullable="true" length="255" comment="foo"/>
    <!--<column xsi:type="varchar" name="bar" nullable="true" length="255" comment="bar"/>-->
    <constraint xsi:type="primary" referenceId="PRIMARY">
      <column name="entity_id"/>
    </constraint>
  </table>
</schema>

We comment the bar column. Then we edit etc/module.xml make etup_version to be 2.1.8

run:

bin/magento setup:upgrade

Check table order_custom_attribute, it has two colums(entity_id, foo),the column bar has been removed.

If you delete db_schema_whitelist.json, the column drop won’t happen.

data patch example

Let’s create a sample data patch, Setup\Patch\Data\TestPatch.php

<?php
namespace VendorName\TestModule\Setup\Patch\Data;

use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchVersionInterface;
use Magento\Framework\Setup\Patch\PatchRevertableInterface;

class TestPatch implements DataPatchInterface, PatchRevertableInterface, PatchVersionInterface
{
    public function getAliases()
    {
        /**
         * This internal Magento method, that means that some patches with time can change their names,
         * but changing name should not affect installation process, that's why if we will change name of the patch
         * we will add alias here
         */
        return [];
    }

    public function apply()
    {
        // lets do something
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('TestPatch apply execute');
    }

    public static function getDependencies()
    {
        /**
         * This is dependency to another patch. Dependency should be applied first
         * One patch can have few dependencies
         * Patches do not have versions, so if in old approach with Install/Ugrade data scripts you used
         * versions, right now you need to point from patch with higher version to patch with lower version
         * But please, note, that some of your patches can be independent and can be installed in any sequence
         * So use dependencies only if this important for you
         */
        // return [
        //     SomeDependency::class
        // ];

        return [];
    }

    public function revert()
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('TestPatch revert execute');
    }


    public static function getVersion()
    {
        /**
         *  If the version number of the module in our database is higher than
         *  the version we specify here in our file, the patch will not execute.
         *  If it is equal to or lower than the version here, it will execute.
         */
        return '2.3.1';
    }
}

Our module’s current version is 2.1.9, this is lower than the version (2.3.1) we specify here in our file, so, after you run bin/magento setup:upgrade, you will see layout_block.xml log. This means our patch has been applied. Also, you will see our TestPatch in patch_list table.

Let’s remove it from patch_list table, and edit the version in our file to be 2.1.0, after run bin/magento setup:upgrade. you will see our path is added to patch_list table but not be applied.

run:

bin/magento module:uninstall --non-composer VendorName_TestModule

Ok, our patch is removed from patch_list table and the revert function executed.

Notes

Implementing declarative schema is not a requirement for Magento 2.3. However, upgrade scripts will be phased out in favor of declarative schema
Once you start with data patches, you cannot continue to use upgrade scripts.

Backward compatibility must be maintained. Therefore, declarative schema does not automatically delete database tables, columns or keys that are not defined in a db_schema.xml file. Declarative schema cannot delete these elements because these items can be declared somewhere else, such as in an Setup/UpgradeSchema.php file.

The //etc/db_schema_whitelist.json file provides a history of all tables, columns, and keys added with declarative schema. It is required to allow drop operations.

db_schema_whitelist.json is a temporary solution. It will be removed in the future, when upgrade scripts are no longer supported.

A data patch is a class that contains data modification instructions. It is defined in a <Vendor>/<Module_Name>/Setup/Patch/Data/<Patch_Name>.php file and implements \Magento\Framework\Setup\Patch\DataPatchInterface.

A schema patch contains custom schema modification instructions. These modifications can be complex. It is defined in a <Vendor>/<Module_Name>/Setup/Patch/Schema/<Patch_Name>.php file and implements \Magento\Framework\Setup\Patch\SchemaPatchInterface.

Currently, use data patch to add eav attributes.

Reference

Develop data and schema patches
Declarative Schema in Magento 2.3 and Higher – a Comprehensive Review

发表评论

电子邮件地址不会被公开。 必填项已用*标注