Models Trong Magento2

Models Magento2

1. Lời mở đầu

  • Như chúng ta đã biết, Model là một phần tử bắt buộc phải có khi tạo một ứng dụng CRUD. Model cũng là một phần quan trọng trong kiến trúc MVC (Model-View-Controller).
  • Models trong Magento2 giúp chúng ta quản lý data, thao tác với database một cách dễ dàng hơn.
  • Trong bài viết này chúng ta sẽ đi vào tìm hiểu về Models theo các phương diện Model, Resource Model, và Resource Model Collection. Let’s get started!

Models Magento2

2. Tạo Database Table cho Model

  • Để bắt đầu tìm hiểu, chúng ta hãy tạo một bảng trong database cho trực quan và dễ hiểu nhé.
  • Để làm điều đó trong Magento2, chúng ta sẽ tạo một file setup:
    app/code/Learning/HelloWorld/Setup/InstallSchema.php
    Lưu ý:
    • File InstallSChema chỉ được chạy một lần khi mà bạn Install Module (Xem thêm Create A New Module In Magento2)
    • Nếu bạn đã Install Module trước đó thì phải phải nâng version của module lên và tạo bảng mới ở trong file UpgradeSchema.php.
    • Chi tiết về các Database Script sẽ được mình trình bày cụ thể chi tiết trong bài viết sau nhé. hihi
  • File: app/code/Learning/HelloWorld/Setup/InstallSchema.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?php

namespace Learning\HelloWorld\Setup;

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('learning_helloworld_post')) {
$table = $installer->getConnection()->newTable(
$installer->getTable('learning_helloworld_post')
)
->addColumn(
'post_id',
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
null,
[
'identity' => true,
'nullable' => false,
'primary' => true,
'unsigned' => true,
],
'Post ID'
)
->addColumn(
'name',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
255,
['nullable => false'],
'Post Name'
)
->addColumn(
'url_key',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
255,
[],
'Post URL Key'
)
->addColumn(
'post_content',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'64k',
[],
'Post Post Content'
)
->addColumn(
'tags',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
255,
[],
'Post Tags'
)
->addColumn(
'status',
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
1,
[],
'Post Status'
)
->addColumn(
'featured_image',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
255,
[],
'Post Featured Image'
)
->addColumn(
'created_at',
\Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
null,
['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT],
'Created At'
)->addColumn(
'updated_at',
\Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
null,
['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT_UPDATE],
'Updated At')
->setComment('Post Table');
$installer->getConnection()->createTable($table);

$installer->getConnection()->addIndex(
$installer->getTable('learning_helloworld_post'),
$setup->getIdxName(
$installer->getTable('learning_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
);
}
$installer->endSetup();
}
}
  • Chạy command line để thực thi:
1
php bin/magento setup:upgrade

2. Tạo Model

  • Model là một phần quan trọng của kiến trúc MVC
  • Là một class đại diện cho một thực thể hay một bảng trong CSDL
  • Trong Magento2, Models có rất nhiều chức năng, như quản lý thao tác database, install, upgrade module.
  • Trong ví dụ này chúng ta sẽ nói về chức năng quản lý thao tác data của Models và cụ thể là bảng learning_helloworld_post mà chúng ta vừa tạo ở bên trên.
  • Tạo file model: app/code/Mageplaza/HelloWorld/Model/Post.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
namespace Learning\HelloWorld\Model;
class Post extends \Magento\Framework\Model\AbstractModel implements \Magento\Framework\DataObject\IdentityInterface
{
const CACHE_TAG = 'learning_helloworld_post';

protected $_cacheTag = 'learning_helloworld_post';

protected $_eventPrefix = 'learning_helloworld_post';

protected function _construct()
{
$this->_init('Learning\HelloWorld\Model\ResourceModel\Post');
}

public function getIdentities()
{
return [self::CACHE_TAG . '_' . $this->getId()];
}

public function getDefaultValues()
{
$values = [];

return $values;
}
}
  • Tất cả Model sẽ được extends \Magento\Framework\Model\AbstractModel và implements \Magento\Framework\DataObject\IdentityInterface
  • Class Model phải định nghĩa phương thức getIdentities() trả về một id duy nhất định danh cho Model
  • Phương thức _construct() sẽ được gọi mỗi khi Model được khởi tạo. Phương thức _construct() sẽ gọi đến phương thức _init() chỉ định Resource Model nào dùng để fetch data từ database. Ở đây là resource model Learning\HelloWorld\Model\ResourceModel\Post.
  • Ngoài ra thì ở class Model còn định nghĩa một vài cái biến, nhưng thôi chúng ta tạm thời bỏ qua trong bài viết này :D

3. Tạo Resource Model

  • Model chưa tất cả các logic thao tác với database. Tuy nhiên nó sẽ không trực tiếp thực thi các câu truy vấn SQL. Thay vào đó Resource Model sẽ làm việc này.
  • Chúng ta sẽ tạo Resource Model app/code/Learning/HelloWorld/Model/ResourceModel/Post
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
namespace Learning\HelloWorld\Model\ResourceModel;


class Post extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{

public function __construct(
\Magento\Framework\Model\ResourceModel\Db\Context $context
)
{
parent::__construct($context);
}

protected function _construct()
{
$this->_init('learning_helloworld_post', 'post_id');
}

}
  • Tất cả Resource Model trong Magento2 sẽ phải extends abstract class \Magento\Framework\Model\ResourceModel\Db\AbstractDb, class này chứa tất cả các function để thao tác với CSDL.
  • Cũng giống như Model class, Resource Model class cũng phải có phương thức _construct(), phương thức này gọi đến _init() để định nghĩa bảng csdl và khóa chính của bảng đó, ở đây là mageplaza_helloworld_post và khóa chínhpost_id

4. Tạo Resource Model Collection

  • Collection cho phép chúng ta lấy ra hay lọc một collection dữ liệu của một bảng.
  • Collection Model được đặt ở app/code/Learning/HelloWorld/Model/ResourceModel/Post/Collection.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
namespace Learning\HelloWorld\Model\ResourceModel\Post;

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
protected $_idFieldName = 'post_id';
protected $_eventPrefix = 'learning_helloworld_post_collection';
protected $_eventObject = 'post_collection';

/**
* Define resource model
*
* @return void
*/
protected function _construct()
{
$this->_init('Learning\HelloWorld\Model\Post', 'Learning\HelloWorld\Model\ResourceModel\Post');
}

}
  • Một Collection Class phải được extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
  • _construct() gọi đến _init() chỉ định Model và Resource Model Class.

5. Factory Object

  • Vất vả từ đầu đến giờ,chúng ta đã tạo được bảng trong CSDL, Model và Resource Model Class. Vậy làm sao để sử dụng nó bây giờ nhỉ? Hihi, Sắp xong rồi
    GoodJob
  • Trong OPP, chắc các bạn cũng đã quen với khái niệm Factory dùng để khởi tạo một object. Trong Magento, Factory cũng được sử dụng như vậy :)
  • Tên của Factory Class sẽ là tên của Class mà bạn muốn khởi tạo (Model Class, Resource Model Class, hoặc Resource Model Collection Class) nối với từ Factory, ví dụ class PostFactory.
  • Bạn không phải tạo class này đâu vì Magento sẽ tạo nó cho bạn. Bất kể khi nào Magento gặp một class có tên kết thúc bằng Factory, Magento sẽ tự động generate class Factory đó ở thư mục var/generation nếu class đó chưa tồn tại
    Ở ví dụ của chúng ta, bạn có thể tìm thấy class Factory ở
    var/generation/Learning/HelloWorld/Model/PostFactory.php
  • Giả sử để khởi tạo một Model object, chúng ta sẽ sử dụng dependency injection để inject một factory object vào contructor, sau đó sử dụng factory object để khởi tạo model object. Ví dụ dưới đây, trong hàm controller chúng ta sẽ gọi Model để lấy ra data

File app/code/Learning/HelloWorld/Controller/Index/Index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
namespace Learning\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,
\Learning\HelloWorld\Model\PostFactory $postFactory
)
{
$this->_pageFactory = $pageFactory;
$this->_postFactory = $postFactory;
return parent::__construct($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();
}
}
  • Chúng ta có thể thấy, PostFactory sẽ được inject ở trong hàm __construct(), và ở hàm execute chúng ta thực hiện
    $post = $this->_postFactory->create();

Lưu ý:

  • Ở ví dụ bên trên chúng ta lấy ra collection từ Model Object bằng phương thức $collection = $post->getCollection();
  • Nếu bạn gặp phải vấn đề phương thức getCollection() đã bị Deprecated thì một trong những cách khác bạn có thể sử dụng đó là dùng Collection Factory Class của Resource Model nhé
1
2
3
4
5
6
7
8
9
10
11
12
13

protected $_postCollectionFactory;

public function __construct(
\Learning\HelloWorld\Model\ResourceModel\Post\CollectionFactory $postCollectionFactory
)
{
...
$this->_postCollectionFactory = $postCollectionFactory;
...
}
$collection = $this->_postCollectionFactory->create();

  • Xong rồi, bây giờ bạn hãy thêm bản ghi vào CSDL và mở trình duyệt test thử controller index nhé
1
http://<yourhost.com>/helloworld/index/index

6. Kết luận