【PHP】Adapterパターンであるカラムの値によって大きく振る舞いを変えるテーブルの扱いを多少マシにする

著者:杉浦

【PHP】Adapterパターンであるカラムの値によって大きく振る舞いを変えるテーブルの扱いを多少マシにする

 ときおり扱い難い定義のデータベースを扱う必要が出てきます。特定のカラムによって値の意味や他テーブルとの関係が大きく変わるテーブルはその一つです。
 例えば、usersテーブルにtypeカラムがあり、typeによって仮会員か一般会員か特別会員か区別するとします。それぞれ似た様で確かに違うモノです。仮会員はメールアドレス等いくつかのデータがnullでも良し、の様に別のふるまいが要求され、それが増えてくると、usersテーブルを扱うのはだんだん面倒になってきます。早い時点でuserテーブルをリファクタリングできていれば問題にならないのですが、そうならないまま既存データやコードが積み重なり今更変える時間がない、ということもあります。アダプターパターンを用いることでデータベース定義を変えないままこれを緩和できます。
 アダプターパターンは増補改訂版Java言語で学ぶデザインパターン入門 | 結城 浩 |本 | 通販 | Amazonでは次のように説明されています。

「すでに提供されているもの」と「必要なもの」の間の「ずれ」を埋めるようなデザインパターン、これが
Adapterパターン
です。

 この考えに従えば「すでに提供されているもの」はtypeによってデータの意味が大きく変わるテーブル、「必要なもの」はデータの意味ごとのテーブルです。多くのフレームワークで採用されているORM(オブジェクト関係マッピング)は1テーブルに1モデルの原則で使いやすい様に作られています。これを1つの意味に対して1モデルになる様に用います。
 具体的にはマッピングの時点でwhere句を用いて、あるテーブルの特定のtype1つに対して1モデルの様にします。
 例えばLaravelならば

/** User.php */
class User{
  // 仮会員、一般会員、特別会員に関する大量のメソッド
}

となっている1つのモデル定義ファイルを明示的なテーブル指定とグローバルスコープによって

/** TemporaryUser.php */
class TemporaryUser{
    protected $table = 'users';
    public funtion boot(){
        parent::boot();
        self::addGlobalScope('decide_user_type', static function (Builder $query) {
            $query->where('type', config('const.user.type.temporary'));
        });
    }
    // 仮会員に関するメソッド
}
/** GeneralUser.php */
class GeneralUser{
    protected $table = 'users';
    public funtion boot(){
        parent::boot();
        self::addGlobalScope('decide_user_type', static function (Builder $query) {
            $query->where('type', config('const.user.type.general'));
        });
    }
    // 一般会員に関するメソッド
}
/** SpecialUser.php */
class SpecialUser{
    protected $table = 'users';
    public funtion boot(){
        parent::boot();
        self::addGlobalScope('decide_user_type', static function (Builder $query) {
            $query->where('type', config('const.user.type.special'));
        });
    }
    // 特別会員に関するメソッド
}

と分割した3ファイルに分割します。完全に共有する部分は、ユーザ特性としてtraitを用意し、3会員モデルクラスそれぞれにuseさせることで整理できます。
 テーブルを分割する例を挙げましたが逆に複数のテーブルや設定等をまとめた上でカプセル化されたEntityクラスを作るというのもまた別のAdapterパターンの活用です。

  • この記事いいね! (1)

著者について

杉浦 administrator