Thứ Tư, 13 tháng 10, 2010

Zend Framework cho người mới bắt đầu

A- Tìm hiểu cách làm việc ZF:

ZF được xem là một trong những framework phổ biến và có sức mạnh rất lớn so với mặt bằng chung các Framework đang có mặt hiện nay. Tuy nhiên, để sử dụng thành thạo được ZF. Người sử dụng phải có những hiểu biết nhất định về các khái niệm mô hình ba lớp M-V-C, kiến thức PHP 5.x thuần và một số kinh nghiệm xử lý tình huống khi tiếp cận lỗi thực tế.

Trong bài này, chúng ta sẽ nói về những định nghĩa, kiến trúc của ZF như thế nào và làm cách nào để sử dụng Zend Application cấu hình thư mục tùy biến trên website của chúng ta.

ZF được xây dựng với một thư viên rất đồ sộ. Nên việc nghiên cứu và đọc hết tài liệu ZF là điều không đơn giản. Tuy nhiên, bạn cũng cần tìm hiểu những nguyên tắc hoạt động của ZF như thế nào.

1- Cách làm việc và xây dựng lớp trên ZF:

Chúng ta vẫn thấy ZF đưa ra tên các thư viện Zend_application hay Zend_Application_Bootstrap_Bootstrapper. Vậy làm với cách viết này, ZF hoạt động ra sao ?.

Trên thực tế, ZF dựa vào thư viện để đọc và làm việc trên các lớp một cách rất cụ thể. Bởi đường dẫn chi tiết của chúng đã được thể hiện rõ nét ngay trên tên của chúng.

Như vậy khi ZF đặt tên Zend_Application. Điều đó có nghĩa là nó gọi tới file Application trong thư mục zend.

Có nghĩa là: library/Zend/Application.php
Hay với tên: Zend_Application_Bootstrap_Bootstrapper
Có nghĩa là: library/Zend/Application/Bootstrap/Bootstrapper.php

Thật đơn giản phải không nào ?. Tuy nhiên, để can thiệp vào các thư viện này. Đòi hỏi bạn phải rất vững và hiểu thật rõ ZF, nếu không thư viện và ứng dụng của ZF sẽ bị hỏng khi các bạn sử dụng các thư viện.

2- Cài đặt Zend Framework và ứng dụng đầu tiên:

Đầu tiên, bạn cần tải toàn bộ source zend framework tại đây:
http://framework.zend.com/releases/ZendFramework-1.9.5/ZendFramework-1.9.5-minimal.zip

Ở đây, chúng ta sẽ sử dụng bản ZF mới nhất là 1.9.5

Xây dựng mô hình các thư mục như sau:
www/zfexam/application
www/zfexam/public/
www/zfexam/library

Tại thư mục library, bạn chỉ việc copy và thư viện zend, phiên bản mới nhất vào đây.

Thư mục pubic: bạn lần lượt tạo 2 file mới là: index.php và .htaccess
File index với nội dung như sau:


defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));
set_include_path(implode(PATH_SEPARATOR, array(
dirname(dirname(__FILE__)) . '/library',
get_include_path(),
)));

require_once 'Zend/Application.php' ;

$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);

$application->bootstrap()->run();



Chúng ta chưa cần quan tâm đến mã nguồn như thế nào, bởi vì ỏ phần dưới chúng ta sẽ đi vào chi tiết từng dòng lệnh.
Trong file .htaccess lại tiếp tục copy và past đoạn code sau:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Thư mục application bạn lại tạo một số thư mục:
www/zfexam/application/controllers
www/zfexam/application/views
www/zfexam/application/models
www/zfexam/application/configs
Tại thư mục controllers tạo file:
www/zfexam/application/controllers/IndexController.php
www/zfexam/application/controllers/ErrorController.php
tại file IndexController.php copy nội dung sau:
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
}
}
?>


Tại thư mục views tại thư mục:
www/zfexam/application/views/scripts/index/index.phtml
www/zfexam/application/views/scripts/error/index.html
File index/index.phtml có nội dung như sau:

hello Zend Framework



Tại thư mục configs tạo file application.ini:
www/zfexam/application/configs/application.ini
Với nội dung:

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

Và tiếp tục tạo file bootstrap.php ở thư mục application
www/zfexam/application/bootstrap.php
Với nội dung:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
}

Và cuối cùng chúng ta cùng chạy:
http://localhost/zfexam/public/
Như vậy, bạn đã viết ứng dụng đầu tiên bằng ZF rồi đấy.

3- Nguyên tắc MVC trên ZF:
Cũng như bao framework khác, ZF cũng hoạt động trên mô hình MVC.
Ví dụ xét liên kết:
http://qhonline.info/book/viewbook/
Như vậy book được xem là một controller và viewbook được xem là một action của controller đó. Tới đây chắc hẳn bạn đã tìm ra những điểm chung của ZF và CI mà chúng ta đã từng nghiên cứu rồi phải không nào.
Khi hoạt động, trong controller bạn sẽ khởi tạo những action một cách cụ thể, thông qua việc thiết lập phương thức một cách cụ thể.
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
}
}
?>

Như vậy IndexController cho ta Controller mang tên index và indexAction cho ta action là index.
Khi đó bạn bắt buộc phải khởi tạo trong view một thư mục ứng với controller là index trong scripts. Và file index.phml ứng với action là index. Để chúng hiểu được mô hình một cách cụ thể hơn.
Xét ví dụ khác:

class BookController extends Zend_Controller_Action
{
public function indexAction()
{
}
public function viewbookAction()
{
}
}
?>


Ở ví dụ này cho ta biết Controller là Book, 2 action là index và viewbook.
Như vậy, để chạy được ứng dụng. Bạn cần tạo thư mục Book trong view và file index.phtml, viewbook.phtml.
Cụ thể:
application/controller/BookController.php
application/views/scripts/Book/index.phtml
application/views/scripts/Book/viewbook.phtml

B- Zend View:

Ở bài trước, chúng ta đã làm việc sơ qua đối với mô hình view trong MVC. Tuy nhiên, những gì mà chúng ta thao tác chỉ là một phần cấu trúc của zend view. Để ứng dụng linh hoạt những thế mạnh của zend view, chúng ta cần tìm hiểu phương thức mà Zend View đang hoạt động như thế nào.
Trong ZF để xây thực thi và truyền tham số chúng ta cần sử dụng:
$this->view->tên_biến;
Và tại các thư mục view chúng ta chỉ cần sử dụng cú pháp: $this->view để lấy giá trị mà chúng ta đang truyền từ controller.
Ví dụ:
Trong controller index ta tạo action index với nội dung:
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->string= "hello Zend FrameWork";
}

}

Trong thư mục view/scripts/index/index.phtml ta lại viết đoạn code sau:
echo "

".$this->string."

";
?>

Như vậy trong controller, ta truyền biến string thông qua mô hình view của ZF. Và gán nó với giá trị mình mong muốn. Tiếp tục, ở phần view chúng ta lại sử dụng biến khởi tạo ở controller. Bằng $this->tên_biến.

Bạn cũng có thể sử dụng một mảng lưu thông tin và sử dụng view để gởi thông tin của mảng ấy:

class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$data= array(
'title' => 'Zend Framework',
'author'=> 'Kenny',
'date' => '20-11-2009',
'rating'=> 'very Hard'
);
$this->view->info =$data;
}
}


Và trang view nhận giá trị của mảng này:

foreach($this->info as $k => $v)
{
echo "$k: $v
";
}
?>

C- Zend Layout:

ZF hỗ trợ người sử dụng bằng một số phương thức đặc biệt. Nó cho phép người sử dụng dễ dàng thay đổi thông tin hoặc giao diện của layout hoặc có thể khởi tạo cùng lúc nhiều giao diện trong hệ thống ZF.
Để sử dụng zend layout. Bạn cần cấu hình trong file application.ini thông số sau:
Trong phân đoạn [production] chúng ta thêm đoạn code sau:
resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "layouts/scripts"

Hai dòng này cho ZF biết thông tin về layout của chúng ta. Như vị trí đặt layout ở đâu và tên của file layout là gì.
Như vậy, ta có thể tạo thư mục layout trong thư mục application để giải quyết bài toán này.
Tại trang application/layouts/scripts/layout.phtml .bạn có thể cấu hình các thông tin như:
doctype() ?>


headTitle() ?>
headLink() ?>
headStyle() ?>
headScript() ?>


layout()->content ?>



Thông tin ở trên dùng để cấu hình các thông số như DOCTYPE, TITLE, LINK CSS,….của một tài liệu HTML.
Phần $this->layout()->content là phần hiển thị view trong mỗi action của chúng ta.
Như vậy trong controller, chúng ta sẽ chuyển nội dung file CSS đến layout thông qua zend view. Và đặt chúng trong hàm init(). Hàm init() là hàm đặc biệt trong cấu trúc ZF, nó sẽ được ZF ưu tiên gọi đầu tiên khi chúng viếng thăm bất cứ controller nào có mặt hàm init.
Như vậy ta có cách xây dựng như sau:

class BlogController extends Zend_Controller_Action
{
function init(){
$dir=$this->_request->getBaseUrl ();
$this->view->headLink()->appendStylesheet($dir.'/public/css/style.css');
$this->view->headLink()->offsetSetStylesheet(1, $dir.'/public/css/style.css', 'all');
$this->view->headLink()->prependStylesheet($dir.'/public/css/style.css', 'screen', 'lte IE 8');
}
public function indexAction()
{
}
}

Chú ý dòng :

$dir=$this->_request->getBaseUrl ();

Việc truyền tham số CSS, javascript,…., chúng ta phải sử dụng đường dẫn tương đối. Nghĩa là lấy ra đường dẫn hiện tại của người sử dụng rồi mới tiến hành truy cập vào đường dẫn thư mục của chúng. Trong trường hộp này tôi đặt file CSS trong thư mục public. Vậy một lần nữa ta có thể lấy được nội dung file css từ nó.

Như vậy, khi người dùng truy cập vào bất kỳ action nào của controller blog, chúng đều triệu gọi layout này giúp bạn rất rõ ràng.

Tuy nhiên, trong một số trường hợp chúng ta sẽ không thể lấy được thông tin từ getBaseUrl(). Nhất là với trường hợp cấu hình website phá vỡ kiến trúc chuẩn của Zend. Và lúc này bạn cần phải sử dụng controller để cấu hình điều hướng chính.

Lúc này trong file bootstrap.php, chúng ta phải viết phương thức _initControllers(). Đây là phương thức cho phép chúng ta triệu gọi đầu tiên, thường được dùng để cấu hình controller.

Như vậy ta cấu hình thông tin hàm như sau:

protected function _initControllers()
{
$frontController = Zend_Controller_Front::getInstance();

$frontController->setBaseUrl('/projects/myapp');
}
?>

Trong ví dụ này, chúng ta setBaseUrl mặc định sẽ là thư mục /project/myapp.


D- Zend Model:
Để sử dụng model trong ZF với kiến trúc ban đầu, trước hết bạn cần thiết lập ở file bootstrap.php với tham số sau:
protected function _initAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => '',
'basePath' => dirname(__FILE__),
));
return $autoloader;
}
protected function _initDB()
{
$db = Zend_Db::factory('Pdo_Mysql', array ('host' => 'localhost', 'username' => 'root',
'password' => 'root',
'dbname' => 'zfexam'));
$db->setFetchMode(Zend_Db::FETCH_BOTH);
Zend_Db_Table::setDefaultAdapter($db);
return $db;
}

Hàm _initAutoload() có trách nhiệm sẽ chỉ cho ZF hiểu rằng bạn đang muốn load với namespace nào và đường dẫn thư mục ra sao. Trong trường hợp này, tôi gọi namespace= "". Vì cấu trúc mà tôi đang cấu hình trong ZF chính là cấu trúc mặc định chưa có module.
Hàm _initDB() là hàm dùng khai báo thông tin CSDL của bạn. Với định dạng là PDO (Hãy kiểm tra xem bạn đã bật PDO chưa nhé).

Tiếp tục trong models bạn chỉ cần khởi tạo class như sau:
class Model_Info extends Zend_Db_Table_Abstract{
protected $_name = 'test';
protected $_primary = 'id';
public function listinfo()
{
$data=$this->fetchall();
return $data;
}

}

Việc khai báo tên class cũng trở nên đơn giản hơn bao giờ hết. Lúc này, vì namespace ta để rỗng. Nên không cần gọi module ở đầu cho việc khai báo trong class.
Dựa vào tên class ta có thể hiểu: Models/Info.php.
Lưu ý: mặc dù thư mục trong cấu trúc của chúng ta là Models, nhưng khi triển khai trong ZF thì ta phải sử dụng là Model.
Trước khi sử dụng, ta cần khai báo cho ZF biết tên mà bảng chúng ta cần thao tác ở đây là gì. Cụ thể là bảng test, và với khóa chính là id.

Tiếp tục, tại controller ta chỉ cần khởi tạo action và gọi chúng như sau:

public function infoAction()
{
$model= new Model_Info();
$this->view->data =$model->listinfo();
}