加入Model,撈取資料庫

有了 View 以後,我們就要試著加入 Model 來取得資料。讓我們依照以下步驟建立 Model。

建立 Example Model

Model 一般來說放在 models 目錄下,這樣 controller 才能夠自動加載 model class,我們先建立一個 Example Model 吧

<?php
// administrator\components\com_blog\models\example.php

use Joomla\CMS\Date\Date;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

defined('_JEXEC') or die;

class BlogModelExample extends BaseDatabaseModel
{
    public function getItem()
    {
        $item = new stdClass;

        $item->title = 'Example View & Template';
        $item->content = 'Go go let\'s go~~~!!!!';
        $item->date = new Date('now', 'Asia/Taipei');

        return $item;
    }
}
 

這個 Model 實作了一個 getItem() method 讓 controller 可以要資料,並返回一個物件。

然後修改一下 controller 來取得 model。

<?php
// administrator\components\com_blog\controller.php

use Joomla\CMS\MVC\Controller\BaseController;

defined('_JEXEC') or die;

class BlogController extends BaseController
{
    public function display($cachable = false, $urlparams = array())
    {
        // Get model & view
        $model = $this->getModel('Example');
        $view = $this->getView('Example', 'html');

        // Get item
        $item = $model->getItem();

        // Push item into view
        $view->item = $item;

        $view->display();
    }
}
 

我們接著更改 View 的幾個檔案來對應剛剛的變更

<?php
// administrator\components\com_blog\views\example\view.html.php

use Joomla\CMS\MVC\View\HtmlView;

defined('_JEXEC') or die;

class BlogViewExample extends HtmlView
{
    public function display($tpl = null)
    {
        $this->item->date = $this->item->date->format('Y-m-d', true);

        parent::display($tpl);
    }
}
 
<?php
// administrator\components\com_blog\views\example\tmpl\default.php

defined('_JEXEC') or die;
?>
<h1><?php echo $this->item->title; ?></h1>
<p><?php echo $this->item->content; ?> in <?php echo $this->item->date; ?></p>
 

這裡稍微注意一下,我們從 Model 把 $item->date 拿出來,但是在 View 物件中,預先做好格式化(format),這樣在 Template 中就只要 echo 出來即可,不用擔心資料的格式。日後大家可以善用 View 物件來處理 Model 進來的 data ,經過各種格式化以後,再交給 Template 印出,會更有結構。

結果應該沒變,我們只是作 refactor 而已

p-2014-09-02-9.jpg

將 Model 注入 View 中

以上皆為傳統的 MVC 運作模式,View 與 Model 不互相溝通,由 controller 來傳遞資料。

但在 Joomla 中的 MVC 其實比較像 MVP 或 MVVM,是一種 MVC 的變體,我們可以從 controller 中將 View 與 Model 繫結起來,於是 View 擁有權力決定要跟 Model 要什麼資料(但 View 不能選擇 Model)。

這種模式在單一頁面卻有多種 layout 版型的時候,其實是很不錯的設計,算是以 UI 為驅動的模式。接下來我們來實作這個模式,要注意在 Joomla 的所有元件中,其實是以這種模式為主流的。

首先更改 controller ,將 model 注入 view 裡面,setModel() 的第二個參數 true 代表這是 default model,意味著你可以裝載多個 model。

<?php
// administrator\components\com_blog\controller.php

use Joomla\CMS\MVC\Controller\BaseController;

defined('_JEXEC') or die;

class BlogController extends BaseController
{
    public function display($cachable = false, $urlparams = array())
    {
        // Get model & view
        $model = $this->getModel('Example');
        $view = $this->getView('Example', 'html');

        // Push model into view
        $view->setModel($model, true);

        $view->display();
    }
}
 

接著 View 物件拿出 Model 來 getItem()

<?php
// administrator\components\com_blog\views\example\view.html.php

use Joomla\CMS\MVC\View\HtmlView;

defined('_JEXEC') or die;

class BlogViewExample extends HtmlView
{
    public function display($tpl = null)
    {
        $model = $this->getModel('Example');

        $this->item = $model->getItem();

        $this->item->date = $this->item->date->format('Y-m-d', true);

        parent::display($tpl);
    }
}
 

結果應該是不會變的,表示操作成功

p-2014-09-02-9.jpg

我們還有更簡單的方法可以 getItem(),請參考如下寫法

public function display($tpl = null)
{
    $this->item = $this->get('Item');

    if(!$this->item)
    {
        throw new \Exception('No item.');
    }

    $this->item->date = $this->item->date->format('Y-m-d', true);

    parent::display($tpl);
}
 

在 View 物件中,呼叫 get('Xxx') 就等於呼叫 Default Model 中的 getXxx(),如果這個 method 不存在,則返回 NULL。讓我們的程式碼更簡潔,也更容易處理錯誤狀況。

如果你裝載了兩個以上的 models 在 view 裡面,可以這樣子呼叫不同 model 中的 method。

$foo = $this->get('Flower', 'Foo');
$bar = $this->get('Sakura', 'Bar');
 

建立我們的 Articles 頁面

現在我們該脫離 Example 了,讓我們來建立 Articles List 頁面吧。

首先,請用你的 MySQL 管理工具匯入此 SQL,以建立我們的第一個資料表

要注意資料表名稱開頭要帶換成你的資料表前綴字,例如安裝時你用了 j3_ 當做前綴字,則這裡要改成 j3_blog_articles。一般來說我們建議的資料表命名原則為 {前綴字}_{元件名}_{MVC名(複數)} 這樣有較高的表達性,也不容易跟其他元件衝突。

有了資料表與三筆記錄後,我們就開始建立 Articles 頁面吧,可以把剛剛的 Example mvc 給忘了,依序建立以下檔案:

Controller

<?php
// administrator\components\com_blog\controller.php

use Joomla\CMS\MVC\Controller\BaseController;

defined('_JEXEC') or die;

class BlogController extends BaseController
{
    public function display($cachable = false, $urlparams = array())
    {
        // Get model & view
        $model = $this->getModel('Articles');
        $view = $this->getView('Articles', 'html');

        // Push model into view
        $view->setModel($model, true);

        $view->display();
    }
}
 

Model

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

use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

defined('_JEXEC') or die;

class BlogModelArticles extends BaseDatabaseModel
{
    public function getItems()
    {
        $db = Factory::getDbo();

        // Or using $db = $this->_db;

        $sql = "SELECT * FROM #__blog_articles";

        $db->setQuery($sql);

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

Model 這邊我們第一次用到 SQL 取得資料庫內容。

Joomla 內的資料庫操作流程,主要是先從 Factory 取得 $db 物件(Model 中可以直接用 $this->_db),然後將寫好的 SQL 字串用 setQuery() 餵給 DB 物件,接著執行 loadObjectList() 就能取得多筆 Record 資料,每筆資料都是物件,全部包成一個陣列回傳。

注意一件事,我們把 getItem() 改成複數 getItems() 了,開發過程中,建議要嚴格遵守單複數的命名。因為我們取的是複數資料,一定要命名 items 與 articles 才不會混淆。

View

<?php
// administrator\components\com_blog\views\articles\view.html.php

use Joomla\CMS\MVC\View\HtmlView;

defined('_JEXEC') or die;

class BlogViewArticles extends HtmlView
{
    public function display($tpl = null)
    {
        $this->items = $this->get('Items');

        parent::display($tpl);
    }
}
 

Template

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

defined('_JEXEC') or die;
?>
<table class="table table-striped">
    <thead>
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Intro</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach ($this->items as $item): ?>
        <tr>
            <td><?php echo $item->id; ?></td>
            <td><?php echo $this->escape($item->title); ?></td>
            <td><?php echo substr(strip_tags($item->introtext), 0, 50); ?></td>
        </tr>
        <?php endforeach; ?>
    </tbody>
</table>
 

比較有趣的是 Template 的地方,我們先用表格印出ID, Title 與 Intro 文字。其中 title 部分之所以用 $this->escape() 包起來是為了跳脫字元,以免有心人士輸入 JS 程式碼在 Title 中,製造 XSS 攻擊。

introtext 則是先移除所有 HTML tags,然後再用 substr() 限制顯示字數。我們會看到如下畫面:

p-2014-09-02-12.jpg

由於中文字是三字元組成,php內建的substr()會無法判斷中文的字元數,因而我們限制50會造成最後面擷取剩下兩個字元的亂碼。因此我們改用 StringHelper::substr() 看看:

<?php

use Joomla\String\StringHelper;

// ...
?>

<td><?php echo StringHelper::substr(strip_tags($item->introtext), 0, 50); ?></td>
 

成功依照中文字元限制 50 個字

p-2014-09-02-13.jpg

StringHelper 是很實用的 UTF-8 字元處理工具,再日後處理文字時,我們應該都要優先使用 StringHelper ,才能夠處理任何國家的語言。

頁面標題

最後我們替這個頁面加上標題吧

<?php
// administrator\components\com_blog\views\articles\view.html.php

use Joomla\CMS\MVC\View\HtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;

defined('_JEXEC') or die;

class BlogViewArticles extends HtmlView
{
    public function display($tpl = null)
    {
        $this->items = $this->get('Items');

        $this->addToolbar();

        parent::display($tpl);
    }

    public function addToolbar()
    {
        ToolbarHelper::title('Articles');
    }
}
 

建立一個 addToolbar() method,然後呼叫 JToolbarHelper 來建立標題。這個 addToolbar() 我們之後還會用到。

p-2014-09-02-14.jpg


本章節的教學內容可以在 GitHub 上找到: Code / Commits

ukash birim çevirme saç ekimi estetik