モデル - モデルクラスを追加する

モデル - モデルクラスを追加する

これまで、Model_Base, Model_User, Model_Companyの使い方を説明致しました

次は、Model_Baseを継承したクラスの具体的な作成方法について記述します


Base\Model_Baseを継承したクラスを定義する際にすべきことは

  1. Base\Model_Baseを継承する
  2. DBのカラムをプロパティとして定義する

の2点です

文字のみの説明では伝わりにくいため、

この先の説明は、具体例とコードを挙げて補足していきます

例として、日記を書き記すために、

  • id
  • slug: (URLになるアルファベット、記号のみの文字列)
  • tags: (日記につけるタグ、カンマ区切り)
  • title: (日記タイトル)
  • content: (日記の内容、Markdownで記述)
  • created_at
  • updated_at

といったカラムを持つ、diariesテーブルをモデルクラス化するとします


必要なファイルを生成

マイグレーションとモデルを同時に生成できるoilコマンドを使用します

$ php oil g model diary slug:string tags:string title:string content:text
    Creating model: /Users/SYS-INOUE/work/noob/tmp/fuel/app/classes/model/diary.php
    Creating migration: /Users/SYS-INOUE/work/noob/tmp/fuel/app/migrations/003_create_diaries.php

マイグレーションとクラス定義ファイルが生成されました

しかし、Model_Baseを継承する際には、このままでは使用できません

Model_Baseを継承できるように、マイグレーションファイルとクラス定義ファイルを修正していきます


1. マイグレーションファイルを修正

マイグレーションファイルで修正しなければならない項目は、

  • created_at
  • updated_at

の2点ですこの2点が下記の表のような構造になるように、マイグレーションを修正します

カラム名 NULL許可 デフォルト 追加情報
created_at TIMESTAMP しない CURRENT_TIMESTAMP
updated_at TIMESTAMP しない CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP

以下は、修正後のマイグレーションファイルです

<?php

namespace Fuel\Migrations;

class Create_diaries
{
    public function up()
    {
        \DBUtil::create_table('diaries', array(
            'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
            'slug' => array('constraint' => 255, 'type' => 'varchar'),
            'tags' => array('constraint' => 255, 'type' => 'varchar'),
            'title' => array('constraint' => 255, 'type' => 'varchar'),
            'content' => array('type' => 'text'),
            'updated_at' => array('type' => 'timestamp', 'default' => \DB::expr('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP')),
            'created_at' => array('type' => 'timestamp', 'default' => \DB::expr('CURRENT_TIMESTAMP')),

        ), array('id'), true, 'InnoDB');
    }

    public function down()
    {
        \DBUtil::drop_table('diaries');
    }
}

2. クラス定義ファイルを修正

モデルクラスのクラス定義は、以下のようになります

class Model_Diary extends \Base\Model_Base {
    public $slug    = null;
    public $tags    = null;
    public $title   = null;
    public $content = null;
}

Model_Baseを継承し、

FuelPHPが生成したプロパティを削除し、DBに存在するカラムをプロパティとして追加しました

id, created_at, updated_atはModel_Baseで既に定義されているため再定義の必要はありません

それら以外のslug, tags, title, contentをプロパティに追加しました


フックを追加

フックは、Model_Baseの説明1でも1つ具体例を挙げましたが、

Model_Diaryを用いた例を説明いたします

日記につけられたタグを表すtagsプロパティは、カンマで区切られた文字列です

これをDB上はカンマ区切りの文字列、PHP上では文字列の配列として扱えるように、フックを実装した例が以下です

class Model_Diary extends \Base\Model_Base {
    public $slug    = null;
    public $tags    = null;
    public $title   = null;
    public $content = null;

    const DELIMITER = ',';

    // 保存前:配列をカンマ区切りの文字列へ戻す
    public function before_save() {
        $this->tags = implode(self::DELIMITER, $this->tags);
    }

    // 保存後:カンマ区切りの文字列を配列へ分割する
    public function after_save($success) {
        $this->tags = explode(self::DELIMITER, $this->tags);
    }

    // 取得後:after_saveと同様に処理する
    public static function after_find($records) {
        foreach($records as &$record) {
            $record->after_save(true);
        }

        return $records;
    }
}

まず、区切り文字を表すDELIMITERを定義しました

before_saveメソッドで、

DBに保存する前にtagsプロパティの値を文字列へ戻す処理を記述しました

after_save, after_findメソッドでは、

カンマ区切りの文字列となったtagsプロパティの値を、配列へ分割しています

このように、フックでプロパティを書き換える場合には、

保存時の変換と、保存後(取得後)の復元ができるように記述します


フックによる変換処理が正しく記述できているか、

oil consoleを用いて動作確認を行います

$ oil console
Fuel 1.7.1 - PHP 5.4.28 (cli) (Jun 19 2014 14:31:57) [Darwin]
>>> $model = new Model_Diary();
>>> $model->slug       = 'this-is-a-first-diary';
>>> $model->title      = 'This is a first diary!!';
>>> $model->content    = 'Hoge hoge foo bar **buzz**';
>>> $model->tags       = ['abc', 'def', 'ghi'];
>>> $model->created_at = DB::expr('NOW()');
>>> $model->insert();
true
>>> $model = Model_Diary::find(3);
>>> $model->tags[] = 'xxxxx';
>>> $model->update();
true

DBの中身を確認しても、正しく値の挿入、更新が行われています


メソッドを追加

次に、複雑な検索条件でのSELECTやJOINを利用するクエリなど、

Model_Baseが提供していないメソッドを実装します

メソッドを追加する際に重要なのは、_getTableName()メソッドです

このメソッドは、メソッドを呼んだクラス名を取得し、テーブル名に変換して返します

引数はなく、メソッドを呼ぶだけで自分自身のクラス名と対応するテーブル名を入手できます

※ _getTableName()はstaticメソッドにすると期待通りに動作しないため、インスタンスメソッドにしております

class Model_Diary extends \Base\Model_Base {
    public $slug    = null;
    public $title   = null;
    public $content = null;

    // カラム名の配列を返す($ignoreSaveKeyに登録されたプロパティは返却されない)
    public function columns() {
        return array_keys($this->toArray());
    }

    // 検索条件を用いず、テーブルに格納されている先頭の1件だけを取得する
    public static function findFirst($order_by = 'id') {
        $table_name = static::_getTableName();

        $query = DB::select($table_name)
                    ->order_by($order_by)
                    ->limit(1);
        $result = $query->execute();

        if(is_null($result)) {
            return array();
        } else {
            $models = $result->as_array();
            return $models[0];
        }
    }
}

static::_getTableName()でテーブル名を取得することができます

Model_Baseのfindなどは実際にこれを使用し、テーブル名を取得しています

テーブル名が取得できれば、

あとは任意のクエリをFuelPHPが提供するクエリビルダ2から生成することができます

また、columnsメソッドで登場しているtoArray()メソッドは、

自分自身のインスタンスを、プロパティ => 値の連想配列へ変換するメソッドです

updateやinsertのクエリビルダに$query->set($this->toArray())とすれば、カラムと値を一度にセットすることができます


更新履歴
  • 2015/02/17: モデル - モデルクラスを追加するページ作成