localdisk

PHP とか Java とか Web とか好きなことを書きます。

CodeIgniter の Model を一工夫して使いやすくする方法

CodeIgniter の ActiveRecord はかなり使いやすいと思うのですが、ちょっと一工夫するともっと使いやすくなるよ! というのを書いてみたいと思います。僕が使ってる MY_Model はこんな感じ。

application/core/MY_Model.php

<?php

/**
 * MY_Model
 *
 * @author localdisk <info@localdisk.org>
 * @property CI_DB_active_record $db
 */
class MY_Model extends CI_Model {

    /**
     * table name
     * 
     * @var string
     */
    protected $_table;

    /**
     * constructor
     */
    public function __construct() {
        parent::__construct();
        $this->load->database();
        $clazz = get_class($this);
        $this->_table = strtolower(substr($clazz, 0, strpos($clazz, '_')));
    }

    /**
     * insert
     * 
     * @return integer 
     */
    public function insert() {
        $now = $this->now();
        $this->db->set(array('created_at' => $now, 'updated_at' => $now));
        $ret = $this->db->insert($this->_table, $this);
        if ($ret === FALSE) {
            return FALSE;
        }
        return $this->db->insert_id();
    }

    /**
     * update
     * 
     * @param integer|string $id
     */
    public function update($id, $data = null) {
        if ($data === null) {
            $data = $this;
        }
        $ret = $this->db->update($this->_table, $data, array('id' => $id));
        if ($ret === FALSE) {
            return FALSE;
        }
    }

    /**
     * delete
     * 
     * @param integer|strng $id 
     */
    public function delete($id) {
        $this->db->delete($this->_table, array('id' => $id));
    }

    /**
     * find_all
     * 
     * @return array
     */
    public function find_all() {
        return $this->db->get($this->_table)->result();
    }

    /**
     * find_list
     * 
     * @param  integer|string $limit
     * @return array
     */
    public function find_list($limit = 10) {
        return $this->db->limit($limit)->order_by('id')->get($this->_table)->result();
    }

    /**
     * find
     * 
     * @param  integer|string $id
     * @return stdClass
     */
    public function find($id) {
        $ret = $this->db->where(array('id' => $id))->get($this->_table)->row();
        return $ret;
    }

    /**
     * now
     * 
     * @return string
     */
    public function now() {
        return date('Y-m-d H:i:s');
    }
}

NetBeans で CodeIgniter のコード補完を行わせる冴えたやり方 - localdiskでも触れたように @property に CI_DB_active_record を定義しておくとコード補完が効いてコーディングが楽になります。
解説するにあたってこの MY_Model を使用する前提なんかを先に説明します。

  • モデル名は「テーブル名_model」にすること
    • User というテーブルのモデルを作成する場合のクラス名は User_model になります
  • id というカラムが存在すること
    • プライマリーキーですね。「テーブル名_id」することも考えましたが、こっちでいいかなーと。
  • created_at, updated_at というカラムが存在すること
    • お決まりの作成日時, 更新日時ですね。なんのかんのいって便利なので僕はすべてのテーブルに timestamp で定義してます。
    • updated_at は ON UPDATE CURRENT_TIMESTAMP にしてます。

さて、疲れてきたぞ…。
では、このクラスの肝だけ説明したいとおもいます。マニュアルや解説本などをみると insert/update 時にデータを配列で渡していますが別にクラスでもいけるっていうことです。以下上記 MY_Model クラスを使用した場合の Model と Controller を書いてみます。書くソースコードの量はあまり変わりませんが、かなり分かりやすく見えるんじゃないでしょうか。

application/models/sample_model.php

<?php
/**
 * Sample
 *
 * @author localdisk <info@localdisk.org>
 */
class Sample_model extends MY_Model {

    // カラムを public フィールドとして定義
    public $name;
    public $address;

    public function __construct() {
        parent::__construct();
    }

}

application/controllers/sample.php

<?php
/**
 * Sample
 *
 * @author localdisk <info@localdisk.org>
 * @property Sample_model $sample
 */
class Sample extends MY_Controller {

    public function __construct() {
        parent::__construct();
    }

    public function sample() {
        // validation などは割愛
        $this->load->model('sample_model', 'sample');
        $this->sample->name = $this->input->post('name');
        $this->sample->address = $this->input->post('address');
        $this->sample->insert();
    }
}

どうでしょう? 些細な違いかもしれませんが僕はこういう書き方がすきなのでこうしてます。