🔥

CodeIgniter\Modelを使わない場合

2021/12/08に公開

CodeIgniter Advent Calendar 2021

CodeIgniter\Model

CodeIgniter4のチュートリアルのモデルは、以下のように CodeIgniter\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->where(['slug' => $slug])->first();
    }
}

CodeIgniter\Model は便利ですが、いろいろな機能が混ざっており、ちょっとわかりづらいです。

もともと、CodeIgniter3でのチュートリアルのモデルは、以下のようでした。

<?php

class News_model extends CI_Model
{
    public function __construct()
    {
        parent::__construct();

        $this->load->database();
    }

    public function get_news($slug = false)
    {
        if ($slug === false) {
            $query = $this->db->get('news');
            return $query->result_array();
        }

        $query = $this->db->get_where('news', ['slug' => $slug]);
        return $query->row_array();
    }

    public function set_news()
    {
        $this->load->helper('url');

        $slug = url_title($this->input->post('title'), 'dash', true);

        $data = [
            'title' => $this->input->post('title'),
            'slug'  => $slug,
            'text'  => $this->input->post('text')
        ];

        return $this->db->insert('news', $data);
    }
}

CodeIgniter3のように、クエリビルダーが使えればいいだけという場合には、CodeIgniter\Model を使わないという選択肢もあります。

CodeIgniter\Modelを使わない場合

いきなりですが、CodeIgniter\Model を使わないで NewsModel を書くと以下のようになります。

app/Models/NewsModel.php

<?php

namespace App\Models;

use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Database\ConnectionInterface;

class NewsModel
{
    /**
     * @var string
     */
    private $table = 'news';

    /**
     * @var ConnectionInterface
     */
    private $db;
    
    /**
     * @var BaseBuilder
     */
    private $builder;

    public function __construct(?ConnectionInterface $db = null)
    {
        if ($db === null) {
            $this->db = db_connect();
        } else {
            $this->db = $db;
        }

        $this->builder = $this->db->table($this->table);
    }

    public function getNews($slug = false)
    {
        if ($slug === false) {
            $query = $this->builder->get();
            return $query->getResultArray();
        }

        $query = $this->builder->getWhere(['slug' => $slug]);
        return $query->getRowArray();
    }

    public function save($data)
    {
        return $this->builder->insert($data);
    }
}

データベース接続

db_connect() 関数は「データベース接続」オブジェクトを返します。

            $this->db = db_connect();

引数なしで呼ぶと、データベース接続にはデフォルトの設定が使われます。

クエリビルダー

「データベース接続」の table() メソッドは、新しいクエリビルダーを返します。

        $this->builder = $this->db->table($this->table);

これで、クエリビルダーを使って、クエリを構築できます。

クエリービルダーは、最初にテーブル名を指定することと、メソッド名がcamelCaseに変わっていること以外は、CodeIgniter3のクエリビルダーとほとんど同じです。

            $query = $this->builder->get();
            return $query->getResultArray();
        $query = $this->builder->getWhere(['slug' => $slug]);
        return $query->getRowArray();
        return $this->builder->insert($data);

App\Models\Model

コンストラクタをモデルごとに毎回書くのは面倒くさいという場合は、抽象クラスにまとめましょう。

app/Models/Model.php

<?php

namespace App\Models;

use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Database\ConnectionInterface;

abstract class Model
{
    /**
     * @var string
     */
    protected $table;

    /**
     * @var ConnectionInterface
     */
    protected $db;

    /**
     * @var BaseBuilder
     */
    protected $builder;

    public function __construct(?ConnectionInterface $db = null)
    {
        if ($db === null) {
            $this->db = db_connect();
        } else {
            $this->db = $db;
        }

        $this->builder = $this->db->table($this->table);
    }
}

このクラスを継承してモデルを作成すれば、クエリビルダーの生成までは行ってくれます。

app/Models/NewsModel.php

<?php

namespace App\Models;

class NewsModel extends Model
{
    /**
     * @var string
     */
    protected $table = 'news';

    public function getNews($slug = false)
    {
        if ($slug === false) {
            $query = $this->builder->get();
            return $query->getResultArray();
        }

        $query = $this->builder->getWhere(['slug' => $slug]);
        return $query->getRowArray();
    }

    public function save($data)
    {
        return $this->builder->insert($data);
    }
}

参考

Discussion