今回は、CodeIgniter4の公式チュートリアルをまとめていきたいと思います。
このチュートリアルでは簡単なニュースサイトを作っていきます。
0.事前準備
まず事前準備として以下の2つの記事をお読みください。
次に、SQLを使ってサンプルデータの入ったテーブルおよびサンプルデータを作成します。
以下のSQLを入力し実行してください。
CREATE TABLE news ( id int(11) NOT NULL AUTO_INCREMENT, title varchar(128) NOT NULL, slug varchar(128) NOT NULL, body text NOT NULL, PRIMARY KEY (id), KEY slug (slug) );
INSERT INTO news VALUES
(1,'Elvis sighted','elvis-sighted','Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app.'),
(2,'Say it isn\'t so!','say-it-isnt-so','Scientists conclude that some programmers have a sense of humor.'),
(3,'Caffeination, Yes!','caffeination-yes','World\'s largest coffee shop open onsite nested coffee shop for staff only.');
1.ニュース一覧画面の作成
それでは実装に入っていきます。まずはニュース一覧画面の作成です。
1-1.ルーティングの編集
まずルーティングを編集していきましょう。
$routes->get('news', 'News::index');
‘news’にアクセスした時、コントローラークラス・Newsのindexというメソッドを呼び出します。
CodeIgniter4のルーティングに関しては下記の記事を参照ください。
1-2.コントローラーの設定
次にControllerを編集していきます。
<?php
namespace App\Controllers;
use App\Models\NewsModel;
use CodeIgniter\Controller;
class News extends Controller
{
public function index()
{
$model = new NewsModel();
$data = [
'news' => $model->getNews(),
'title' => 'News archive'
];
echo view('templates/header', $data);
echo view('news/overview', $data);
echo view('templates/footer', $data);
}
//以下省略
}
index()内でModelのインスタンスを生成し、 そのModelから取得したデータを$data[‘news’]に’News archive’という文字列を$data[‘title’]に格納し、viewメソッドの中に第二引数として$dataを渡しています。
CodeIgniterでは、$dataのような変数にキーと共に値を代入し、その$dataと共にViewを呼び出す際に第二引数として呼び出すことで、View内でキー名を用いた変数を用いることができます。
1-3.ビューの作成
次にViewの方を見てみましょう。
<h2><?= esc($title) ?></h2>
<?php if(!empty($news) && is_array($news)): ?>
<?php foreach($news as $news_item): ?>
<h3><?= esc($news_item['title']) ?></h3>
<div class="main">
<?= esc($news_item['title']) ?>
</div>
<p><a href="/news/<?=esc($news_item['slug'], 'url') ?>">View article</a></p>
<?php endforeach; ?>
<?php else: ?>
<h3>No News</h3>
<p>Unable to find any news for you.</p>
<?php endif; ?>
コントローラから渡された配列型変数の$dataのキー名がview内では変数名になります。
今回はニュース内容に当たる$newsが何もない場合は、表示記事がない旨の表示、ある場合はその件数に応じてタイトルとニュースへの遷移リンクを表示するHTMLになります。
タイトルについてはエスケープ処理を施しております。CodeIgniterのエスケープ処理については下記を参照ください。
1-4..モデルの作成
最後にModelを見ていきます。
<?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->asArray()
->where(['slug' => $slug])
->first();
}
}
Controllerから呼び出したModelはこのようになっています。
getNewsメソッドでは引数がなければ、全てのデータの取得、引数がある場合は、その引数に基づいてデータを取得します。これをルーティングで引数を制御することによって、同じModelのメソッドで二つの機能を実現することができます。
下のような画面ができていたら成功です。
2.記事閲覧画面の作成
続いて記事閲覧画面の作成を行います。
2-1.ルーティングの追加
まずは、ルーティングを追加します。
$routes->get('news/(:segment)', 'News::view/$1'); //追加
$routes->get('news', 'News::index');
ルーティングでは上から下に実行されるため、下の方により汎用的なルーティングを書きます。
このルーティングでは、newsの後の(:segment)の部分をNewsクラス内のviewメソッドの引数として渡します。
2-2.コントローラーの編集
それでは、コントローラーを編集していきましょう。今回は追加するviewメソッド部分だけを記載いたします。
public function view($slug = null)
{
$model = new NewsModel();
$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);
}
前回同様Modelクラスのインスタンスが生成され、getNewsメソッドが引数付きで呼び出されています。
getNewsで帰ってきた値が空であった場合、エラーメッセージが表示され、そうでない場合は、
$dataをViewに受け渡して画面を表示させます。
2-3.モデルの編集
続いてModelを編集していきましょう。
<?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->asArray()
->where(['slug' => $slug])
->first();
}
}
メソッドは同じですが、今回は引数が渡された状態でメソッドが呼び出されるので、SQLはwhereで指定した値を取得します。
これによって詳細閲覧画面のための特定の記事のデータを保持することができます。
2-4.ビューの編集
最後にViewの編集になります。
<h2><?= esc($news['title']) ?></h2>
<p><?= esc($news['body']) ?><p>
それぞれ、エスケープ処理を用いて、$news[‘title’]と$news[‘body’]を表示していま
3.記事を投稿する機能の実装
最後に記事を投稿する機能を実装して完成です。
3-1.ルーティングの追加
まずはルーティングからです。
$routes->match(['get', 'post'], 'news/create', 'News::create'); //追加
$routes->get('news/(:segment)', 'News::view/$1');
$routes->get('news', 'News::index');
前回までのルーティングに一番上のルーティングの記述を足しました。
今回はget,postの両方に対応するため’match’を用いてルートを設定し、Newsクラスのcreateメソッドを呼び出します。
3-2.コントローラーの編集
続いて、コントローラーの編集をしていきます。
public function create()
{
$model = new NewsModel();
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');
}
}
今回もデータベースを利用するので最初にModelのインスタンスを呼び出しています。
続いて、リクエストされたメソッドがポストであるかどうかのif文で条件分岐、さらにその条件の中にバリデージョンをクリアしているかの条件が加わっています。
validationの中身は、’title’が必須かつ、最低3文字、最高255文字で、’body’が必須となっております。
このif文に当てはまった場合は、$model->save()でデータベースに保存します。
保存する値は’title’がrequestに対してgetPostを用いて’title’の名前でPOSTされた値を取り、これは’body’に対しても同様の操作を行います。
‘slug’に対しては’title’で取得した値と同じ値に対してurl_title()を用いて、文字と文字の間を’-‘でつなぎ、繋がれた後の文字を大文字にします。
この’slug’は記事のURIとして使われます。
もし、投稿に成功したら、投稿成功を表示する’news/success’のViewを表示します。
もし、ポストでなかった場合は、’news/create’のViewを呼び出して、投稿フォームを呼び出します。
これで同じURIで投稿機能と投稿フォームの表示二つを実装することができます。
3-3.ビューの編集
次にViewを編集していきます。
<h2><?= esc($title) ?></h2>
<?= \Config\Services::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"></textarea><br />
<input type="submit" name="submit" value="Create news item">
</form>
2行目の記述はバリデーションエラーがあった時に表示するための標準で用意されているメソッドです。
また4行目の記述はこちらもCodeIgniter4の標準で用意されているcsrf対策用のメソッドです。
そして、inputタグとtextareaを用いて、投稿内容をPOSTできるようにし、’news/create’にformの内容を送信します。
3-4.モデルの編集
最後にModelの編集についてです。
標準で用意されているsave()をコントローラーで実行してデータベースにデータを保存します。
唯一気をつけなければいけないのは、Modelクラス内で下記の内容を宣言すること。
protected $allowedFields = ['title', 'slug', 'body'];
これによってテーブルのどのカラムにデータを保存可能であるかを定義することになります。