3. Magento2 中模型 CRUD

后端开发2019-06-12

Magento 2 开发内容目录

通过 Magento 2 的模型可以很容易管理数据库数据,不需要写很多代码来实现基础的 CRUD。CRUD 代表新增(create)、读取(read)、更新(update)和删除(delete)。本节主要了解如何创建数据表、模型(model)、资源模型(resource model)和资源模型集合(resource model collection)及数据库的相关操作。

开始之前先定好要用到的数据表,表名 aqrun_helloworld_post ,字段如下:

  • post_id - 文章的唯一标识 ID
  • name - 文章标题
  • url_key - URL
  • post_content - 文章正文
  • tags - 标签
  • status - 状态
  • featured_image - 图片
  • created_at - 创建时间
  • updated_at - 更新时间

创建模型有如下步骤:

  • 1 安装脚本(Setup Script)
  • 2 创建模型(Model)
  • 3 创建资源模型(Resource Model)
  • 4 创建资源模型集合(Resource Model Collection)
  • 5 工厂对象(Factory Object)

第一步 添加安装脚本

首先为我们的模型创建数据表,需要增加安装配置文件

app/code/Aqrun/HelloWorld/Setup/InstallSchema.php

这个文件会在模块安装时执行一次。使用如下代码创建上面的文章表

<?php
namespace Aqrun\HelloWorld\Setup;
 
use Magento\Framework\DB\Ddl\Table;
 
class InstallSchema implements \Aqrun\Framework\Setup\InstallSchemaInterface
{
    public function install(
        \Magento\Framework\Setup\SchemaSetupInterface $setup,
        \Magento\Framework\Setup\ModuleContextInterface $context
    ){
        $installer = $setup;
        $installer->startSetup();
        if (!$intaller->tableExists('aqrun_helloworld_post')) {
            $installer->getConnection()->newTable(
                $installer->getTable('aqrun_helloworld_post')
            )->addColumn(
                'post_id',
                Table::TYPE_INTERGER,
                null,
                [
                    'identity' => true,
                    'nllable' => 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();
 
    }
}

以上代码实现如何创建数据表。要注意的是系统会在模块第一次安装时自动运行这个文件。如果模块已经安装,这时需要更新模块就要把创建表的代码写在 UpgradeSchema.php 文件,并且修改 module.xml 文件的 setup_version 安装版本号值,改大一些,app/code/Aqrun/HelloWorld/etc/module.xml

内容如:

文件: 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.1.0">
    </module>
</config>

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

namespace Aqrun\HelloWorld\Setup;
 
use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
 
class UpgradeSchema implements UpgradeSchemaInterface
{
    public function upgrade(
        SchemaSetupInterface $setup,
        ModuleContextInterface $context
    ){
        $installer = $setup;
        $installer->startSetup();
        if (version_compare($context->getVersion(), '1.1.0', '<')) {
            if (!$installer->tableExists('aqrun_helloworld_post')) {
                $table = $installer->getConnection()->newTable(
                    $installer->getTable('aqrun_helloworld_post')
                )->addColumn(
                    'post_id',
                    Table::TYPE_INTERGER,
                    null,
                    [
                        'identity' => true,
                        'nllable' => 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('aqrun_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 not table exists
        }// if version compare
    } //
 
}
 

然后运行更新的命令:

php bin/magento setup:upgrade

更新完成可以继续执行静态内容发布命令:

php bin/magento setup:static-content:deploy

现在数据库中应该就有 aqrun_helloworld_post 数据表,字段和上面一样。如果没有创建成功,或许是由于在你添加内容到 InstallSchema.php 文件前运行过上面的命令。这时需要手动清除数据表信息,在 setup_module 表找到并删除 aqrun_helloworld_post 这一行数据。然后再运行上面的命令试下。

InstallSchema.php 文件是用来创建数据表结构的, 如果要在安装时添加数据,需要使用 InstallData.php 文件:

app/code/Aqrun/HelloWorld/Setup/InstallData.php

如何使用可以到系统找如下文件查看:

  • vendor/magento/module-tax/Setup/InstallData.php
  • vender/magento/module-customer/Setup/InstallData.php
  • vendor/magento/module-catalog/Setup/InstallData.php

上面提到这些安装文件是模块第一次安装时使用的,如果要修改数据表并更新模块,要使用 UpgradeSchema.phpUpgradeData.php

第二步 创建模型

模型是 MVC 架构中很大一坨内容。Magento 2 模型有很多不同的功能如数据管理、安装或更新模块。这里只讨论数据的 CRUD 操作。我们需要创建模型、资源模型、资源模型集合来管理 aqrun_helloworld_post 表的数据。

创建模型文件:

app/code/Aqrun/HelloWorld/Model/Post.php

内容:

<?php
namespace Aqrun\HelloWorld\Model;
 
use Magento\Framework\Model\AbstractModel;
use Magento\Framework\DataObject\IdentityInterface;
 
class Post extends AbstractModel implements IdentityInterface
{
    const CACHE_TAG = 'aqrun_helloworld_post';
    protected $_cacheTag = 'aqrun_helloworld_post';
    protected $_eventPrefix = 'aqrun_helloworld_post';
 
    protected function _construct()
    {
        $this->_init('Aqrun\HelloWorld\Model\ResourceModel\Post');
    }
 
    public function getIdentities()
    {
        return [self::CACHE_TAG . '_' . $this->getId()];
    }
 
    public function getDefaultValues()
    {
        $values = [];
        return $values;
    }
}

模型继承自 AbstractModelMagento\Framework\Model\AbstractModel 并实现接口 Magento\Framework\DataObject\IdentityInterfaceIdentityInterface 强制模型类必须实现返回模型唯一 ID 的 getIdentities() 方法。如果在数据库内容修改之后需要缓存清除之类的操作来显示前端内容就必须使用这个接口。

__construct() 构造方法在模型初始化时会执行,每一个 CURD 模型都必须使用构造方法调用 _init() 方法。_init() 方法定义了实际获取数据库信息的资源模型。如代码我们定义了资源模型: `Aqrun\Post\Model\ResourceModel\Post'。最后是一些变量:

  • $_eventPrefix 触发事件时的前缀
  • $_eventObject 获取事件对象的名称
  • $_cacheTag 缓存用的唯一 ID

第三步 创建资源模型

如你所见,模型文件包含所有数据库相关处理逻辑,并不运行实际的 SQL 操作,而这些操作是在资源模型中定义的。现在添加资源模型:app/code/Aqrun/HelloWorld/Model/ResourceModel/Post.php

代码:

namespace Aqrun\Helloworld\Model\ResourceModel;
 
class Post extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
    public function __construct(
        \Magento、Framework\Model\ResouceModel\Db\Context $context
    ){
        parent::__construct($context);
    }
 
    protected function _construct()
    {
        $this->init('aqrun_helloworld_post', 'post_id');
    }
}

资源模型必须继承虚类 \Magento\Framework\Model\ResourceModel\Db\AbstractDb。这个类包含从数据库获取信息的功能逻辑。

和模型类一样,资源模型类必须有 __construct() 构造方法,这个方法会调用定义了数据表名和主键的 _init() 函数。上面代码我们的表是 aqrun_helloworld_post 主键为 post_id

第四步 创建资源模型集合 - 获取模型集合

模型集合可以看作是资源模型,但可以筛选和获取表数据的集合。集合模型类定义在:

app/code/Aqrun/HelloWorld/Model/ResourceModel/Post/Collection.php

代码:

<?php
namespace Aqrun\HelloWorld\Model\ResourceModel\Post;
 
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
    protected $_idFieldName = 'post_id';
    protected $_eventPrefix = 'aqrun_helloworld_post_collection';
    protected $_eventObject = 'post_collection';
 
    protected function _construct()
    {
        $this->_init(\Aqrun\HelloWorld\Model\Post::class, \Aqrun\HelloWorld\Model\ResourceModel\Post::class);
    }
}

集合类需要继承类: \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection 并且在构造函数初始化模型和资源模型。

第五步 工厂对象

我们已经实现了创建数据表、模型、资源模型、和集合。那如何使用他们呢?

这里讨论一下模型的工厂对象。我们知道面向对象里,工厂方法是用来初始化对象的,而在 Magento,工厂对象也做同样的事。

工厂类名称是模型类名后面加上 'Factory' 关键字。所以我们的工厂类是 PostFactory。 我们不需要创建这个类,Magento 系统可以自动生成。当 Magento 的对象管理器碰到 'Factory' 结尾的类名时,如果没有创建则会自动在 var/generation 目录生成。可以找到工厂类在:

var/generation/<vendor_name>/<module_name>/Model/ClassFactory.php

此例中,目录是:

var/generation/Aqrun/HelloWorld/Model/PostFactory.php

要实例化一个模型对象我们需要使用到构造函数的依赖注入获取工厂对象,然后使用工厂对象来实例化模型对象。如下代码我们在控制器调用模型获取数据:

app/code/Aqrun/HelloWorld/Controller/Index/Index.php

代码:

<?php
namespace Aqrun\HelloWorld\Controller\Index;
 
class Index extends \Magento\Framework\App\Action\Action
{
    protected $_pageFactory;
    protected $_postFactory;
 
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $pageFactory,
        \Aqrun\HelloWorld\Model\PostFactory $postFactory
    ){
        $this->_pageFactory = $pageFactory;
        $this->_postFactory = $postFactory;
        return parent::__contruct($context);
    }
 
    public function execute()
    {
        $post = $this->_postFactory->create();
        $collection = $post->getCollection();
        foreach($collection as $item){
            echo '<pre>';
            print_r($item->getData());
            echo '</pre>';
        }
        exit();
        return $this->_pageFactory->create();
    }
}

如上控制器, PostFactory 对象会在构造函数创建,在 execute() 方法我们使用 $post = $this->_postFactory->create(); 来创建模型对象。

接下来可以使用数据库管理软件到 aqrun_helloworld_post 表添加 2 条假数据,测试模型是否正常工作。

添加完数据访问 URL http://mage.dev/helloworld/index/index 确认添加的数据列表已经显示。

如果显示错误信息: Exception printing is disabled by default for security reasons 。可以到 var/report 目录检查错误日志。

模型相关就完结了,下一章节了解下视图:布局、区块、模板