過濾欄位

除了搜尋與排序,後台還有一項特別的功能叫做過濾(filter),例如在 Joomla 內建文章中,我們常常可以選擇要顯示發佈或未發佈的文章,或是限制某個分類下的文章,這些都是透過過濾功能來運作的。本章節將會說明過濾功能怎麼樣運作。

加上發佈狀態

我們現在沒有適合用來過濾的欄位,所以先在 Articles 頁面的 template 加上發佈狀態:

<?php
// administrator\components\com_blog\views\articles\tmpl\default.php

// ...
?>

<!-- ... -->

<table class="table table-striped">
    <thead>
    <tr>
        <th><?php echo HTMLHelper::_('grid.sort', 'ID', 'id', $currentDir, $currentOrder); ?></th>
        <th><?php echo HTMLHelper::_('grid.sort', 'Title', 'title', $currentDir, $currentOrder); ?></th>

        <!-- 在 Title 的 <th> 後面加上 Published 的表頭 -->
        <th><?php echo HTMLHelper::_('grid.sort', 'Published', 'published', $currentDir, $currentOrder); ?></th>
        <th><?php echo HTMLHelper::_('grid.sort', 'Intro', 'introtext', $currentDir, $currentOrder); ?></th>
        <th><?php echo HTMLHelper::_('grid.sort', 'Delete', 'delete', $currentDir, $currentOrder); ?></th>
    </tr>
    </thead>
    <tbody>
    <?php foreach ($this->items as $item): ?>
        <tr>
            <td><?php echo $item->id; ?></td>
            <td>
                <a href='<?php echo JRoute::_('index.php?option=com_blog&task=article.edit&id=' . $item->id); ?>'>
                    <?php echo $this->escape($item->title); ?>
                </a>
            </td>
            <!-- 同樣的也在 <td> 中加入發佈狀態的顯示,1是發佈,0是未發佈-->
            <td>
                <?php if ($item->published): ?>
                <span class="label label-success">發佈</span>
                <?php else: ?>
                <span class="label label-important">未發佈</span>
                <?php endif; ?>
            </td>

        <!-- ... -->
 

p-2015-01-17-8.jpg

然後在 Article Edit 的 View template 中加入 Published 的選項, HTMLHelper::_('select.booleanList') 是一個方便用來產生「是/否」單選欄位的功能:

<?php
// administrator\components\com_blog\views\article\tmpl\default.php

use Joomla\CMS\HTML\HTMLHelper;

defined('_JEXEC') or die;
?>

    <!-- ... -->

        <!-- Created -->
        <div class="control-group">
            <label for="form-created" class="control-label">Created Time</label>
            <div class="controls">
                <?php echo HTMLHelper::_('calendar', $this->item->created, 'created', 'form-created'); ?>
            </div>
        </div>

        <!-- 加在 Created 的後面 -->

        <!-- Published -->
        <div class="control-group">
            <label for="form-created" class="control-label">Published</label>
            <?php echo HTMLHelper::_('select.booleanList', 'published', array(), $this->item->published); ?>
        </div>

    </fieldset>

    <!-- ... -->
 

p-2015-01-17-9.jpg

當我們把這個選項加進去,就可以更改每一篇文章的發佈狀態。但還需要到 Article Controller 的 save() 中把 published 的值從 request 接下來給 Model。這樣才能把 published 的值存進資料庫。

// administrator\components\com_blog\controllers\article.php

use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;

defined('_JEXEC') or die;

class BlogControllerArticle extends BaseController
{
    // ...

    public function save()
    {
        // 只取得 POST 的資料
        $post = $this->input->post;

        // 將 POST 資料塞進一個陣列中,用 getString() 避免不合法字元
        $data['id']      = $post->getInt('id');
        $data['title']   = $post->getString('title');
        $data['alias']   = $post->getString('alias');
        $data['created'] = $post->getString('created');
        $data['published'] = $post->getInt('published'); // 加上這一行
 

現在稍微更改幾篇文章的發佈狀態,他們都會顯示在頁面上,我們可以開始寫過濾功能了。

p-2015-01-17-10.jpg

過濾發佈狀態

我們先在 Articles View template 準備好過濾用的 select 清單:

<?php
// administrator\components\com_blog\views\articles\tmpl\default.php

defined('_JEXEC') or die;

$currentOrder = $this->state->get('list.ordering', 'asc');
$currentDir   = $this->state->get('list.direction', 'asc');
$filterPublished = (string) $this->state->get('filter.published', ''); // 加上這行
?>
<form action="<?php echo JUri::getInstance(); ?>" id="adminForm" name="adminForm" method="post">

    <div class="filter-bar">
        <div class="btn-wrapper input-append">
            <input type="text" name="filter_search" id="filter_search" value="<?php echo $this->state->get('filter.search'); ?>" placeholder="搜尋">
            <button type="submit" class="btn">
                <i class="icon-search"></i>
            </button>
        </div>

        <!-- 還有這個 select,我們把預設值的功能預先寫好了,一樣也是從 state 拿資料 -->
        <div class="pull-right filter-inputs">
            <select name="filter_published" id="filter_published" onchange="this.form.submit();">
                <option value="">- 請選擇 -</option>
                <option value="1" <?php echo ($filterPublished === '1') ? 'selected="selected"' : ''; ?>>發佈</option>
                <option value="0" <?php echo ($filterPublished === '0') ? 'selected="selected"' : ''; ?>>未發佈</option>
            </select>
        </div>
    </div>

    <!-- ... -->
 

這樣可以在頁面上產生一個簡易的清單來選擇發佈狀態,要注意我們有加一個 onchange="this.form.submit();" 的屬性,一旦變更項目,就會自動把表單 post 出去。但現在我們先不要做任何動作。

p-2015-01-17-11.jpg

下一步,更改 Articles Model 中的 populateState()getItems():

// administrator\components\com_blog\models\articles.php

protected function populateState()
{
    $app = Factory::getApplication();

    // 加上 filter_published 的 state
    $this->setState('filter.published', $app->getUserStateFromRequest('blog.articles.published', 'filter_published'));
    $this->setState('filter.search', $app->getUserStateFromRequest('blog.articles.search', 'filter_search'));
    $this->setState('list.ordering', $app->getUserStateFromRequest('blog.articles.ordering', 'filter_order'));
    $this->setState('list.direction', $app->getUserStateFromRequest('blog.articles.direction', 'filter_order_Dir'));
}

public function getItems()
{
    $db = $this->_db;

    $query = $db->getQuery(true);

    $ordering = $this->getState('list.ordering', 'id');
    $direction = $this->getState('list.direction', 'asc');
    $published = $this->getState('filter.published', ''); // 從 state 把過濾值拿出來,預設值是空字串
    $search = $this->getState('filter.search');

    // 只要不是空字串,就加上 where 過濾
    if ($published !== '')
    {
        $query->where('published = ' . $query->quote($published));
    }

    if ($search)
    {
        $conditions = '(`title` LIKE "%' . $search . '%"';
        $conditions .= ' OR `introtext` LIKE "%' . $search . '%"';
        $conditions .= ' OR `fulltext` LIKE "%' . $search . '%")';

        $query->where($conditions);
    }

    $query->select('*')
        ->from('#__blog_articles')
        ->order($ordering . ' ' . $direction);

    $db->setQuery($query);

    // If not thing found, return empty array.
    return $db->loadObjectList() ? : array();
}
 

主要的更改也就是加上一個 state 與一個 query where,之後一切就緒,現在可以更改發佈狀態的過濾功能看看:

p-2015-01-17-12.jpg

p-2015-01-17-13.jpg

這樣就可以只選擇想要出現的文章狀態。

過濾功能可以一直延伸,除了發佈狀態以外,精選、分類、權限、作者、語言或日期都是可以用來過濾的欄位。

但每新增一個過濾欄位就要做這麼多步驟嗎?其實有更進階的方法讓你可以快速配置一系列 filters 欄位,還能自動生成 select 清單與自動加載 state 等功能,不過這就要等待日後進階教學才會提到了,現階段一個一個欄位新增也是可以解決問題的。


本章節所有內容可以於 GitHub 上取得: Code / Commits

ukash birim çevirme saç ekimi estetik