Menu

Magento 008: Tạo một grid trong backend Magento

Trong những tut trước mình đã giới thiệu về những thành phần cơ bản của một module trong magento như: block, template, layout, config… và nó sẽ là nền tảng cơ bản cho các bạn có thể xây dựng nên những extension cho các website sử dụng mã nguồn mở Magento.

Bài học này mình sẽ hướng dẫn các bạn tạo một grid trong backend của Magento và để cụ thể hóa vấn đề này chúng ta sẽ đi xây dựng một extension với tên là: Salestaff (namespace là Basetut). Extension này có tác dụng quản lý nhân viên bán hàng của store và trong phạm vi bài này chúng ta cũng chỉ viết một grid hiển thị danh sách nhân viên bán hàng với những thông tin như: firstname, lastname, birthday, sex, status mà thôi.

1. Tạo file Basetut_Salestaff.xml trong thư mục app/etc/modules

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<config>
 <modules>
 <Basetut_Salestaff>
 <active>true</active>
 <codePool>local</codePool>
 </Basetut_Salestaff>
 </modules>
</config>

2. Tạo file config.xml trong thư mục app/code/local/Basetut/Salestaff

Trong file này cần khai báo để sử dụng: model, helper, block, layout, router… cho module. Nếu muốn biết chi tiết các thành phần, các thẻ trong file config hãy xem lại Tut Magento 006 và 007:  Magento config nhé!

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
<?xml version="1.0"?>
<config>
 <modules>
 <!--Version của module-->
 <Basetut_Salestaff>
 <version>0.1.0</version>
 </Basetut_Salestaff>
 </modules>
 <!--Khai báo admin router-->
 <admin>
 <routers>
 <salestaffadmin>
 <use>admin</use>
 <args>
 <module>Basetut_Salestaff</module>
 <frontName>salestaffadmin</frontName>
 </args>
 </salestaffadmin>
 </routers>
 </admin>
 <adminhtml>
 <!-- Khai báo file layout trong admin-->
 <layout>
 <updates>
 <salestaff>
 <file>salestaff.xml</file>
 </salestaff>
 </updates>
 </layout>
 </adminhtml>
 <global>
 <!--Khai báo model, resource model-->
 <models>
 <salestaff>
 <class>Basetut_Salestaff_Model</class>
 <resourceModel>salestaff_mysql4</resourceModel>
 </salestaff>
 <salestaff_mysql4>
 <class>Basetut_Salestaff_Model_Mysql4</class>
 <entities>
 <staff>
 <table>salestaff_staff</table>
 </staff>
 </entities>
 </salestaff_mysql4>
 </models>
 <!--Khai báo resource để connect và thao tác với database được-->
 <resources>
 <salestaff_setup>
 <setup>
 <module>Basetut_Salestaff</module>
 </setup>
 <connection>
 <use>core_setup</use>
 </connection>
 </salestaff_setup>
 <salestaff_write>
 <connection>
 <use>core_write</use>
 </connection>
 </salestaff_write>
 <salestaff_read>
 <connection>
 <use>core_read</use>
 </connection>
 </salestaff_read>
 </resources>
 <!--Khai báo block để có thể dùng được-->
 <blocks>
 <salestaff>
 <class>Basetut_Salestaff_Block</class>
 </salestaff>
 </blocks>
 <!--Khai báo helper-->
 <helpers>
 <salestaff>
 <class>Basetut_Salestaff_Helper</class>
 </salestaff>
 </helpers>
 </global>
 
</config>

Nếu các bạn có bất cứ thắc mắc hay chỗ nào chưa hiểu về file config này thì hỏi mình nhé! Hoặc đặt câu hỏi trên diễn đàn http://forum.basetut.com và mình sẽ giúp các bạn hiểu hơn về nó.

3. Tạo models, resource và collection

  • Model: tạo một file có tên là Staff.php trong thư mục app/code/local/Basetut/Salestaff/Model
1
2
3
4
5
6
7
8
<?php
class Basetut_Salestaff_Model_Staff extends Mage_Core_Model_Abstract
{
 public function _construct(){
 parent::_construct();
 $this->_init('salestaff/staff');
 }
}

Với file model thế này thì mỗi khi chúng ta muốn gọi đến model Staff có thể dùng câu lệnh:

1
$staff = Mage::getModel('salestaff/staff');
  • Resource: tạo file Staff.php trong thư mục app/code/local/Basetut/Salestaff/Model/Mysql4
1
2
3
4
5
6
7
8
<?php
class Basetut_Salestaff_Model_Mysql4_Staff extends Mage_Core_Model_Mysql4_Abstract
{
 public function _construct()
 {
 $this->_init('salestaff/staff', 'staff_id');
 }
}

Trong hàm construct của resource model trên có 2 tham số:

+ salestaff/staff: tên model truyền vào

+ staff_id: id của bảng tương ứng với model salestaff/staff

  • Collection: tạo file Collection.php trong thư mục app/code/local/Basetut/Salestaff/Model/Mysql4/Staff
1
2
3
4
5
6
7
8
9
<?php
class Basetut_Salestaff_Model_Mysql4_Staff_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{
 public function _construct()
 {
 parent::_construct();
 $this->_init('salestaff/staff');
 }
}

4. Tạo file blocks

– Tạo file block Staff.php trong thư mục app/code/local/Basetut/Salestaff/Block/Adminhtml

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class Basetut_Salestaff_Block_Adminhtml_Staff extends Mage_Adminhtml_Block_Widget_Grid_Container
{
 public function __construct()
 {
 $this->_controller = 'adminhtml_staff';
 $this->_blockGroup = 'salestaff';
 $this->_headerText = Mage::helper('salestaff')->__('Staff Manager');
 parent::__construct();
 $this->_removeButton('add');
 }
}

File block này có tác dụng render ra mã html hiển thị, cụ thể trong ví dụ này nó sẽ render ra 1 grid danh sách nhân viên bán hàng được lấy trong bảng salestaff_staff ra.

(Chú ý: block chứa grid thì phải thừa kế từ class: Mage_Adminhtml_Block_Widget_Grid_Container)

+ $this->_controller: đường dẫn tới block grid của block này, bạn hãy để ý tên lớp của nó nhé

Basetut_Salestaff_Block_Adminhtml_Staff 

+ $this->_blockGroup: thường là tên của module

Basetut_Salestaff_Block_Adminhtml_Staff

– Tạo block grid Grid.php trong thư mục app/code/local/Basetut/Salestaff/Block/Adminhtml/Staff.

Mỗi khi block container Mage_Adminhtml_Block_Widget_Grid_Container được gọi đến để render ra mã html thì nó sẽ gọi tới block grid tương ứng để đẩy ra grid, trong ví dụ này thì block grid đó chính là: Basetut_Salestaff_Block_Adminhtml_Staff_Grid

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
<?php
class Basetut_Salestaff_Block_Adminhtml_Staff_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
 public function __construct()
 {
 parent::__construct();
 $this->setId('staffGrid');
 $this->setDefaultSort('staff_id');
 $this->setDefaultDir('ASC');
 $this->setSaveParametersInSession(true);
 }
 
 /**
 * lay ra collection can hien thi len grid
 */
 protected function _prepareCollection()
 {
 $collection = Mage::getModel('salestaff/staff')->getCollection();
 $this->setCollection($collection);
 return parent::_prepareCollection();
 }
 
 /**
 * hàm chuẩn bị trước khi in ra grid
 */
 protected function _prepareColumns()
 {
 $this->addColumn('staff_id', array(
 'header' => Mage::helper('salestaff')->__('ID'),
 'align' =>'right',
 'width' => '50px',
 'index' => 'staff_id',
 ));
 
$this->addColumn('name', array(
 'header' => Mage::helper('salestaff')->__('Name'),
 'align' =>'left',
 'index' => 'name',
 ));
 
$this->addColumn('birthday', array(
 'header' => Mage::helper('salestaff')->__('Birthday'),
 'width' => '150px',
 'index' => 'birthday',
 'type' => 'date'
 ));
 
 $this->addColumn('sex', array(
 'header' => Mage::helper('salestaff')->__('Sex'),
 'align' => 'left',
 'width' => '80px',
 'index' => 'sex',
 'type' => 'options',
 'options' => array(
 1 => 'Male',
 2 => 'Female',
 ),
 ));
 
$this->addColumn('status', array(
 'header' => Mage::helper('salestaff')->__('Status'),
 'align' => 'left',
 'width' => '80px',
 'index' => 'status',
 'type' => 'options',
 'options' => array(
 1 => 'Enabled',
 2 => 'Disabled',
 ),
 ));
 
return parent::_prepareColumns();
 }
 
 /**
 * hàm trả lại url cho mỗi row trong grid
 */
 public function getRowUrl($row)
 {
 return '#';
 }
}

Trong block grid này có ba hàm rất quan trọng đó là:

+ __construct (): hàm khởi tạo này có tác dụng set một số giá trị mặc định cho grid như id cho grid, field được sort mặc định…

+ _prepareCollection(): hàm này có tác dụng lấy ra collection dữ liệu hiển thị ra grid

+ _prepareColumns(): hàm này có tác dụng thêm các cột, mass action cho grid.

5. Tạo file layout salestaff.xml trong thư mục app/design/adminhtml/default/default/layout

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<layout version="0.1.0">
 <salestaffadmin_adminhtml_staff_index>
 <reference name="content">
 <block type="salestaff/adminhtml_staff" name="staff" />
 </reference>
 </salestaffadmin_adminhtml_staff_index>
</layout>

Một số câu hỏi cho file layout này là: salestaffadmin_adminhtml_staff là gì? Tại sao lại sử dụng type =”salestaff/adminhtml_staff”?

Trong Tut Magento 004: Layout, block và template trong Magento mình đã có giải thích qua về phần này tuy nhiên nhìn vào ví dụ này thì ta có thể hình dung một cách cụ thể và chi tiết hơn.
Trong handle salestaffadmin_adminhtml_staff_index ta sẽ chèn vào phần layout content một block với type là “salestaff/adminhtml_staff” tương ứng với đường class Basetut_Salestaff_Block_Adminhtml_Staff – một block kế thừa từ class Mage_Adminhtml_Block_Widget_Grid_Container mà ta đã tạo trong thư mục Block.
Nhưng tại sao handle lại là salestaffadmin_adminhtml_staff_index? Tại sao lại là salestaffadmin mà không phải là salestaff? Cái handle này có ý nghĩa gì?
Câu trả lời:
– Mỗi handle trong file layout tương đương với một action trong controller. Như vậy handle này sẽ chỉ đến action index trong file StaffController.php, file controller này lại thuộc thư mục Salestaff/controllers/Adminhtml.
Các bạn đã hình dung được tại sao mình lại viết handle kia chưa?
Còn về salestaffadmin – đây chính là router admin mà mình đã khai báo trong file config.xml và nếu bạn muốn kiểm tra thì có thể xem lại nhé!

Ok vậy là chúng ta đã khai báo xong tất cả mọi thứ, viết tất cả những thành phần chính có thể hiển thị ra một grid trong admin nhưng chúng ta lại không biết luồng chạy của nó bắt đầu từ đâu. Hãy đến phần quan trọng cuối cùng đó là controllers

6. Tạo file StaffController.php trong thư mục app/code/local/Basetut/Salestaff/controllers

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class Basetut_Salestaff_Adminhtml_StaffController extends Mage_Adminhtml_Controller_Action
{
 /**
 * index action
 */
 public function indexAction()
 {
 $this->loadLayout()
 ->renderLayout();
 }
}

Trong indexAction này ta chỉ gọi 2 hàm cơ bản:
+ loadLayout(): load tất cả các block đã khai báo trong file layout (salestaff.xml trong thư mục layout)
+ renderLayout(): render ra mã html và đẩy ra ngoài trình duyệt từ những block đã được khai báo

Vậy từ bây giờ các bạn đã có thể hình dung được luồng chạy của một handle trong Magento. Nó cũng không thực sự phức tạp quá như các bạn từng nghĩ đúng không? Bài viết của mình chắc chắn vẫn còn rất nhiều thiếu xót mong nhận được sự góp ý của các bạn để blog ngày càng hoàn thiện.
Các bạn có thể download source code của Tut 008 này tại đây: basetut_salestaff_1.0.

Facebook Comments

No comments

Trả lời