9.如何创建安装、升级、卸载脚本

后端开发2019-10-02

Magento 2 开发内容目录

本文主要研究一下 Magento2 模块中如何使用安装升级的 SQL 脚本。在你安装或升级一个模块时,你或许想要修改数据表结构或新增一些数据,Magento 2 为这些需求提供了一些类。

本节目录:

  • InstallSchema / InstallData
  • UpgradeSchema / UpgradeData
  • 更新数据表或数据
  • 更新数据表
  • 更新数据
  • 循环
  • 卸载

安装、更新、卸载 SQL 脚本简介

  • InstallSchema 这个类在模块安装时运行创建数据表结构
  • InstallData 这个类在模块安装时运行初始化数据表的数据
  • UpgradeSchema 这个类在模块更新时运行修改数据表结构
  • UpgradeData 这个类在模块更新时运行从数据表添加或删除数据
  • Recurring 循环
  • Uninstall 卸载

以上所有类都在文件夹: app/code/Vendor/Module/Setup。 在每次运行以下命令时安装或更新脚本会运行:

php bin/magento setup:upgrade

本章节继续使用前面的 HelloWorld 模块。

安装脚本: InstallSchema & InstallData

InstallSchema 和 InstallData 这两个类会在模块安装时运行

InstallSchema 会修改数据表结构。如下代码创建 aqrun_helloworld_post 数据表:

文件: app/code/Aqrun/HelloWorld/Setup/InstallSchema.php

<?php
namespace Aqrun\HelloWorld\Setup;
 
use \Magento\Framework\DB\Ddl\Table;
 
class InstallSchema implements \Magento\Framework\Setup\InstallSchemaInterface
{
    public function install(
        \Magento\Framework\Setup\SchemaSetupInterface $setup,
        \Magento\Framework\Setup\ModuleContextInterface $context
    ){
        $installer = $setup;
        $installer->startSetup();
 
        if (!$installer->tableExists('aqrun_helloworld_post')) {
            $table = $installer->getConnection()->newTable(
                $installer->getTable('aqrun_helloworld_post')
            )->addColumn(
                'post_id',
                Table::TYPE_INTEGER,
                null,
                [
                    'identity' => true,
                    'nullable' => false,
                    'primary'  => true,
                    'unsigned' => true,
                ],
                'Post ID'
            )->addColumn(
                'name',
                Table::TYPE_TEXT,
                255,
                ['nullable' => false],
                'Post name'
            )->addColumn(
                'url_key',
                Table::TYPE_TEXT,
                255,
                ['nullable' => false],
                'Post URL Key'
            )->addColumn(
                'post_content',
                Table::TYPE_TEXT,
                '64k',
                [],
                'Post Content'
            )->addColumn(
                'tags',
                Table::TYPE_TEXT,
                255,
                [],
                'Post Tags'
            )->addColumn(
                'status',
                Table::TYPE_INTEGER,
                1,
                [],
                'Post Status'
            )->addColumn(
                'featured_image',
                Table::TYPE_TEXT,
                255,
                [],
                'Post Featured Image'
            )->addColumn(
                'created_at',
                Table::TYPE_TIMESTAMP,
                null,
                ['nullable' => false, 'default' => Table::TIMESTAMP_INIT],
                'Created At'
            )->addColumn(
                'updated_at',
                Table::TYPE_TIMESTAMP,
                null,
                ['nullable' => false, 'default' => Table::TIMESTAMP_INIT_UPDATE],
                'Updated At'
            )->setComment('Post Table');
 
            $installer->getConnection()->createTable($table);
            $installer->getConnection()->addIndex(
                $installer->getTable('aqrun_helloworld_post'),
                $setup->getIdxName(
                    $installer->getTable('mageplaza_helloworld_post'),
                    ['name', 'url_key', 'post_content', 'tags', 'featured_image'],
                    \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_FULLTEXT
                ),
                ['name','url_key','post_content','tags','featured_image',],
                \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_FULLTEXT
            );
 
        }//if
 
        $installer->endSetup();
    }
}

代码解释:

这个类必须实现接口: \Magento\Framework\Setup\InstallSchemaInterface

这个类必须实现 install() 方法,并且有两个参数 SchemaSetupInterfaceModuleContextInterfaceSchemaSetupInterface 接口类型的 setup 对象提供了很多和数据库服务器进行交互的函数。ModuleContextInterface 只有一个方法 getVersion() 用来获取模块的当前版本号。

上面代码中我们创建了名为 aqrun_helloworld_post 的数据表,字段有: post_id, name, post_content,created_at 等。

InstallSchema 运行完成后,会执行 InstallData 类给数据表添加数据

文件: app/code/Aqrun/HelloWorld/Setup/InstallData.php

<?php
namespace Aqrun\HelloWorld\Setup;
 
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
 
class InstallData implements InstallDataInterface
{
    protected $_postFactory;
    public function __contruct(
        \Aqrun\HelloWorld\Model\PostFactory $postFactory
    ){
        $this->_postFactory = $postFactory;
    }
 
    public function install(
        ModuleDataSetupInterface $setup,
        ModuleContextInterface $context
    ){
        $data = [
            'name' => '测试文章标题',
            'post_content' => '测试正文内容好多内容',
            'url_key' => '/module-test/test-post-title.html',
            'tags' => '测试,内容,标题',
            'status' => 1
        ];
        $post = $this->_postFactory->create();
        $post->addData($data)->save();
    }
}

这个类和 InstallSchema 类的结构意义相同

更新脚本: UpgradeSchema & UpgradeData

这两个文件会在模块安装后或更新后都运行。这两个类和安装脚本类不同,它们在模块每次更新时都会运行。所以我们需要对比版本号并且按版本号把脚本分开,版本号指的是 app/code/Aqrun/HelloWorld/etc/module.xml 文件的 setup_version 属性值

本例中我们修改 setup_version 为 1.2.0

文件: app/code/Aqrun/HelloWorld/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="Aqrun_HelloWorld" setup_version="1.2.0">
    </module>
</config>

更新脚本

文件: app/code/Aqrun/HelloWorld/Setup/UpgradeSchema.php

<?php
namespace Aqrun\HelloWorld\Setup;
 
use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Famework\Setup\ModuleContextInterface;
 
class UpgradeSchema implements UpgradeSchemaInterface
{
    public function upgrade(
        SchemaSetupInterface $setup,
        ModuleContextInterface $context
    ){
        $installer = $setup;
        $installer->startSetup();
        if(version_compare($context->getVersion(), '1.2.0', '<')){
            $installer->getConnection()->addColumn(
                $installer->getTable('aqrun_helloworld_post'),
                'test',
                [
                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL,
                    'nullable' => true,
                    'length' => '12,4',
                    'comment' => 'test',
                    'after' => 'status'
                ]
            );
        }
        $installer->endSetup();
    }
}

中这个类中,定义了 upgrade() 方法,它会在模块每次更新后都执行。并对对比了版本号为每个版本分开添加脚本

更新数据

和 UpgradeSchema 类一样

文件: app/code/Aqrun/HelloWorld/Setup/UpgradeData.php

<?php
namespace Aqrun\HelloWorld\Setup;
 
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
 
class UpgradeData implements UpgradeDataInterface
{
    protected $_postFactory;
 
    public function __construct(
        \Aqrun\HelloWrold\Model\PostFactory $postFactory
    ){
        $this->_postFactory = $postFactory;
    }
 
    public function(
        ModuleDataSetupInterface $setup,
        ModuleContextInterface $context
    ){
        if(version_compare($context->getVersion(), '1.2.0', '<')) {
            $data = [
                'name' => '测试文章标题',
                'post_content' => '测试正文内容好多内容',
                'url_key' => '/module-test/test-post-title.html',
                'tags' => '测试,内容,标题',
                'status' => 1
            ];
            $post = $this->_postFactory->create();
            $post->addData($data)->save()
        }
    }
}

循环脚本 Recurring

循环脚本在每次执行 php bin/magento setup:upgrade 命令后安装脚本运行完成时都会运行。

这个脚本和 InstallSchema 类一样定义,只是类不同。代码实例可以查看系统文件: vendor/magento/module-indexer/Setup/Recurring.php

卸载脚本

系统提供了卸载模块的功能,可以删除所有模块相关的数据表和数据,就如同模块没有安装过一样。如下示例:

文件: app/code/Aqrun/HelloWorld/Setup/Uninstall.php

<?php
namespace Aqrun\HelloWorld\Setup;
 
use Magento\Framework\Setup\UninstallInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
 
class Uninstall implements UninstallInterface
{
    public function uninstall(
        SchemaSetupInterface $setup,
        ModuleContextInterface $context
    ){
        $installer = $setup;
        $installer->startSetup();
        $installer->getConnection()->dropTable($installer->getTable('aqrun_helloworld_post'));
        $installer->endSetup();
    }
}