進階資料庫操作

這個章節不太會動到 UI,我們要開始重構資料庫存取的部分,讓我們擁有強大的 Model 可以使用。

改用 insertObject 與 updateObject() 儲存資料

前面的教學是以 SQL 指令來插入資料,不過我們現在要改用方便一點的方法,不用花那麼多力氣在組合 SQL,只要把陣列丟給 $db 物件就能夠儲存了:

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

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

defined('_JEXEC') or die;

class BlogModelArticle extends BaseDatabaseModel
{
    // ...

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

        $id = $data['id'];

        $data = (object) $data;

        // 有 id 時用 update
        if ($id)
        {
            $db->updateObject('#__blog_articles', $data, 'id');
        }

        // 沒有 id 時用 insert
        else
        {
            $db->insertObject('#__blog_articles', $data);
        }

        return true;
    }

    // ...
}
 

如上面的範例,改用 insertObject()updateObject() 來建立或更新資料,DB 物件會自動幫我們處理好SQL的語法。這兩個方法只能吃物件,所以我們必須預先把$data 轉成物件形式。其中要特別注意,updateObject() 的第三個參數是必須的,我們要告訴DB物件以 id 為判斷標準來更新,也就是之前寫 SQL 時的 WHERE

現在你可以嘗試再次新增或修改文章看看,應該是可以正常運作的。

改用 JTable 來存取資料

JTable 是一個非常好用的 ActiveRecord 物件,我們可以用 JTable 來快速的存取單一一筆資料庫記錄。

首先,讓我們建立一個 Article 的 Table 物件在 tables/article.php

<?php
// administrator/components/com_blog/tables/article.php

use Joomla\CMS\Table\Table;

defined('_JEXEC') or die;

class BlogTableArticle extends Table
{
    public function __construct($db)
    {
        parent::__construct('#__blog_articles', 'id', $db);
    }
}
 

接著我們就可以在元件的任何地方呼叫這個 Table 物件,Table 的呼叫方法是這樣:

// 在 Model 中
$table = $this->getTable('Article', 'BlogTable');

// 在任何地方
$table = \Joomla\CMS\Table\Table::getInstance('Article', 'BlogTable');
 

JTable 的主要功能就是方便我們快速存取單筆資料,而他本身就是 Data 的容器:

// 讀取記錄
$table->load($id);

// Table 本身就是 data 容器,直接取值即可
echo $table->title;
echo $table->alias;

// 也可以直接塞資料
$table->title = 'New Title';

// 或是綁定一個陣列進去
$table->bind($data);

// 然後儲存,store() 會自動幫你判斷id存在與否而選擇 insert 或 update
$table->store();
 

用 JTable 取得記錄

現在我們將 Article Model 中的 getItem() 改用 Table 來取得文章:

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

public function getItem()
{
    $table = $this->getTable('Article', 'BlogTable');

    $input = JFactory::getApplication()->input;

    $id = $input->get('id');

    if (!$id)
    {
        return false;
    }

    $table->load($id);

    return $table;
}
 

你會發現我們只要用 load() 就能快速以 id 取得一筆記錄,然後整個 table 物件 return 回去即可直接使用。

用 JTable 儲存記錄

現在,我們把剛剛 save() 再改用 JTable 來儲存,你會發現變得驚人的簡潔:

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

public function save($data)
{
    $table = $this->getTable('Article', 'BlogTable');

    $table->bind($data);

    return $table->store();
}
 

用 JTable 刪除記錄

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

public function delete($id)
{
    $table = $this->getTable('Article', 'BlogTable');

    return $table->delete($id);
}
 

用 Proxy 模式快速取得 Table

覺得老是要寫 getTable('Article', 'BlogTable') 這麼長一串很麻煩嗎?我們來寫一個代理方法,繼承 parent 的 getTable():

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

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

defined('_JEXEC') or die;

class BlogModelArticle extends BaseDatabaseModel
{
    public function getTable($name = 'Article', $prefix = 'BlogTable', $options = array())
    {
        return parent::getTable($name, $prefix, $options);
    }

    // ...    
}
 

現在在 Model 裡面我們只需要用 $this->getTable() 就能取得 Article Table 了,不用再寫落落長的參數啦。

用 Query Builder 來建立 SQL

在複數的 Articles Model 中,因為有比較複雜的查詢邏輯,我們無法方便的用 Table 來取得資料,因此,SQL語法還是必要的工具。不過 Joomla 中提供了一個方便的物件,讓我們不用再很笨的去組織 SQL 字串,而是藉由物件導向的方法來寫出 SQL 指令,這個物件叫做 Query Builder。

Query Builder 的用法

只要我們取得 DB 物件,就隨時可以取得 Query Builder。

// 取得 Query Builder,true 代表一個新的物件。沒有 true 的話會取得上一次 setQuery() 的內容。
$query = $db->getQuery(true);
 
//簡單的 select
$query->select('*')
    ->from('#__my_table')
    ->where('id = 12')
    ->where('state >= 1')
    ->order('date ASC');

// 簡單的 insert
$query->insert('#__my_table')
    ->columns('title, alias, introtext')
    ->values($values);

// 簡單的 Update
$query->update('#__my_table')
    ->set('title = "New Title"')
    ->set('alias = "New Alias"')
    ->where('id = 12');

// 簡單的 Delete
$query->delete('#__my_table')
    ->where('id = 15');
 

用 Query Builder 重寫 list query

我們改用 Query Builder 重寫之前 Articles Model 的 getItems():

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

use Joomla\CMS\MVC\Model\BaseDatabaseModel;

defined('_JEXEC') or die;

class BlogModelArticles extends BaseDatabaseModel
{
    public function getItems()
    {
        $db = $this->_db;

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

        $query->select('*')
            ->from('#__blog_articles')
            ->order('id ASC');

        $db->setQuery($query);

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

看起來變化不大,不過等到未來我們要加入複雜的過濾與搜尋功能時就會派上用場了。


本章節的程式碼可以在 GitHub 上參考: Code / Commits

ukash birim çevirme saç ekimi estetik