{"id":135685,"date":"2019-10-03T04:16:36","date_gmt":"2019-10-03T04:16:36","guid":{"rendered":"https:\/\/inchoo.net\/?p=35423"},"modified":"2019-10-03T04:16:36","modified_gmt":"2019-10-03T04:16:36","slug":"declarative-schema-feature-in-magento-2","status":"publish","type":"post","link":"https:\/\/www.sushilkumar.ind.in\/blog\/magento-2\/declarative-schema-feature-in-magento-2\/","title":{"rendered":"Declarative Schema feature in Magento 2"},"content":{"rendered":"<p>First of all, what is declarative schema in Magento 2? It is a new way of working with database without developers having to write various scripts for each new module version. It was introduced in 2018 with Magento 2.3 and it&#8217;s one of the major changes. In this article you will learn how to use declarative schema and apply data patches.<span id=\"more-35423\"><\/span><\/p>\n<h2>Why declarative schema?<\/h2>\n<p>What are the advantages of using declarative schema? In short, before it, we had to write database scripts in PHP which is not a perfect solution. That&#8217;s because when you upgrade Magento to a version several releases ahead of the installed version, all the upgrade scripts between those two versions will still be executed. In other words, this creates unnecessarily complex situations. The new approach allows us to declare the final state of the database and the system automatically adjusts to it. Furthermore, when you uninstall the module, data will be deleted.<\/p>\n<h2>Declarative Schema Configuration<\/h2>\n<p>Let&#8217;s say you have a module with version 1.0.0 and the latest version is 1.0.3. When you upgrade it, script changes for 1.0.1 and 1.0.2 will also be applied. This is less than ideal because Magento applies changes blindly. What that means is that in one version you might introduce a column and then delete it in the very next. That&#8217;s one of the problems declarative schema eliminates. Using it, Magento determines the differences between the current table structure and what it should look like.<\/p>\n<p>You&#8217;ll have to <a href=\"https:\/\/inchoo.net\/magento-2\/how-to-create-a-basic-module-in-magento-2\/\">create a new module<\/a> before we dig into working with database.<\/p>\n<p>In the Module\/etc\/ folder create db_schema.xml. This is the file where you will define your tables, columns, pretty much everything you need. I made a simple example with two tables to show you how to do it.<\/p>\n<pre class=\"ish\"><code class=\"language-xml\"><span class=\"sc3\"><span class=\"re1\">&lt;?xml<\/span> <span class=\"re0\">version<\/span>=<span class=\"st0\">&quot;1.0&quot;<\/span><span class=\"re2\">?&gt;<\/span><\/span>\n<span class=\"sc3\"><span class=\"re1\">&lt;schema<\/span> <span class=\"re0\">xmlns:xsi<\/span>=<span class=\"st0\">&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;<\/span><\/span>\n<span class=\"sc3\"> <span class=\"re0\">xsi:noNamespaceSchemaLocation<\/span>=<span class=\"st0\">&quot;urn:magento:framework:Setup\/Declaration\/Schema\/etc\/schema.xsd&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;table<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;inchoo_declarative_schema1&quot;<\/span> <span class=\"re0\">resource<\/span>=<span class=\"st0\">&quot;default&quot;<\/span> <span class=\"re0\">engine<\/span>=<span class=\"st0\">&quot;innodb&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;Inchoo Table 1&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;int&quot;<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;table_1_id&quot;<\/span> <span class=\"re0\">padding<\/span>=<span class=\"st0\">&quot;10&quot;<\/span> <span class=\"re0\">unsigned<\/span>=<span class=\"st0\">&quot;true&quot;<\/span> <span class=\"re0\">nullable<\/span>=<span class=\"st0\">&quot;false&quot;<\/span> <span class=\"re0\">identity<\/span>=<span class=\"st0\">&quot;true&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;ID&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;varchar&quot;<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;name&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;Name&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;constraint<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;primary&quot;<\/span> <span class=\"re0\">referenceId<\/span>=<span class=\"st0\">&quot;PRIMARY&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;table_1_id&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;\/constraint<span class=\"re2\">&gt;<\/span><\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;\/table<span class=\"re2\">&gt;<\/span><\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;table<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;inchoo_declarative_schema2&quot;<\/span> <span class=\"re0\">resource<\/span>=<span class=\"st0\">&quot;default&quot;<\/span> <span class=\"re0\">engine<\/span>=<span class=\"st0\">&quot;innodb&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;Inchoo Table 2&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;int&quot;<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;table_2_id&quot;<\/span> <span class=\"re0\">padding<\/span>=<span class=\"st0\">&quot;10&quot;<\/span> <span class=\"re0\">unsigned<\/span>=<span class=\"st0\">&quot;true&quot;<\/span> <span class=\"re0\">nullable<\/span>=<span class=\"st0\">&quot;false&quot;<\/span> <span class=\"re0\">identity<\/span>=<span class=\"st0\">&quot;true&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;ID&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;text&quot;<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;content&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;Content&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;constraint<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;primary&quot;<\/span> <span class=\"re0\">referenceId<\/span>=<span class=\"st0\">&quot;PRIMARY&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;table_2_id&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;\/constraint<span class=\"re2\">&gt;<\/span><\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;\/table<span class=\"re2\">&gt;<\/span><\/span><\/span>\n<span class=\"sc3\"><span class=\"re1\">&lt;\/schema<span class=\"re2\">&gt;<\/span><\/span><\/span><\/code><\/pre>\n<p>Running setup:upgrade will create two tables, inchoo_declarative_schema1 and inchoo_declarative_schema2 with IDs and an additional column. As you can see, the ID columns are set as primary key.<\/p>\n<h4>Tables<\/h4>\n<p>The table node can contain three different types of subnodes:<\/p>\n<ul>\n<li>column<\/li>\n<li>constraint<\/li>\n<li>index<\/li>\n<\/ul>\n<h5>Column<\/h5>\n<p>Column is used to define a column in the table. Its \u201cxsi:type\u201d defines its type (boolean, date, int\u2026). There are more attributes except for those you can see in our image (such as default, precision, scale) but in this article I won\u2019t go into details about what each of them does.<\/p>\n<h5>Constraint<\/h5>\n<p>Constraint always contains the \u201ctype\u201d and \u201creferenceId\u201d attributes. Type can be primary, unique or foreign. ReferenceId is a custom identifier we use for relation mapping in the scope of db_schema.xml files. The recommended way to set the value of the referenceId attribute is to use the value from db_schema_whitelist.json. For an explanation on how to generate whitelist, continue reading.<\/p>\n<h5>Index<\/h5>\n<p>We use the index subnode for speeding up DQL operations and it contains two attributes, \u201creferenceId\u201d and \u201cindexType\u201d. We already explained what referenceId is and how to get its value. The value of indexType must be btree, fulltext or hash.<\/p>\n<p>In case you ran setup upgrade and then remembered you forgot a column or anything, don\u2019t worry, you don\u2019t need any additional files! You can just add anything you missed inside the same db_schema.xml and on the next setup upgrade your database will be updated.<\/p>\n<p>The same goes for table or column deletion. Simply delete the table or column from db_schema.xml and run setup upgrade. However, if you want to drop a column declared in another module, you should redeclare it with the \u201cdisabled=true\u201d attribute. It\u2019s also important to know that you can only drop a column if it exists in the db_schema_whitelist.json file.<\/p>\n<p>Table and column renaming is supported and here\u2019s how to do it. All you have to do is change the \u201cname\u201d attribute on the table declaration and add the &#8220;onCreate&#8221; attribute. In our case, the table declaration would look like this if we wanted to rename inchoo_declarative_schema1:<\/p>\n<pre class=\"ish\"><code class=\"language-xml\"><span class=\"sc3\"><span class=\"re1\">&lt;table<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;inchoo_declarative_schema1_renamed&quot;<\/span> <span class=\"re0\">onCreate<\/span>=<span class=\"st0\">&quot;migrateDataFromAnotherTable(inchoo_declarative_schema1)&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;int&quot;<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;table_1_id&quot;<\/span> <span class=\"re0\">padding<\/span>=<span class=\"st0\">&quot;10&quot;<\/span> <span class=\"re0\">unsigned<\/span>=<span class=\"st0\">&quot;true&quot;<\/span> <span class=\"re0\">nullable<\/span>=<span class=\"st0\">&quot;false&quot;<\/span> <span class=\"re0\">identity<\/span>=<span class=\"st0\">&quot;true&quot;<\/span><\/span>\n<span class=\"sc3\"> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;ID&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;varchar&quot;<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;name&quot;<\/span> <span class=\"re0\">comment<\/span>=<span class=\"st0\">&quot;Name&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;constraint<\/span> <span class=\"re0\">xsi:type<\/span>=<span class=\"st0\">&quot;primary&quot;<\/span> <span class=\"re0\">referenceId<\/span>=<span class=\"st0\">&quot;PRIMARY&quot;<\/span><span class=\"re2\">&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;column<\/span> <span class=\"re0\">name<\/span>=<span class=\"st0\">&quot;table_1_id&quot;<\/span><span class=\"re2\">\/&gt;<\/span><\/span> <span class=\"sc3\"><span class=\"re1\">&lt;\/constraint<span class=\"re2\">&gt;<\/span><\/span><\/span>\n<span class=\"sc3\"><span class=\"re1\">&lt;\/table<span class=\"re2\">&gt;<\/span><\/span><\/span><\/code><\/pre>\n<p>Renaming is done by actually removing the table with the old name and creating the table with the new name while keeping all your data.<\/p>\n<h2>Dry run<\/h2>\n<p>One of the best novelties with this approach is the dry run mode. With it you can examine all the DDL SQL statements generated during the installation. Your data and schemas will remain the same so this is essentially a testing tool.<\/p>\n<p>You can enable dry run mode using the following commands:<\/p>\n<pre class=\"ish\"><code class=\"language-bash\">bin<span class=\"sy0\">\/<\/span>magento setup:install <span class=\"re5\">--dry-run<\/span>=<span class=\"nu0\">1<\/span><\/code><\/pre>\n<p>or<\/p>\n<pre class=\"ish\"><code class=\"language-bash\">bin<span class=\"sy0\">\/<\/span>magento setup:upgrade <span class=\"re5\">--dry-run<\/span>=<span class=\"nu0\">1<\/span><\/code><\/pre>\n<p>After running it, Magento creates a log at var\/log\/dry-run-installation.log. There you can see the generated DDL SQL statements and use them for debugging or optimizing.<br \/>\nI added another column to the inchoo_declarative_schema2 table and run setup upgrade with dry run mode enabled:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-35445 size-medium\" src=\"https:\/\/www.sushilkumar.ind.in\/blog\/wp-content\/uploads\/2019\/10\/declarative-schema-feature-in-magento-2.png\" alt=\"Dry Run\" width=\"760\" height=\"340\" \/><br \/>\nIn the log you can see that I tried to add column \u2018log_test\u2019 but it won\u2019t actually happen before I run setup upgrade without dry run mode. Extremely useful, isn\u2019t it?<\/p>\n<h2>Whitelist<\/h2>\n<p>Since backward compatibility must be maintained, declarative schema doesn\u2019t automatically delete database tables, columns or keys not defined in db_schema.xml.<br \/>\nThis is one of the reasons we have db_schema_whitelist.json. It shows a history of all tables, columns and keys added with declarative schema and it\u2019s required for drop operations. After running setup upgrade or install, you can generate it with the following command:<\/p>\n<pre class=\"ish\"><code class=\"language-bash\">bin<span class=\"sy0\">\/<\/span>magento setup:db-declaration:generate-whitelist<\/code><\/pre>\n<p>This will create a file inside your etc folder called db_schema_whitelist.json. For instance, our db_schema_whitelist.json will look like this:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-35448 size-medium\" src=\"https:\/\/www.sushilkumar.ind.in\/blog\/wp-content\/uploads\/2019\/10\/declarative-schema-feature-in-magento-2-1.png\" alt=\"Whitelist\" width=\"760\" height=\"305\" \/><br \/>\nThere are options you can add at the end of that command. For instance,\u00a0 you can use &#8220;&#8211;module-name=YourModule&#8221; to specify the module you want to generate a whitelist for. Similarly, you could also set &#8220;&#8211;module-name=all&#8221; although it will generate a whitelist for all modules by default.<\/p>\n<p>It is recommended to generate a new whitelist for each release that contains changes in the db_schema.xml.<\/p>\n<h2>Data patches<\/h2>\n<p>In this article I will only give you an overview on what data patches are and why we use them. In short, data patches are classes with data modification instructions. Patches are applied only once and a list of those applied patches can be found in the patch_list table in database. All patches that are not applied will be applied when you run setup upgrade.<br \/>\nYou should create your data patch inside Module\/Setup\/Patch\/Data folder. It has to implement \\Magento\\Framework\\Setup\\Patch\\DataPatchInterface.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-35446 size-medium\" src=\"https:\/\/www.sushilkumar.ind.in\/blog\/wp-content\/uploads\/2019\/10\/declarative-schema-feature-in-magento-2-2.png\" alt=\"Data Patch\" width=\"760\" height=\"556\" \/><\/p>\n<p>As you can see, we got 3 methods, getDependencies(), getAliases(), and apply(). Since patches can depend on other patches, you can define their dependencies in the getDependencies() method:<\/p>\n<pre class=\"ish\"><code class=\"language-php\"><span class=\"kw2\">public<\/span> static <span class=\"kw2\">function<\/span> getDependencies<span class=\"br0\">&#040;<\/span><span class=\"br0\">&#041;<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"kw1\">return<\/span> <span class=\"br0\">[<\/span> Module\\Setup\\Patch\\Data\\Patch<span class=\"sy0\">::<\/span><span class=\"kw2\">class<\/span> <span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">&#125;<\/span><\/code><\/pre>\n<p>The method getAliases() allows us to add patch aliases if we have to change the name of the patch.<br \/>\nThe method you\u2019ll be using the most is apply(). This is where your code you want to apply in the patch goes. For example, this is the apply() method in Magento\\Catalog\\Setup\\Patch\\Data\\DisallowUsingHtmlForProductName class:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-35447 size-medium\" src=\"https:\/\/www.sushilkumar.ind.in\/blog\/wp-content\/uploads\/2019\/10\/declarative-schema-feature-in-magento-2-3.png\" alt=\"Apply method\" width=\"760\" height=\"190\" \/><\/p>\n<p>In conclusion, the declarative schema feature makes it easier for developers to work with the database. Furthermore, the process is faster and much simpler than it was before, which means performance will be improved. <\/p>\n<p>While currently implementing declarative schema is not required for Magento 2.3, it is highly recommended you learn it as it will replace upgrade scripts in the future.<\/p>\n<p>And if you want to see how we can help you with your development process, <a href=\"https:\/\/inchoo.net\/contact\/\">get in touch<\/a> to start the conversation!<\/p>\n<p>The post <a rel=\"nofollow\" href=\"https:\/\/inchoo.net\/magento-2\/declarative-schema\/\">Declarative Schema feature in Magento 2<\/a> appeared first on <a rel=\"nofollow\" href=\"https:\/\/inchoo.net\">Inchoo<\/a>.<\/p>\n<h1><a target=\"_blank\" href=\"http:\/\/www.circulatetechnology.com\/\">Click here for more informations about top website development services <\/a><\/h1>\n","protected":false},"excerpt":{"rendered":"<p>First of all, what is declarative schema in Magento 2? It is a new way of working with database without developers having to write various scripts for each new module version. It was introduced in 2018 with Magento 2.3 and it&#8217;s one of the major changes. In this article you will learn how to use &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[1121,14113,20,14114],"tags":[],"class_list":["post-135685","post","type-post","status-publish","format-standard","","category-database","category-declarative-schema","category-magento-2","category-tutorials"],"jetpack_publicize_connections":[],"acf":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p99pkJ-zit","_links":{"self":[{"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/posts\/135685"}],"collection":[{"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/comments?post=135685"}],"version-history":[{"count":0,"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/posts\/135685\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/media?parent=135685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/categories?post=135685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sushilkumar.ind.in\/blog\/wp-json\/wp\/v2\/tags?post=135685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}