Notes from the Team

Upgrade and Installation Scripts in Magento 2

Magento

Magento Logo

In this article we will be discussing installation and upgrade scripts for custom modules in Magento 2. If you want to create a database table, modify a table, or insert some data when your module is installed or updated then these scripts are what handle those actions. This article assumes you have completed our custom module creation tutorial.

Need help with more advanced module behaviours? Contact the Richmond, Virginia Magento experts at Ameronix.

Types of Installation Scripts

There are a few differences between how Magento 1.x and Magento 2 handle installation/upgrade scripts. Previously, in Magento 1.x, upgrade scripts were seperate files in the form of ‘upgrade-1.0.0-1.1.0.php’. In Magento 2 all installation and upgrade files have been put into one file per action. So there is one upgrade script in which you must handle all version numbers you wish to upgrade, and there is one installation script which runs when the module is first installed. The official docs on custom module lifecycles can be found here.

  • InstallSchema - Runs when the module is first installed
  • UpgradeSchema - Runs every time that the version number in etc/module.xml is changed and does not match the version number in the setup_module table as the current version. This file handles all version upgrades by comparing current version number with each specific upgrade version
  • InstallData - Runs when the module is first installed, after InstallSchema, used to insert data into the table or
  • UpgradeData - Runs every time that the version number in etc/module.xml is changed and does not match the version number in the setup_module table. This file handles all data upgrades by comparing current version number with each specific upgrade version
  • Recurring - Runs after any module runs a schema installation/upgrade and handles any finalization changes to the schema. This allows this module to do ‘post-processing’ on changes of other modules if needed.
  • RecurringData - Runs after any module runs a data installation/upgrade and handles any finalization changes to the data. This allows this module to do ‘post-processing’ on changes of other modules if needed.
  • Uninstall - Runs when the module is uninstalled via the CLI or Component Manager, handles any database cleanup or other tasks related to module removal

Creating Installation Scripts

We are going to create a new custom module to try out these features. In our app/code/Training folder let’s create a SetupTesting module. Remember from our custom module setup lesson that we need to create a few files first.

SetupTesting/registration.php

<?php \Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Training_SetupTesting',
   __DIR__
);

SetupTesting/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="Training_SetupTesting" setup_version="0.1.0">
   </module>
</config>

Next we are going to create a SetupTesting/Setup/InstallSchema.php file. This file will be executed when this module is first installed and will handle creating our database.

SetupTesting/Setup/InstallSchema.php

<?php
namespace Training\SetupTesting\Setup;

use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Ddl\Table;

class InstallSchema implements InstallSchemaInterface {

   public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) {
       $installer = $setup;
       $installer->startSetup();

       $table = $installer->getConnection()->newTable(
           $installer->getTable( 'store_locations' )
       )->addColumn(
           'store_id',
           Table::TYPE_SMALLINT,
           null,
           [ 'identity' => true, 'nullable' => false, 'primary' => true ],
           'Store ID'
       )->addColumn(
           'name',
           Table::TYPE_TEXT,
           255,
           [ 'nullable' => false ],
           'Store Name'
       )->addColumn(
           'address',
           Table::TYPE_TEXT,
           255,
           [ 'nullable' => false ],
           'Store Address'
       )->addColumn(
           'is_active',
           Table::TYPE_SMALLINT,
           null,
           [ 'nullable' => false, 'default' => '1' ],
           'Is Store Active'
       )->addIndex(
           $setup->getIdxName(
               $setup->getTable( 'store_locations' ),
               [ 'name', 'address' ],
               AdapterInterface::INDEX_TYPE_FULLTEXT
           ),
           [ 'name', 'address' ],
           [ 'type' => AdapterInterface::INDEX_TYPE_FULLTEXT ]
       )->setComment(
           'Store Locations Table'
       );

       $installer->getConnection()->createTable( $table );

       $installer->endSetup();
   }
}

This install file runs when the module is first installed via php bin/magento setup:upgrade. Here we are creating a table to store a list of retail store locations. The table is named store_locations, with columns store_id, name, address, and is_active. Next we will also create a InstallData.php file in our Setup directory.

SetupTesting/Setup/InstallData.php

<?php
namespace Training\SetupTesting\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;

class InstallData implements InstallDataInterface {

   public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {

       $data = [
           [
               'name' => 'Testing Store',
               'address' => '123 Testing Street'
           ],
           [
               'name' => 'Second Testing Store',
               'address' => '456 Testing Street'
           ]
       ];

       $setup->getConnection()
           ->insertMultiple($setup->getTable('store_locations'), $data);
   }
}

This is to insert some data into our table so that we can do something with it later. This file will also run when the module is initially installed, but will happen after InstallSchema. If we now run php bin/magento setup:upgrade then our module will install and run the InstallSchema and InstallData scripts. After it completes, use the database viewer of your choice to ensure that we have the table and data in our database.

Database Rows Screenshot

So now we’ve created some schema and data installation scripts. But what if later we wanted to change something about the schema or data? We can use UpgradeSchema/UpgradeData scripts in order to handle this.

Creating Upgrade Scripts

SetupTesting/Setup/UpgradeSchema.php

<?php

namespace Training\SetupTesting\Setup;

use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;

class UpgradeSchema implements UpgradeSchemaInterface {

   public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) {
       $installer = $setup;

       if (version_compare($context->getVersion(), '0.2.0') < 0) {
           $installer->getConnection()->addColumn($installer->getTable('store_locations'), 'custom_value', array(
               'type' => Table::TYPE_TEXT,
               'nullable' => false,
               'length' => 255,
               'after' => null, //Column name to insert new column after
               'comment' => 'Testing Adding Column'
           ));
       }
   }
}

Here we are checking the version number, and if we have a lower version than what we are looking for then execute the upgrade logic. It will get the table we created in our InstallSchema, and add a column named ‘custom_value’ to it. Next we will create an UpgradeData script

SetupTesting/Setup/UpgradeData.php

<?php
namespace Training\SetupTesting\Setup;

use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;

class UpgradeData implements UpgradeDataInterface
{
   public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
   {
       if (version_compare($context->getVersion(), '0.2.0') < 0) {
           $setup->getConnection()->update($setup->getTable('store_locations'), ['custom_value' => 'Some Value']);
       }

   }
}

We are doing the same version comparison logic here and then updating all rows in the table to have a value of ‘Some Value’ for our new ‘custom_value’ column. Next we just need to change the version number in our module.xml file.

SetupTesting/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="Training_SetupTesting" setup_version="0.2.0">
   </module>
</config>

If we run the CLI setup:upgrade command then these changes will apply. You can check this by looking at the table to see if the new column is present with our updated data. If it has not applied, check the version number of our module in the setup_module table and ensure it is on version 0.2.0 now. If not, make sure you updated the version in the module.xml

Today we have covered what the various types of installation and upgrade scripts are and how to create them. We have dealt with creating and manipulating database tables using these scripts. Next in this series we will be covering the difference between product types and then how to add attributes to products via installation/upgrade scripts.

About The Author

David Friend
David Friend

Web Developer

The Next Step

Connect

[email protected] (804) 272-1200