【CodeIgniter4】チュートリアルまとめ – ニュースアプリを作成する –

CodeIgniter

今回は、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のメソッドで二つの機能を実現することができます。

下のような画面ができていたら成功です。

f:id:tempahage:20210823223531p:plain

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'];

これによってテーブルのどのカラムにデータを保存可能であるかを定義することになります。

参考記事

Just a moment...
タイトルとURLをコピーしました