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

- [URL](http://d.hatena.ne.jp/localdisk/20110502/1304325847)

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

application/core/MY_Model.php

```MY_Model.php
<?php

/**
 * MY_Model
 *
 * @author localdisk
 * @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');
    }
}
```

解説するにあたってこの 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

```sample_model.php
<?php
/**
 * Sample
 *
 * @author localdisk
 */
class Sample_model extends MY_Model {

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

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

}
```

application/controllers/sample.php

```sample.php
<?php
/**
 * Sample
 *
 * @author localdisk
 * @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();
    }
}
```