Magento 中有兩種持久化模型,簡單類型和 **Entity**–**attribute**–**value**?(**EAV**) 類型。術語 entity (后面統一譯做實體) 可以表示其中的任意一種模型,我們可以將 entity 看成一種持久化模型。
<br />Magento_Newsletter 模塊中的 Subscriber 實體是簡單模型的一個例子,我們可以觀察到它包含以下內容:
> - 一個繼承自 `Magento\Framework\Model\AbstractModel` 的模型類 `Magento\Newsletter\Model\Subscriber`
> - 一個繼承自 `Magento\Framework\Model\ResourceModel\Db\AbstractDb` 的資源類 `Magento\Newsletter\Model\ResourceModel\Subscriber`
> - 一個繼承自 `Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection` 的 collection 類 `Magento\Newsletter\Model\ResourceModel\Subscriber\Collection`
<br />Magento_Customer 模塊的 Customer 實體是 EAV 模型的一個例子,它由以下幾部分組成。
> - 一個繼承自 `Magento\Framework\Model\AbstractModel` 類的模型類 `Magento\Customer\Model\Customer`
> - 一個繼承自 `Magento\Eav\Model\Entity\VersionControl\AbstractEntity` 類的 resource model 類 `Magento\Customer\Model\ResourceModel\Customer`
> - 一個繼承自 `Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection` 類的 collection 類 `Magento\Customer\Model\ResourceModel\Customer\Collection`
<br />EAV 模型和普通模型的不同之處本質上在于 resource model 和 collection 類的不同,resource model 用來連接數據庫,或者稱作持久化器,如果你愿意的話。<br />
<br />當一個訂閱者(subscriber)被保存時,對應的數據被水平地保存在數據庫中,從訂閱者的模型中獲取的數據直接輸出到單張 `newsletter_subscriber` 表中。<br />
<br />當保存顧客(customer)信息時,數據被水平地保存在數據庫中,從顧客模型中獲取的數據被輸出到一下幾張表中:
> - customer_entity
> - customer_entity_datetime
> - customer_entity_decimal
> - customer_entity_int
> - customer_entity_text
> - customer_entity_varchar
<br />決定個體屬性存儲在什么地方是由包含在 `eav_attribute.backend_type` 的列決定的,`SELECT DISTINCT backend_type FROM eav_attribute;` 查詢語句獲取到的數據展示如下:
> - 存儲在 `<entityName>_entity` 表中的 `static` 屬性值
> - 存儲在 `<entityName>_entity_varchar` 表中的 `varchar` 屬性值
> - 存儲在 `<entityName>_entity_int` 表中的 `int` 屬性值
> - 存儲在 `<entityName>_entity_text` 表中的 `text` 屬性值
> - 存儲在 `<entityName>_entity_datetime` 表中的 `datetime` 屬性值
> - 存儲在 `<entityName>_entity_decimal` 表中的 `decimal` 屬性值
緊挨著 `eav_attribute` 表,其他相關信息散落在其他 `eav_*` 表中,最重要的就是 `eav_attribute_*` 表,主要有:
> - eav_attribute
> - eav_attribute_group
> - eav_attribute_label
> - eav_attribute_option
> - eav_attribute_option_swatch
> - eav_attribute_option_value
> - eav_attribute_set
<br />`SELECT entity_type_code, entity_model FROM eav_entity_type;` 查詢表明下面的幾個 Magento 實體采用的是 EAV 模型:
> - `customer`: `Magento\Customer\Model\ResourceModel\Customer`
> - `customer_address`: `Magento\Customer\Model\ResourceModel\Address`
> - `catalog_category`: `Magento\Catalog\Model\ResourceModel\Category`
> - `catalog_product`: `Magento\Catalog\Model\ResourceModel\Product`
> - `order`: `Magento\Sales\Model\ResourceModel\Order`
> - `invoice`: `Magento\Sales\Model\ResourceModel\Order\Invoice`
> - `creditmemo`: `Magento\Sales\Model\ResourceModel\Order\Creditmemo`
> - `shipment`: `Magento\Sales\Model\ResourceModel\Order\Shipment`
但是,以上的幾個模型并沒有全部使用 EAV 模型,SELECT DISTINCT entity_type_id FROM eav_attribute; 查詢出來的只有下面幾個:
> - customer
> - customer_address
> - catalog_category
> - catalog_product
<br />
<br />EAV 模型本身就更加復雜,它的主要使用場景是動態創建屬性,最理想的是通過管理接口創建屬性,就像產品屬性的創建一樣。但是在絕大多數時候,簡單模型就夠用了。<br />
### 創建一個簡單模型
<br />和 EAV 模型不同,創建一個簡單模型十分直接。下面就一起來創建一個 Log 實體的 model、resource model 和 collection。<br />
<br />我們首先創建 <MAGELICIOUS_DIR>/Core/Model/Log.php 并填充以下內容:
```php
class Log extends \Magento\Framework\Model\AbstractModel {
protected $_eventPrefix = 'magelicious_core_log';
protected $_eventObject = 'log';
protected function _construct() {
$this->_init(\Magelicious\Core\Model\ResourceModel\Log::class);
}
}
```
$_eventPrefix 和 $_eventObject 的使用并不是必須的,但是推薦使用。這些值會在 Magento\Framework\Model\AbstractModel 的事件派發中被使用,而且也給我們的模塊添加了可擴展性。盡管 Magento 使用 <ModuleName>_<ModelName> 慣例來給 $_eventPrefix 賦值,但是使用 <VendorName>_<ModuleName>_<ModelName> 會更加安全。 $_eventObject 的名稱按照慣例是模型本身的名稱。<br />
<br />我們接下來創建 <MAGELICIOUS_DIR>/Core/Model/ResourceModel/Log.php 文件并填充以下內容:
```php
class Log extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb {
protected function _construct() {
$this->_init('magelicious_core_log', 'entity_id');
}
}
```
_init 方法有 2 個參數:magelicious_core_log 賦值給 $mainTable ,entity_id 賦值給 $idFieldName 參數 ,$idFieldName 的值是對應表的主鍵名稱。現在 magelicious_core_log 表還不存在,我們將在后面創建它。<br />
<br />接下來我們創建 <MAGELICIOUS_DIR>/Core/Model/ResourceModel/Log/Collection.php 并填充以下內容:
```php
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection {
protected function _construct() {
$this->_init(
\Magelicious\Core\Model\Log::class,
\Magelicious\Core\Model\ResourceModel\Log::class
);
}
}
```
_init 方法有 2 個參數:$model 和 $resourceModel 的字符串表示,Magento 用 <FULLY_QUALIFIED_CLASS_NAME>::class 這種語法來表示,這種方式相比直接傳遞類名更好。 <br />
<br />
### 需要記住的方法
EAV 模型和簡單模型都繼承自 Magento\Framework\Model\AbstractModel 類,Magento\Framework\Model\AbstractModel 又繼承自 Magento\Framework\DataObject ,DataObject 又幾個簡潔的值得記住的方法。<br />
<br />下面的一組方法和數據轉換相關:
> - toArray: 將對象轉換為數組,數組中的鍵為請求的鍵
> - toXml: 將對象轉換為
> - toJson: 將對象轉換為 JSON
> - toString: 將對象數據按照預定義格式轉換為字符串
> - serialize: 將對象按照定義好的鍵和值轉換為字符串
<br />下面的這些方法都是通過魔術方法 __call?實現的,主要有以下幾種語法:
> - get<AttributeName>, 例如 $object->getPackagingOption()
> - set<AttributeName>, 例如 $object->setPackagingOption('plastic_bag')
> - uns<AttributeName>, 例如 $object->unsPackagingOption()
> - has<AttributeName>, 例如 $object->hasPackagingOption()
<br />為了嘗試上面的幾個方法,我們手動創建 magelicious_core_log 表,SQL 如下:
```sql
CREATE TABLE `magelicious_core_log` (
`entity_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`severity_level` varchar(24) NOT NULL,
`note` text NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`entity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
因為繼承自 DataObject ,所以即使 Magelicious\Core\Model\Log 模型是空的,也可以利用下面的方法來保存數據:
```php
$log->setCreatedAt(new \DateTime());
$log->setSeverityLevel('info');
$log->setNote('Just Some Note');
$log->save();
```
上面的例子能正常運行,但是模型類遠遠不止這些。在創建模型的過程中手動創建數據表并不可行。Magento 中采用了 setup 腳本的機制來創建數據表。<br />
- Magento 基本概念
- Magento 中的 Plugin
- Magento 中的 Events 和 observers
- Magento 中的 Areas
- Magento 中的請求處理流程
- Magento 中的模塊(Modules)
- Magento 中的 Cache
- Magento 中的依賴注入
- Magento 中的 Console commands
- Magento 中的 Cron jobs
- 掌握 Entities
- 理解 model 的類型
- 理解 setup scripts
- 實體擴展
- 初入 web API
- users 的幾種不同類型
- 授權的不同類型
- APIs 的不同類型
- 使用 Magento 現有的 API
- 創建自定義 web APIs
- 理解 search criteria
- Magento 后臺開發
- 使用 listing 組件
- 使用 form 組件
- 開發前臺功能
- 搭建前臺開發環境
- 初始化 & 調用 JS 組件
- 開始使用 RequireJS
- 替換 jQuery widget 組件
- 擴展 jQuery widget 組件
- 創建 jQuery widgets 組件
- 創建 UI/KnockoutJS 組件
- 擴展 UI/KnockoutJS 組件
- 自定義 Catalog
- 創建參考尺寸
- 創建當天發貨
- 標識新產品
- Magento 性能最佳實踐
- Magento 硬件推薦配置
- 軟件推薦
- 架構參考
- 配置項最佳實踐
- 高級設置
- 其他
- 如何通過 Burp Suite 和 Xdebug 來調試 Magento
- Mageno checkout 必知必會
- Magento 安裝(新手必看)
- 安裝流程
- 系統要求