0

Joomla Bài học 33: Lập trình View và xây dựng bảng dữ liệu HTML phía Administrator (HTMLView & Layout)

Trong Joomla Bài học 32, chúng ta đã hoàn thành phần hậu trường với ItemsModel (truy vấn danh sách) và DisplayController (điều phối). Trong Joomla Bài học 33, chúng ta sẽ tiến hành xây dựng phần giao diện phía Administrator — nơi dữ liệu từ Model được thổi hồn thành các bảng dữ liệu HTML (Tables), các nút công cụ hành động (Toolbar) và ô tìm kiếm trực quan cho người quản trị.

1. Vai trò của HTMLView và Layout Template

Trong mô hình MVC của Joomla, việc hiển thị giao diện được chia làm 2 lớp:

  1. HTMLView (View/Items/HtmlView.php): Lớp xử lý logic hiển thị. Nó lấy dữ liệu từ Model, chuẩn bị sẵn các tiêu đề cột, cấu hình thanh công cụ (Toolbar) và gọi file giao diện HTML tương ứng.

  2. Layout Template (tmpl/items/default.php): Tệp tin thuần HTML kết hợp PHP dạng trình bày (Presentation). Nó chịu trách nhiệm in ra bảng dữ liệu, các nút phân trang và vòng lặp qua từng dòng bản ghi.

2. Lập trình View logic (View/Items/HtmlView.php)

Tạo file tại đường dẫn: src/administrator/components/com_custom/src/View/Items/HtmlView.php

PHP

<?php
namespace MyCompany\Component\Custom\Administrator\View\Items;

\defined('_JEXEC') or die;

use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;

class HtmlView extends BaseHtmlView
{
    protected $items;
    protected $pagination;
    protected $state;

    public function display($tpl = null)
    {
        // 1. Lấy dữ liệu từ Model thông qua các phương thức chuẩn của Joomla
        $this->items      = $this->get('Items');
        $this->pagination = $this->get('Pagination');
        $this->state      = $this->get('State');

        // 2. Thêm thanh công cụ (Toolbar) ở đỉnh trang quản trị
        $this->addToolbar();

        parent::display($tpl);
    }

    /**
     * Khởi tạo các nút bấm chức năng trên thanh Toolbar (Thêm, Sửa, Xóa, Xuất bản)
     */
    protected function addToolbar()
    {
        $canDo = \Joomla\CMS\Access\Access::getActions('com_custom');
        ToolbarHelper::title(Text::_('COM_CUSTOM_MANAGER_ITEMS'), 'cube');

        if ($canDo->get('core.create')) {
            ToolbarHelper::addNew('item.add');
        }

        if ($canDo->get('core.edit')) {
            ToolbarHelper::editList('item.edit');
        }

        if ($canDo->get('core.delete')) {
            ToolbarHelper::deleteList('COM_CUSTOM_CONFIRM_DELETE', 'items.delete');
        }
    }
}

3. Lập trình Layout giao diện bảng (tmpl/items/default.php)

Layout này sử dụng các thành phần giao diện chuẩn của Joomla 5 (Bootstrap 5 và lớp Joomla\CMS\HTML\HTMLHelper để render trạng thái, sắp xếp cột).

Tạo file tại đường dẫn: src/administrator/components/com_custom/tmpl/items/default.php

PHP

<?php
\defined('_JEXEC') or die;

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var \Joomla\CMS\MVC\View\HtmlView $this */

$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn  = $this->escape($this->state->get('list.direction'));
?>

<form action="<?php echo Route::_('index.php?option=com_custom&view=items'); ?>" method="post" name="adminForm" id="adminForm">
    <div class="row">
        <div class="col-md-12">
            <!-- Ô TÌM KIẾM VÀ BỘ LỌC NHANH -->
            <div id="j-main-container" class="card shadow-sm border-0 p-3 mb-4">
                <div class="row mb-3">
                    <div class="col-md-6">
                        <div class="input-group">
                            <input type="text" name="filter_search" id="filter_search" 
                                   value="<?php echo $this->escape($this->state->get('filter.search')); ?>" 
                                   class="form-control" placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>">
                            <button type="submit" class="btn btn-primary">
                                <span class="icon-search" aria-hidden="true"></span> <?php echo Text::_('JSEARCH_FILTER_SUBMIT'); ?>
                            </button>
                            <button type="button" class="btn btn-secondary" onclick="document.getElementById('filter_search').value='';this.form.submit();">
                                <?php echo Text::_('JSEARCH_FILTER_CLEAR'); ?>
                            </button>
                        </div>
                    </div>
                </div>

                <!-- BẢNG HIỂN THỊ DỮ LIỆU -->
                <div class="table-responsive">
                    <table class="table table-striped table-hover align-middle mb-0">
                        <thead class="table-dark">
                            <tr>
                                <th width="1%" class="text-center">
                                    <?php echo HTMLHelper::_('grid.checkall'); ?>
                                </th>
                                <th width="10%" class="text-center">
                                    <?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
                                </th>
                                <th>
                                    <?php echo HTMLHelper::_('searchtools.sort', 'COM_CUSTOM_TITLE', 'a.title', $listDirn, $listOrder); ?>
                                </th>
                                <th width="15%" class="text-center">
                                    <?php echo HTMLHelper::_('searchtools.sort', 'JDATE', 'a.created', $listDirn, $listOrder); ?>
                                </th>
                                <th width="5%" class="text-center">
                                    <?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (!empty($this->items)) : ?>
                                <?php foreach ($this->items as $i => $item) : ?>
                                    <tr class="row<?php echo $i % 2; ?>">
                                        <td class="text-center">
                                            <?php echo HTMLHelper::_('grid.id', $i, $item->id); ?>
                                        </td>
                                        <td class="text-center">
                                            <?php echo HTMLHelper::_('jgrid.published', $item->state, $i, 'items.'); ?>
                                        </td>
                                        <td>
                                            <a href="<?php echo Route::_('index.php?option=com_custom&task=item.edit&id=' . (int) $item->id); ?>">
                                                <?php echo $this->escape($item->title); ?>
                                            </a>
                                        </td>
                                        <td class="text-center text-muted small">
                                            <?php echo HTMLHelper::_('date', $item->created, Text::_('DATE_FORMAT_LC4')); ?>
                                        </td>
                                        <td class="text-center text-secondary">
                                            <?php echo (int) $item->id; ?>
                                        </td>
                                    </tr>
                                <?php endforeach; ?>
                            <?php else : ?>
                                <tr>
                                    <td colspan="5" class="text-center py-4 text-muted">
                                        <?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
                                    </td>
                                </tr>
                            <?php endif; ?>
                        </tbody>
                    </table>
                </div>

                <!-- THANH PHÂN TRANG (PAGINATION) -->
                <div class="card-footer bg-white border-0 py-3 d-flex justify-content-center">
                    <?php echo $this->pagination->getListFooter(); ?>
                </div>
            </div>
        </div>
    </div>
    
    <!-- CÁC TRƯỜNG ẨN HỖ TRỢ SUBMIT FORM -->
    <input type="hidden" name="task" value="">
    <input type="hidden" name="boxchecked" value="0">
    <?php echo HTMLHelper::_('form.token'); ?>
</form>

4. Tổng kết bài học

  • Hiểu rõ sự phân tách trách nhiệm giữa HTMLView (xử lý logic, gọi Toolbar) và Layout Template (default.php).

  • Thành thạo việc sử dụng các hàm trợ giúp của Joomla như HTMLHelper::_('grid.checkall'), HTMLHelper::_('jgrid.published') và HTMLHelper::_('searchtools.sort') để tạo bảng dữ liệu chuyên nghiệp chuẩn Bootstrap 5.

Trong Bài học 34, chúng ta sẽ tiếp tục hoàn thiện thao tác Thêm & Sửa dữ liệu (CRUD Form): Lập trình Controller, Model và Form View để xử lý Thêm/Sửa bản ghi phía Administrator.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí