Trình bày trang và layout ZF
Trình bày trang web trong ứng dụng Skeleton liên quan đến các lớp đối tượng gồm mô hình MVC của ZF trong Zend\Mvc
,
các chức năng để truy cập biến truyền đến view, dựng HTML trong Zend\View
Với ứng dụng Skeleton bạn đã cài đặt, việc trình bày và điều khiển ứng sử trang với người dùng còn tích hợp sẵn thư viện CSS
getBootstrap và jQuery,
ở đây coi như bạn đã biết về cách dùng hai thư viện này.
Ở mục Đổi template ZF và mục View Helper chúng ta đã biết cách ZF sử dụng template và layout để dựng trang, bạn hãy đọc qua lại để nhớ. Giờ ta sẽ tìm hiểu một số đặc điểm thường dùng khi dựng HTML với View của ZF.
Tạo một ứng dụng đơn giản ZF3
Để thực hành và hiểu các vấn đề ta sẽ tạo ra một Controller mới, hiện thị thông tin sản phẩm. Các kiến thức mà bạn dùng đến gồm: Tạo một Controller và các Action, Đăng ký Controller, Viết Route, Tạo template cho từng Action
Bước 1 : Tạo Controller: Product
, có hai action là category
và detail
module/Application/src/Controller/ProductController.php
<?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; class ProductController extends AbstractActionController { public function categoryAction() { } public function detailAction() { } }
Bước 2 : Tiến hành đăng ký tên controller trên vào hệ thống, bằng cách cập nhật module.config.php
module/Application/config/module.config.php
//.. 'controllers' => [ 'factories' => [ Controller\IndexController::class => Controller\IndexController::class, \Application\Controller\ProductController::class => InvokableFactory::class, //... ], ], //..
Bước 3 : Đăng ký route vào hệ thống. Với các URL truy cập đến controller/action như sau
http://localhost/zf3/product/
sẽ gọi đến actioncategory
http://localhost/zf3/product/[categoryname]/
sẽ gọi đến actioncategory
và lưu lại thông tin categorynamehttp://localhost/zf3/product/[categoryname]/[productname].html
sẽ gọi đến actiondetail
và có lưu lại thông tin categoryname và productname
Để đáp ứng việc, khai báo hai route có tên showcategory
và showdetail
như sau:
module/Application/config/module.config.php
//... 'router' => [ 'routes' => [ //... 'showcategory' => [ 'type' => Segment::class, 'options' => [ 'route' => '/product/[:categoryname/]', 'defaults' => [ 'controller' => Controller\ProductController::class, 'action' => 'category', ], ], ], 'showdetail' => [ 'type' => Segment::class, 'options' => [ 'route' => '/product/[:categoryname/:productname].html', 'defaults' => [ 'controller' => Controller\ProductController::class, 'action' => 'detail', ], ], ], //... ], ], //...
Bước 5 : Tạo 2 file template tương ứng với 2 action của controller là category.phtml
và detail.phtml
với nội dung như sau:
module/Application/view/application/product/category.phtml
<h1>Thông tin về Category Sản phẩm</h1>
module/Application/view/application/product/detail.phtml
<h1>Thông tin chi tiết sản phẩm</h1>
Mời chạy thử với url như: http://localhost/zf3/product/do-gia-dung/
và http://localhost/zf3/product/do-gia-dung/ban-la-a123.html
để xem action category
và detail
đã hoạt động, tương ứng với template là category.phtml
và detail.phtml
Đổi layout ứng dụng
Bạn có thể sửa file template module/Application/view/layout/layout.phtml
theo nhu cầu riêng của bạn. Ngoài ra bạn cũng có thể tạo layout mới, và thiết lập một số action,
sử dụng layout riêng này. Ví dụ bạn copy module/Application/view/layout/layout.phtml
thành module/Application/view/layout/layoutproduct.phtml
và mở ra sử một số thông tin
cho khác biệt như: chuyển sử dụng getBootstrap 4.x
module/Application/view/layout/layoutproduct.phtml
<?= $this->doctype() ?> <html lang="en"> <head> <meta charset="utf-8"> <?= $this->headTitle('Sản phẩm với ZF')->setSeparator(' - ')->setAutoEscape(false) ?> <?= $this->headMeta() ->appendName('viewport', 'width=device-width, initial-scale=1.0') ->appendHttpEquiv('X-UA-Compatible', 'IE=edge') ?> <!-- Le styles --> <?= $this->headLink(['rel' => 'shortcut icon', 'type' => 'image/vnd.microsoft.icon', 'href' => $this->basePath() . '/img/favicon.ico']) ->prependStylesheet($this->basePath('public/css/style.css')) ->prependStylesheet($this->basePath('public/css/bootstrap-theme.min.css')) ->prependStylesheet('https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css') ?> <!-- Scripts --> <?= $this->headScript() ->prependFile($this->basePath('public/js/bootstrap.min.js')) ->prependFile($this->basePath('public/js/jquery-3.1.0.min.js')) ?> </head> <body class="p-4"> <div class="container"> <nav class="navbar navbar-expand-lg navbar-dark bg-danger"> <a class="navbar-brand" href="<?=$this->url("home")?>">Trang chủ</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="<?=$this->url('showcategory')?>"> Danh mục sản phẩm</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Giới thiệu</a> </li> </ul> </div> </nav> </div> <div class="container"> <?= $this->content ?> <hr> <footer> <p>© 2000 - <?= date('Y') ?> by Công ty của bạn.</p> </footer> </div> <?= $this->inlineScript() ?> </body> </html>
Sau đó đăng ký template layout này vào hệ thống bằng một cái tên ví dụ: layoutproduct
module/Application/config/module.config.php
'view_manager' => [ //... 'template_map' => [ 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index' => __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', 'layoutproduct' => __DIR__ . '/../view/layout/layoutproduct.phtml', //... ], //... ], //..
Lúc này trong các action của controller mà muốn sử dụng layout mới tên layoutproduct thay cho layout mặc định thì thêm đoạn code
$this->layout()->setTemplate('layoutproduct');
Ví dụ:
module/Application/src/Controller/ProductController.php
<?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; class ProductController extends AbstractActionController { public function categoryAction() { $this->layout()->setTemplate('layoutproduct'); } public function detailAction() { $this->layout()->setTemplate('layoutproduct'); } }
Mời chạy thử với url như: http://localhost/zf3/product/do-gia-dung/
và http://localhost/zf3/product/do-gia-dung/ban-la-a123.html
để xem nó đã dùng layout mới
Thay layout tất cả các action
Trong các controller có phương thức onDispatch(MvcEvent $e)
, hàm này tự động gọi sau khi Action thi hành xong, bạn chỉ cần nạp chồng hàm này để thiết lập layout.
Ví dụ sau kết quả tương đương với thiết lập trong từng Action
<?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\Mvc\MvcEvent; class ProductController extends AbstractActionController { public function onDispatch(MvcEvent $e) { //Thi hành hàm onDispatch mặc định $response = parent::onDispatch($e); //Thiết lập layout mới $this->layout()->setTemplate('layoutproduct'); return $response; } public function categoryAction() { } public function detailAction() { } }
Sử dụng Partial trong View
Ví dụ sửa action category của Controller như sau
module/Application/src/Controller/ProductController.php
//... public function categoryAction() { $category = [ [ 'id' => 1, 'name' => 'Máy ảnh số', 'amout' => 90, ], [ 'id' => 2, 'name' => 'Máy nghe nhạc', 'amout' => 45, ], [ 'id' => 3, 'name' => 'Vỏ điện thoại', 'amout' => 45, ], [ 'id' => 4, 'name' => 'Pin', 'amout' => 39, ], [ 'id' => 5, 'name' => 'Xác dự phòng', 'amout' => 29, ], ]; return new ViewModel(['category' => $category]); } //..
Với code trên, ViewModel đã chuyển biến dữ liệu $category vào template category.phtml
Giờ sửa category.phtml
và lấy dữ liệu controller truyền đến để dựng HTML
<?php $this->headTitle('Partial View Demo'); ?> <h1 class="text-primary">Thông tin danh mục sản phẩm</h1> <p> Đây là dữ liệu do controller truyền đến trong biến có tên <strong>$this->category</strong> </p> <table class="table table-striped table-hover"> <tr> <th>ID</th> <th>Category</th> <th>Số lượng</th> </tr> <?php foreach ($this->category as $cate) { ?> <tr> <td> <?= $cate['id'] ?> </td> <td> <?= $cate['name'] ?> </td> <td> <?= $cate['amount'] ?> </td> </tr> <? } ?> </table>
Mời chạy với URL: http://localhost/zf3/product/
kết quả:
Bạn quan sát đoạn mã trong template
<tr> <td> <?= $cate['id'] ?> </td> <td> <?= $cate['name'] ?> </td> <td> <?= $cate['amount'] ?> </td> </tr>
Đoạn mã xuất ra mã HTML từng dòng của bảng, lặp lại cho hết tất cả các mục. Một ý tưởng ở đây là nhóm các đoạn mã đó vào một script template khác sau đó dùng partial() để dựng với cú pháp như sau:
$this->partial('name_template', $value)
name_template
là tên dẫn đến file .pthml, $value
là mảng chứa dữ liệu truyền tới .phtml
Ở ví dụ trên, bạn lưu đoạn mã dựng dòng của bảng vào file template có tên rowcate.phtml
module/Application/view/application/partial/rowcate.phtml
<tr> <td> <?= $cate['id'] ?> </td> <td> <?= $cate['name'] ?> </td> <td> <?= $cate['amount'] ?> </td> </tr>
Giờ sửa lại category.phtml
<?php $this->headTitle('Partial View Demo'); ?> <h1 class="text-primary">Thông tin danh mục sản phẩm</h1> <p> Đây là dữ liệu do controller truyền đến trong biến có tên <strong>$this->category</strong> </p> <table class="table table-striped table-hover"> <tr> <th>ID</th> <th>Category</th> <th>Số lượng</th> </tr> <?php foreach ($this->category as $cate) { echo $this->partial('application/partial/rowcate', ['cate' => $cate]); } ?> </table>
Kết quả là đã dùng template rowcate để dựng từng dòng dữ liệu bảng. Kết quả cuối cùng như trên
Sử dụng Placeholder
Đây là kỹ thuật mà mã HTML phát sinh được lưu vào session sau đó đọc lại để sử dụng chứ không xuất trực tiếp.
Một khối HTML muốn lưu lại thì đầu tiên chọn một cái tên gọi là keyholder
.
Cú pháp sử dụng như sau:
<!--Bắt đầu khối HTML --> <?php $this->placeholder('keyholder')->captureStart(); ?> <!--Các mã HTML sẽ lưu vào keyholder --> <?php $this->placeholder('keyholder')->captureEnd(); ?> <!--Lấy nội dung trong keyholder --> <? $noidung = $this->placeholder('keyholder');?>
Ví dụ sửa lại category.phtml
với kỹ thuật sử dụng placeholder
module/Application/view/application/product/category.phtml
<?php $this->headTitle('Partial View Demo'); ?> <h1 class="text-primary">Thông tin danh mục sản phẩm</h1> <p> Đây là dữ liệu do controller truyền đến trong biến có tên <strong>$this->category</strong> </p> <?php $this->placeholder('listcategory')->captureStart(); ?> <table class="table table-striped table-hover"> <tr> <th>ID</th> <th>Category</th> <th>Số lượng</th> </tr> <?php foreach ($this->category as $cate) { echo $this->partial('application/partial/rowcate', ['cate' => $cate]); } ?> </table> <? $this->placeholder('listcategory')->captureEnd();?> <?php $this->placeholder('rightaside')->captureStart(); ?> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Quảng cáo</h3> </div> <div class="panel-body"> <strong>Học lập trình Zend Framework 3</strong> <p>Các thông tin về lập trình PHP và các Framework hay dùng. Học lập trình, học lập trình, học lập trình</p> <a target="_blank" href="https://xuanthulab.net/"> Chi tiết </a> </div> </div> <? $this->placeholder('rightaside')->captureEnd();?> <div class="row"> <div class="col-md-8"> <?=$this->placeholder('listcategory') ?> </div> <div class="col-md-4"> <?=$this->placeholder('rightaside')?> </div> </div>
Kết quả chạy thử
Thêm JS và CSS
Trong .phtml
có thể thêm vào CSS và JS từ file hoặc nhúng mã.
Thêm JS
Cú pháp thêm bằng cách gọi các phương thức thích hợp từ headScript() như: appendFile(), prependFile(), appendScript(), prependScript()
$this->headScript()->appendFile('/js/yourscript.js');
Thêm InlineScript JS
$script = "alert('Hi')"; $this->inlineScript()->appendScript($script);
Thêm CSS
Thêm file CSS
$this->headLink()->appendStylesheet('/css/style.css'); //Hoặc prependStylesheet
Têm CSS inline
$css = "body {background:red;}"; $this->HeadStyle()->appendStyle($css); //Hoặc $this->HeadStyle()->prependStyle($css);
<?php $this->placeholder('rightaside')->captureStart(); ?> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Quảng cáo</h3> </div> <div class="panel-body"> <strong>Học lập trình Zend Framework 3</strong> <p>Các thông tin về lập trình PHP và các Framework hay dùng. Học lập trình, học lập trình, học lập trình</p> <a target="_blank" href="https://xuanthulab.net/"> Chi tiết </a> </div> </div> <? $this->placeholder('rightaside')->captureEnd();?>