文章彙整

Magento 2 EAV Model 介紹 (3) – 在 Magento 2 使用程式新增 entity type

By Steffi 5 months agoNo Comments
首頁  /  Magento  /  Magento-2  /  Magento 2 EAV Model 介紹 (3) – 在 Magento 2 使用程式新增 entity type

之前的文章內,我們介紹了 Eav Model 的關係,以及如何使用程式新增 Attribute,但是在 Magento 裡面使用了許多的 Entity Type,今天要透過程式的方式來教大家如何新增 Entity Type 及其相關的資料表,讓自己的定義的 Entity Type 也可以存取 Attribute 屬性唷!

※Magento 版本:2.1 以上

1.新增資料表

要建立 Entity type,必須依照 Magento 的規則建立相對應的資料表,我們以建立 Post 的 Entity type 為例,共需要產生以下 6 張資料表

* post_entity

* post_entity_datetime

* post_entity_decimal

* post_entity_int

* post_entity_text

* post_entity_varchar

要建立資料表,我們必須先在 module 的 Setup 資料夾內建立 InstallSchema.php,裡面程式碼如下:

<?php


namespace Grayson\Post\Setup;


use Magento\Framework\DB\Adapter\AdapterInterface;

use Magento\Framework\DB\Ddl\Table;

use Magento\Framework\Setup\InstallSchemaInterface;

use Magento\Framework\Setup\ModuleContextInterface;

use Magento\Framework\Setup\SchemaSetupInterface;


/**

* Class InstallSchema

* @package Grayson\Post\Setup

*/

class InstallSchema implements InstallSchemaInterface

{

   const POST_ENTITY = 'post_entity';


   /**

    * @param SchemaSetupInterface $setup

    * @param ModuleContextInterface $context

    * @throws \Zend_Db_Exception

    */

   public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)

   {

       $installer = $setup;


       $installer->startSetup();


   }

}

 

(1) post_entity 資料表

這張是實體 ( Entity ) 主表,所有的紀錄都會在這邊產生,程式如下:

/**

    * @param SchemaSetupInterface $setup

    * @param string $entity

    * @return InstallSchema

    * @throws \Zend_Db_Exception

    */

   private function addEntityTable(SchemaSetupInterface $setup, string $entity): InstallSchemaInterface

   {

       $table = $setup->getConnection()

           ->newTable($setup->getTable($entity))

           ->addColumn(

               'entity_id',

               Table::TYPE_INTEGER,

               null,

               [

                   'identity' => true,

                   'unsigned' => true,

                   'nullable' => false,

                   'primary' => true

               ],

               'Entity ID'

           )->addColumn(

               'created_at',

               Table::TYPE_TIMESTAMP,

               null,

               [

                   'nullable' => false,

                   'default' => Table::TIMESTAMP_INIT

               ],

               'Creation Time'

           )->addColumn(

               'updated_at',

               Table::TYPE_TIMESTAMP,

               null,

               [

                   'nullable' => false,

                   'default' => Table::TIMESTAMP_INIT_UPDATE

               ],

               'Update Time'

           );


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


       return $this;


   }

 

(2) post_entity_datetime 資料表

/**

    * @param SchemaSetupInterface $setup

    * @param string $entity

    * @return InstallSchema

    * @throws \Zend_Db_Exception

    */

   private function addDatetimeTable(SchemaSetupInterface $setup, string $entity): InstallSchemaInterface

   {

       $table = $setup->getConnection()

           ->newTable($setup->getTable($entity . '_datetime')

           )->addColumn(

               'value_id',

               Table::TYPE_INTEGER,

               null,

               ['identity' => true, 'nullable' => false, 'primary' => true],

               'Value ID'

           )->addColumn(

               'attribute_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Attribute Id'

           )->addColumn(

               'store_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Store ID'

           )->addColumn(

               'entity_id',

               Table::TYPE_INTEGER,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Entity Id'

           )->addColumn(

               'value',

               Table::TYPE_DATETIME,

               null,

               [],

               'value'

           )->addIndex(

               $setup->getIdxName($entity . '_decimal',

                   ['entity_id', 'attribute_id', 'store_id'],

                   AdapterInterface::INDEX_TYPE_UNIQUE),

               ['entity_id', 'attribute_id', 'store_id'],

               ['type' => AdapterInterface::INDEX_TYPE_UNIQUE]

           )->addIndex(

               $setup->getIdxName($entity . '_datetime',

                   ['store_id']),

               ['store_id']

           )->addIndex(

               $setup->getIdxName($entity . '_datetime',

                   ['attribute_id']),

               ['attribute_id']

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_datetime',

                   'attribute_id',

                   'eav_attribute',

                   'attribute_id'

               ),

               'attribute_id',

               $setup->getTable('eav_attribute'),

               'attribute_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_datetime',

                   'entity_id',

                   $entity,

                   'entity_id'

               ),

               'entity_id',

               $setup->getTable($entity),

               'entity_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_datetime', 'store_id', 'store', 'store_id'

               ),

               'store_id',

               $setup->getTable('store'),

               'store_id',

               Table::ACTION_CASCADE

           );

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


       return $this;

   }

 

(3)  post_entity_decimal 資料表

 /**

    * @param SchemaSetupInterface $setup

    * @param string $entity

    * @return InstallSchema

    * @throws \Zend_Db_Exception

    */

   private function addDecimalTable(SchemaSetupInterface $setup, string $entity): InstallSchemaInterface

   {

       $table = $setup->getConnection()

           ->newTable($setup->getTable($entity . '_decimal'))

           ->addColumn(

               'value_id',

               Table::TYPE_INTEGER,

               null,

               ['identity' => true, 'nullable' => false, 'primary' => true],

               'Value ID'

           )->addColumn(

               'attribute_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Attribute Id'

           )->addColumn(

               'store_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Store ID'

           )->addColumn(

               'entity_id',

               Table::TYPE_INTEGER,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Entity Id'

           )->addColumn(

               'value',

               Table::TYPE_DECIMAL,

               '12,4',

               [],

               'value'

           )->addIndex(

               $setup->getIdxName($entity . '_decimal',

                   ['entity_id', 'attribute_id', 'store_id'],

                   AdapterInterface::INDEX_TYPE_UNIQUE),

               ['entity_id', 'attribute_id', 'store_id'],

               ['type' => AdapterInterface::INDEX_TYPE_UNIQUE]

           )->addIndex(

               $setup->getIdxName($entity . '_decimal',

                   ['store_id']),

               ['store_id']

           )->addIndex(

               $setup->getIdxName($entity . '_decimal',

                   ['attribute_id']),

               ['attribute_id']

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_decimal',

                   'attribute_id',

                   'eav_attribute',

                   'attribute_id'

               ),

               'attribute_id',

               $setup->getTable('eav_attribute'),

               'attribute_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_decimal',

                   'entity_id',

                   $entity . '_entity',

                   'entity_id'

               ),

               'entity_id',

               $setup->getTable($entity),

               'entity_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_decimal', 'store_id', 'store', 'store_id'

               ),

               'store_id',

               $setup->getTable('store'),

               'store_id',

               Table::ACTION_CASCADE

           );


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


       return $this;


   }

 

(4) post_entity_int 資料表

<?php


   /**

    * @param SchemaSetupInterface $setup

    * @param $entity

    * @return InstallSchema

    * @throws \Zend_Db_Exception

    */

   private function addIntTable(SchemaSetupInterface $setup, $entity): InstallSchemaInterface

   {

       $table = $setup->getConnection()

           ->newTable($setup->getTable($entity . '_int'))

           ->addColumn(

               'value_id',

               Table::TYPE_INTEGER,

               null,

               ['identity' => true, 'nullable' => false, 'primary' => true],

               'Value ID'

           )->addColumn(

               'attribute_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Attribute Id'

           )->addColumn(

               'store_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Store ID'

           )->addColumn(

               'entity_id',

               Table::TYPE_INTEGER,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Entity Id'

           )->addColumn(

               'value',

               Table::TYPE_INTEGER,

               null,

               [],

               'value'

           )->addIndex(

               $setup->getIdxName($entity . '_int',

                   ['entity_id', 'attribute_id', 'store_id'],

                   AdapterInterface::INDEX_TYPE_UNIQUE),

               ['entity_id', 'attribute_id', 'store_id'],

               ['type' => AdapterInterface::INDEX_TYPE_UNIQUE]

           )->addIndex(

               $setup->getIdxName($entity . '_int',

                   ['store_id']),

               ['store_id']

           )->addIndex(

               $setup->getIdxName($entity . '_int',

                   ['attribute_id']),

               ['attribute_id']

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_int',

                   'attribute_id',

                   'eav_attribute',

                   'attribute_id'

               ),

               'attribute_id',

               $setup->getTable('eav_attribute'),

               'attribute_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_int',

                   'entity_id',

                   $entity,

                   'entity_id'

               ),

               'entity_id',

               $setup->getTable($entity),

               'entity_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_int', 'store_id', 'store', 'store_id'

               ),

               'store_id',

               $setup->getTable('store'),

               'store_id',

               Table::ACTION_CASCADE

           );

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


       return $this;

   }

 

(5)  post_entity_text 資料表

<?php


   /**

    * @param SchemaSetupInterface $setup

    * @param string $entity

    * @return InstallSchema

    * @throws \Zend_Db_Exception

    */

   private function addTextTable(SchemaSetupInterface $setup, string $entity): InstallSchemaInterface

   {

       $table = $setup->getConnection()

           ->newTable($setup->getTable($entity . '_text'))

           ->addColumn(

               'value_id',

               Table::TYPE_INTEGER,

               null,

               ['identity' => true, 'nullable' => false, 'primary' => true],

               'Value ID'

           )->addColumn(

               'attribute_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Attribute Id'

           )->addColumn(

               'store_id',

               Table::TYPE_SMALLINT,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Store ID'

           )->addColumn(

               'entity_id',

               Table::TYPE_INTEGER,

               null,

               ['unsigned' => true, 'nullable' => false, 'default' => '0'],

               'Entity Id'

           )->addColumn(

               'value',

               Table::TYPE_TEXT,

               255,

               [],

               'value'

           )->addIndex(

               $setup->getIdxName($entity . '_text',

                   ['entity_id', 'attribute_id', 'store_id'],

                   AdapterInterface::INDEX_TYPE_UNIQUE),

               ['entity_id', 'attribute_id', 'store_id'],

               ['type' => AdapterInterface::INDEX_TYPE_UNIQUE]

           )->addIndex(

               $setup->getIdxName($entity . '_text',

                   ['store_id']),

               ['store_id']

           )->addIndex(

               $setup->getIdxName($entity . '_text',

                   ['attribute_id']),

               ['attribute_id']

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_text',

                   'attribute_id',

                   'eav_attribute',

                   'attribute_id'

               ),

               'attribute_id',

               $setup->getTable('eav_attribute'),

               'attribute_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_text',

                   'entity_id',

                   $entity,

                   'entity_id'

               ),

               'entity_id',

               $setup->getTable($entity),

               'entity_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_text', 'store_id', 'store', 'store_id'

               ),

               'store_id',

               $setup->getTable('store'),

               'store_id',

               Table::ACTION_CASCADE

           );

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

       return $this;

   }

 

(6) post_entity_varchar 資料表

<?php

   /**

    * @param SchemaSetupInterface $setup

    * @param $entity

    * @return InstallSchema

    * @throws \Zend_Db_Exception

    */

   private function addVarcharTable(SchemaSetupInterface $setup, $entity): InstallSchemaInterface

   {

       $table = $setup->getConnection()

           ->newTable($setup->getTable($entity . '_varchar'))

           ->addColumn(

               'value_id',

               Table::TYPE_INTEGER,

               null,

               [

                   'identity' => true,

                   'nullable' => false,

                   'primary' => true

               ],

               'Value ID'

           )->addColumn(

               'attribute_id',

               Table::TYPE_SMALLINT,

               null,

               [

                   'unsigned' => true,

                   'nullable' => false,

                   'default' => '0'

               ],

               'Attribute Id'

           )->addColumn(

               'store_id',

               Table::TYPE_SMALLINT,

               null,

               [

                   'unsigned' => true,

                   'nullable' => false,

                   'default' => '0'

               ],

               'Store ID'

           )->addColumn(

               'entity_id',

               Table::TYPE_INTEGER,

               null,

               [

                   'unsigned' => true,

                   'nullable' => false,

                   'default' => '0'

               ],

               'Entity Id'

           )->addColumn(

               'value',

               Table::TYPE_TEXT,

               256,

               [],

               'value'

           )->addIndex(

               $setup->getIdxName($entity . '_varchar',

                   ['entity_id', 'attribute_id', 'store_id'],

                   AdapterInterface::INDEX_TYPE_UNIQUE),

               ['entity_id', 'attribute_id', 'store_id'],

               ['type' => AdapterInterface::INDEX_TYPE_UNIQUE]

           )->addIndex(

               $setup->getIdxName($entity . '_varchar',

                   ['store_id']),

               ['store_id']

           )->addIndex(

               $setup->getIdxName($entity . '_varchar',

                   ['attribute_id']),

               ['attribute_id']

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_varchar',

                   'attribute_id',

                   'eav_attribute',

                   'attribute_id'

               ),

               'attribute_id',

               $setup->getTable('eav_attribute'),

               'attribute_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_varchar',

                   'entity_id',

                   $entity,

                   'entity_id'

               ),

               'entity_id',

               $setup->getTable($entity),

               'entity_id',

               Table::ACTION_CASCADE

           )->addForeignKey(

               $setup->getFkName(

                   $entity . '_varchar', 'store_id', 'store', 'store_id'

               ),

               'store_id',

               $setup->getTable('store'),

               'store_id',

               Table::ACTION_CASCADE

           );

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


       return $this;

   }

 

(7) InstallSchema

接下來我們在 InsatallSchema 內使用剛剛建立的 function,並帶入 $installer self::POST_ENTITY 變數,參考底下程式碼:

<?php


namespace Grayson\Post\Setup;


use Magento\Framework\DB\Adapter\AdapterInterface;

use Magento\Framework\DB\Ddl\Table;

use Magento\Framework\Setup\InstallSchemaInterface;

use Magento\Framework\Setup\ModuleContextInterface;

use Magento\Framework\Setup\SchemaSetupInterface;


/**

* Class InstallSchema

* @package Grayson\Post\Setup

*/

class InstallSchema implements InstallSchemaInterface

{

   const POST_ENTITY = 'post_entity';


   /**

    * @param SchemaSetupInterface $setup

    * @param ModuleContextInterface $context

    * @throws \Zend_Db_Exception

    */

   public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)

   {

       $installer = $setup;


       $installer->startSetup();


       $this->addEntityTable($installer, self::POST_ENTITY);

       $this->addDatetimeTable($installer, self::POST_ENTITY);

       $this->addDecimalTable($installer, self::POST_ENTITY);

       $this->addIntTable($installer, self::POST_ENTITY);

       $this->addTextTable($installer, self::POST_ENTITY);

       $this->addVarcharTable($installer, self::POST_ENTITY);


   }

   

//... 略

 

2.新增 Model、Collection、ResouceModel

MVC 是一種現代化的設計模式,Model 則是 MVC 中的 M,它負責資料庫的操作,而 Magento 的 ORM 已經幫我們封裝好 Model 的 Class ,我們使用時僅需要繼承正確的抽象類別 ( Abstract Class ) 即可,而除了 Model 之外,也幫我們封裝了 Collection 及 ResourceModel 的兩種類別,讓我們在使用 ORM 的時候更加的方便,底下我們就要在這模組中新增這幾隻程式,來完成我們 Post 的 Entity Type。

(1) Model

請注意!這邊是非常大的地雷!需要特別注意!

一般的 Model 是繼承 \Magento\Framework\Model\AbstractModel,但是因為是需要操作 Entity Type 的關係,我們繼承的 Class 需更改為 Magento\Catalog\Model\AbstractModel,可以參考下面程式的第 6 行:

<?php


namespace Grayson\Post\Model;


use Magento\Catalog\Model\AbstractModel;

use Magento\Framework\DataObject\IdentityInterface;


/**

* Class Post

* @package Grayson\Post\Model

*/

class Post extends AbstractModel implements IdentityInterface

{

   /**

    * Entity code.

    * Can be used as part of method name for entity processing

    */

   const ENTITY = 'grayson_post';


   const CACHE_TAG = 'grayson_post';


   const STORE_ID = 'store_id';


   /* @var string */

   protected $_eventPrefix = 'grayson_post';


   /* @var string */

   protected $_eventObject = 'post';


   /* @var string */

   protected $_cacheTag = self::CACHE_TAG;


   /**

    * @return void

    */

   protected function _construct()

   {

       $this->_init(ResourceModel\Post::class);

   }


   /**

    * @return array

    */

   public function getIdentities()

   {

       return [self::CACHE_TAG . '_' . $this->getId()];

   }

}

(2) ResourceModel
也不同於原本繼承 Magento\Framework\Model\ResourceModel\Db\AbstractDb
這邊要更換為Magento\Catalog\Model\ResourceModel\AbstractResource

<?php

namespace Grayson\Post\Model\ResourceModel;

use Magento\Catalog\Model\ResourceModel\AbstractResource;

/**

* Class Post

* @package Grayson\Post\Model\ResourceModel

*/

class Post extends AbstractResource

{

   /**

    *

    * @return \Magento\Eav\Model\Entity\Type

    * @throws \Magento\Framework\Exception\LocalizedException

    */

   public function getEntityType()

   {

       if (empty($this->_type)) {

           $this->setType(\Grayson\Post\Model\Post::ENTITY);

       }

       

       return parent::getEntityType();

   }

}

(3) Collection
Collection 的部分也需要由原本繼承的 Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection 改為 Magento\Catalog\Model\ResourceModel\Collection\AbstractCollection 才行:

<?php

namespace Grayson\Post\Model\ResourceModel\Post;

use Grayson\Post\Model\Post;

use Grayson\Post\Model\ResourceModel\Post as ResourceModelPost;

use Magento\Catalog\Model\ResourceModel\Collection\AbstractCollection;

/**

* Class Collection

* @package Grayson\Post\Model\ResourceModel\Post

*/

class Collection extends AbstractCollection

{

   protected function _construct()

   {

       $this->_init(Post::class, ResourceModelPost::class);

   }

}

 

3.執行 Upgrade 指令

在我們都完成上面的程式檔案後,並且做最後的確認,是否有 Module 沒有複製到正確的資料。如果一切都沒有問題,直接執行

$  bin/magento setup:upgrade

即可看到安裝完成的訊息,我們可以至 eav_entity_type 資料表內檢查,是否有多出 grayson_post 這個 Entity Type 呢?如果沒有,請回頭至第一個步驟再檢查一次有沒有程式碼遺漏掉,還是沒有的話,可以參考我下面的 Github 連結,裡面有完整的模組範例,包含上述的程式碼。
參考連結:Gitbub
想看更多Magento 2 教學導覽,別忘了訂閱我們的電子報,以及追蹤我們的Facebook粉絲專頁唷!

更多Magento相關文章請看: Magento教學導覽

 

以上內容由Astralweb 歐斯瑞編寫製作

 000

推薦文章

Category:
  Magento-2

留下回應

你的電子郵件地址不會被公開.

取得獨家電子商務祕技

建立更好的策略靈感

跟上全球的網路趨勢

絕佳的電商解決方案

電子商務戰略全指南

每月發送電商戰略指南,只要填寫E-mail即可訂閱!

請到您的信箱確認,即可完成訂閱。