CodeIgniter4入門 公式チュートリアル (3)DBへのデータの追加
CodeIgniter Advent Calendar 2021
CodeIgniter4入門 公式チュートリアル (2)DBデータの表示
の続きです。
データベースへの書き込みを実装します。
目次
- CodeIgniter4入門 公式チュートリアル (1)静的ページの表示
- CodeIgniter4入門 公式チュートリアル (2)DBデータの表示
- CodeIgniter4入門 公式チュートリアル (3)DBへのデータの追加
CSRFフィルターの設定
CSRF対策のための設定を少し変更します。
app/Config/Filters.php
を以下のように変更してください。
--- a/app/Config/Filters.php
+++ b/app/Config/Filters.php
@@ -30,7 +30,7 @@ class Filters extends BaseConfig
public $globals = [
'before' => [
// 'honeypot',
- 'csrf',
+ // 'csrf',
],
'after' => [
'toolbar',
@@ -47,7 +47,9 @@ class Filters extends BaseConfig
*
* @var array
*/
- public $methods = [];
+ public $methods = [
+ 'post' => ['csrf'],
+ ];
/**
* List of filter aliases that should run on any
全てのリクエストで csrf
フィルターを有効にしていたものを、POSTメソッドのリクエストに対してのみ有効にするように変更しました。
フォームの作成
記事を書き込むためのビューファイル app/Views/news/create.php
を作成します。
<h2><?= esc($title) ?></h2>
<?= session()->getFlashdata('error') ?>
<?= 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>
session()
関数は、セッションオブジェクトを返します。
session()->getFlashdata('error')
は、セッションに保存されているフラッシュデータ error
を返します。
これは、csrf
フィルターがトークンの検証に失敗した場合に、エラーメッセージを表示します。
service()
関数は、CodeIgniter4のサービスロケータ(\Config\Services
)へのラッパーです。
CodeIgniter4では、フレームワークのクラスはサービスとして、サービスロケータから取得できます。
service('validation')
は、CodeIgniter4の Validation
オブジェクトを返します。
Validation
クラスの listErrors()
メソッドは、検証エラーをHTMLのリストで返します。
csrf_field()
関数は、CSRF対策のためのトークンをフォームに追加します。
フォームを受け取るためのコントローラメソッドの追加
News
コントローラにフォームを受け取るための create()
メソッドを追加します。
--- a/app/Controllers/News.php
+++ b/app/Controllers/News.php
@@ -37,4 +37,26 @@ class News extends Controller
echo view('news/view', $data);
echo view('templates/footer', $data);
}
+
+ 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');
+ }
+ }
}
コントローラの $this->validate()
メソッドは、リクエストのデータを検証するための便利なメソッドです。
CodeIgniter\Model
クラスの save()
メソッドは、データを挿入または更新するメソッドです。今回は、プライマリキーの指定がないため全て挿入処理になります。
書き込み成功時のビューの追加
書き込みが成功した旨のメッセージを表示するための app/Views/news/success.php
を作成します。
News item created successfully.
NewsModelの変更
NewsModel
がデータをDBに保存できるように、$allowedFields
プロパティに変更可能なカラム名を指定します。
--- a/app/Models/NewsModel.php
+++ b/app/Models/NewsModel.php
@@ -8,6 +8,8 @@ class NewsModel extends Model
{
protected $table = 'news';
+ protected $allowedFields = ['title', 'slug', 'body'];
+
public function getNews($slug = false)
{
if ($slug === false) {
ルーティングの追加
News
コントローラの create()
メソッドへのルートを追加します。
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -33,6 +33,7 @@ $routes->setAutoRoute(true);
// route since we don't have to scan directories.
$routes->get('/', 'Home::index');
+$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');
news/create
にGETまたはPOSTメソッドでアクセスされた場合に、News::create()
メソッドを呼び出します。
記事の追加
では、http://localhost/news/create にアクセスしてみましょう。
記事を入力します。
「Create news item」ボタンを押します。
書き込みに成功しました。
右下のプロファイラから、データベースクエリを確認してみます。
ニュースの一覧を表示してみます。
一番下に追加した記事が表示されています。
以上で公式チュートリアルの内容は完了しました。データベースからの読み込みと書き込み処理までが含まれています。
NewsコントローラとNewsModel
コントローラとモデルのコードは以下のようになっています。
app/Controllers/News.php
<?php
namespace App\Controllers;
use App\Models\NewsModel;
use CodeIgniter\Controller;
class News extends Controller
{
public function index()
{
$model = model(NewsModel::class);
$data = [
'news' => $model->getNews(),
'title' => 'News archive',
];
echo view('templates/header', $data);
echo view('news/overview', $data);
echo view('templates/footer', $data);
}
public function view($slug = null)
{
$model = model(NewsModel::class);
$data['news'] = $model->getNews($slug);
if (empty($data['news'])) {
throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug);
}
$data['title'] = $data['news']['title'];
echo view('templates/header', $data);
echo view('news/view', $data);
echo view('templates/footer', $data);
}
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');
}
}
}
app/Models/NewsModel.php
<?php
namespace App\Models;
use CodeIgniter\Model;
class NewsModel extends Model
{
protected $table = 'news';
protected $allowedFields = ['title', 'slug', 'body'];
public function getNews($slug = false)
{
if ($slug === false) {
return $this->findAll();
}
return $this->where(['slug' => $slug])->first();
}
}
Discussion