建立新聞

現在,你已經知道如何使用 CodeIgniter 從資料庫中讀取資料,但尚未將任何資訊寫入到資料庫中。在本條目,你將擴充之前創建的新聞控制器與模型以完成此功能。

開啟 CSRF 過濾器

在建立一個表單前,讓我們先打開 CSRF 保護。

打開 app/Config/Filters.php 檔案,並更新 $methods 屬性成下面這個樣子

public $methods = [
    'post' => ['csrf'],
];

它將會對所有 POST 請求啟用 CSRF 過濾器,你可以在 安全性程式庫 中閱讀更多有關 CSRF 保護的資訊。

創建表單

你需要製作出一個表單,藉由表單的輸入才能將資料存入資料庫。這代表你需要製作一個包含兩個欄位的表單,一個欄位用於標題、一個欄位用於文章內容。你將從模型中的標題派生出這個 slug 。請在 app/Views/news/create.php 新建一個包含下列程式碼的視圖。

<h2><?= esc($title) ?></h2>

<?= service('validation')->listErrors() ?>

<form action="/news/create" method="post">
    <?= csrf_field() ?>

    <label for="title">Title</label>
    <input type="input" name="title" /><br />

    <label for="body">Text</label>
    <textarea name="body" cols="45" rows="4"></textarea><br />

    <input type="submit" name="submit" value="Create news item" />
</form>

你可能會覺得 service('validation')->listErrors() 這個函數看起來很陌生。它能用於表單驗證相關的錯誤報告。而 csrf_field() 函數創建了一個帶有 CSRF 權杖的隱藏輸入框,有助於你預防一些常見的攻擊。

回到你的 News 控制器。你將在這裡執行:檢查表單是否已經提交、提交的資料是否通過驗證,這兩項操作。我們使用 表單驗證 程式庫進行驗證。

public function create()
{
    $model = model(NewsModel::class);

    if ($this->request->getMethod() === 'post' && $this->validate([
        'title' => 'required|min_length[3]|max_length[255]',
        'body'  => 'required',
    ])) {
        $model->save([
            'title' => $this->request->getPost('title'),
            'slug'  => url_title($this->request->getPost('title'), '-', true),
            'body'  => $this->request->getPost('body'),
        ]);

        echo view('news/success');
    } else {
        echo view('templates/header', ['title' => 'Create a news item']);
        echo view('news/create');
        echo view('templates/footer');
    }
}

上面的程式碼增加了很多功能。首先,我們載入了 NewsModel 。之後,我們檢查了 POST 請求是否已被處理,接著使用控制器提供的輔助函數來驗證使用者傳入的資料。在這種情況下,POST 資料,以及標題和文字欄位是必須的。

如上所述, CodeIgniter 具有強大的驗證程式庫,你可以在 這裡 閱讀更多關於這個程式庫的資訊。

繼續往下看,你可以看到一個條件式,檢查表單驗證是否成功運行。如果沒有成功,則顯示表單;如果表單提交後,也通過了所有的規則,就會呼叫模型,把新聞的資料傳遞到模型中。這裡你會看到一個新的函數 url_title() (由 URL 輔助函數 提供),它將你傳遞給它的字串使用破折號替代所有的空格,你便可以獲得一個漂亮的 slug ,這非常適合用於創建 URL 。

在這之後,就會載入一個視圖來顯示成功訊息,新建一個 app/Views/news/success.php 檔案並且寫入一些成功訊息。

你可簡單地這麼寫:

News item created successfully.

更新模型

完成了上述工作,剩下的就是將模型給設定好,讓資料可以被正確保存。 save() 方法將根據主鍵來判斷是否需要插入訊息,若是這一筆資料已存在便會執行更新。在本例中,我們並沒有傳遞 id 給它,所以它將會插入一筆新的紀錄在 news 表。

但是,在預設的情形向,模型中的插入與更新方法並不會保存任何資料,因為它不知道那些欄位是可以被安全地更新。我們可以編輯模型,在 $allowedFields 屬性中宣告可更新地欄位列表。

<?php

namespace App\Models;

use CodeIgniter\Model;

class NewsModel extends Model
{
    protected $table = 'news';

    protected $allowedFields = ['title', 'slug', 'body'];
}

這個新的屬性現在包含了允許被更新的欄位,注意到我們省略了 id 嗎?這是因為你幾乎不需要這樣做,它在資料庫中是一個自動遞增的欄位。這有助於防止 Mass assignment vulnerability 漏洞的發生。如果你的模型正在處理你的時間戳,那麼你也應該將那些時間戳排除在外。

路由

在你開始在你的 CodeIgniter 應用程式中添加新聞之前,你必須到 app/Config/Routes.php 這個設定檔添加額外的規則,這將可以確保 CodeIgniter 將 create 視為一個可執行的方法,而不是新聞的 slug 。你可以在 這裡 閱讀更多有關路由的知識。

$routes->match(['get', 'post'], 'news/create', 'News::create');
$routes->get('news/(:segment)', 'News::view/$1');
$routes->get('news', 'News::index');
$routes->get('(:any)', 'Pages::view/$1');

現在將瀏覽器指向你的 CodeIgniter 開發環境,並前往 /news/create 這個URL添加一些新聞,就可以查看你所添加的不同頁面了!

../_images/tutorial3.png ../_images/tutorial4.png

恭喜你

你剛剛完成了你第一個 CodeIgniter4 應用程式!

下圖顯示的是專案的 app 資料夾,你所創建的所有文件顯示成綠色字體。兩個你所修改的設定檔案( Config/Routes.php & Config/Filters.php )並沒有改變顏色。

../_images/tutorial9.png