こんにちは!Webエンジニアをしている南です。
CakePHPを初めて使用している時に、よくTableクラスってどんな時によく使うのだろう?とか。
Tableクラスにはどんなコードを書くのが良いのかなあ?っと悩んだことはありませんか?
僕は結構思っていました。
そこで、今回はCakePHPのTableクラスについて紹介していきます。
この記事で紹介しているCakePHPのバージョンは3系です。
CakePHPのTableクラスとは
Photo by Tim Mossholder on Unsplash
CakePHPで使用しているTableクラスは公式のドキュメントで、下記のように紹介されています。
テーブルオブジェクトは特定のテーブルに保存されたエンティティーのコレクションへのアクセスを提供します。
個人的に、CakePHPのTableクラスには、下記の3点を定義することが多いです。
1.各テーブルのリレーション
2.各値のバリデーション
3.データベースからデータを取得するメソッド。
1.各テーブルのリレーションについて
Photo by Iga Palacz on Unsplash
Tableクラスには、下記のように各テーブルのリレーションを定義することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php class UsersTable extends Table { public function initialize(array $config) { parent::initialize($config); $this->hasMany('Threads', [ 'foreignKey' => 'user_id', 'joinType' => 'INNER' ]); } } |
上記の場合だと、Threadsテーブルに各ユーザーが書いた記事が格納されていて、Threadsテーブル内の外部キーであるuser_idがUsersテーブルと関連しているということを表しています。
Tableクラスには、上記のように各テーブルのリレーションを定義します。
2.各値のバリデーションについて
Photo by dylan nolte on Unsplash
Tableクラスには、下記のように各テーブルがもつデータのバリデーションを定義することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php class UsersTable extends Table { public function validationDefault(Validator $validator) { $validator ->notEmpty('name', 'ユーザー名は必須項目です。'); return $validator; } } |
基本的な使用法は上記になります。
上記をTableクラスに定義しておくことで、下記のようにフォームから送られてきたデータを$userに格納する時に同時にバリデーションを行うことができます。
1 2 3 4 |
<?php $user = $this->Users->newEntity(); $this->Users->patchEntity($user, $this->getRequest()->getData()); |
もし、バリデーションエラーがあれば下記のようにすることでエラーを検知できます。
1 2 3 |
if ($user->errors()) { //エラー処理 } |
バリデーションに関するTips
ここでは、下記の2点を紹介します。
・バリデーションを分けたい時
・独自のバリデーションを追加したい時
バリデーションを分けたい時
Tableクラスに下記のように記載することで、バリデーションを書く場面に応じて分けることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php class UsersTable extends Table { public function validationDefault(Validator $validator) { $validator ->notEmpty('name', 'ユーザー名は必須項目です。'); return $validator; } // ユーザー編集用のバリデーション public function validationEdit(Validator $validator) { $validator ->allowEmpty('name'); } } |
上記の場合だと、デフォルトは、ユーザー名は必須ですが、編集時は必須ではない状態にすることができます。
実際使用する時は、下記のようにvalidateの箇所に指定することで分けることができます。
1 2 3 4 5 6 7 |
<?php $user = $this->Users->newEntity(); $this->Users->patchEntity($user, $this->getRequest()->getData(),[ // ここで使用するvalidaationを指定。 'validate' => 'edit', ]); |
各用途で切り分けができるのは、地味に便利ですよね。
独自のバリデーションを追加したい時
デフォルトのnotEmptyは、一応空文字の場合は防いでくれますが、例えば全角や半角のスペースが入っている場合は空として検知してくれません。
なので、スペースを使った変な入力を使いたい場合は、下記のように指定することで防いだりしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php class UsersTable extends Table { public function validationDefault(Validator $validator) { $validator ->notEmpty('name', 'ユーザー名は必須項目です。') ->add('name_furigana', 'isUserNameNotAllowedEmptyString', [ 'rule' => [$this, 'isNotEmpty'], 'message' => '店舗名のフリガナが全て空白文字になっています。', ]); return $validator; } /** * isNotEmpty method * 渡された値が空白文字ならtrueを返す。 * @param string $string * @return bool */ public function isNotEmpty(string $string): bool { return (preg_replace("/( | )/", '', $string) !== ''); } } |
ちなみに、add()の第一引数に該当のフィールド名、第二引数にはエイリアス、もしくは複数のバリデーションルールを配列形式で設定できます。
3.データベースからデータを取得するメソッドについて
Tableクラスには、下記のように各テーブルがもつデータを取得するためのメソッドも定義することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php class UsersTable extends Table { /** * @param int $userId * @return App\Model\Entity\User */ public function findUserThreadsByUserId(?int $userId): ?User { if (empty($userId)) { return null; } return $this->find() ->contain([ 'Threads', ]) ->where([ 'Users.id' => $userId, ]) ->first(); } } |
実際に上記で定義したfindメソッドは、下記のように書くことで使用することできます。
1 2 3 |
<?php $user = $this->Users->findUserThreadsByUserId(1); |
また、上記のコードは下記のように記載して、使用することもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php class UsersTable extends Table { /** * @param Cake\ORM\Query $query * @param array $options * @return App\Model\Entity\User */ public function findUserThreadsByUserId(Cake\ORM\Query $query, array $options): ?User { if (!isset($options['user_id'])) { return null; } $this->find() ->contain('Threads') ->where([ 'Users.id' => $options['user_id'], ]) ->first(); return $query; } } |
実際に使用する時は、下記のように使用します。
1 2 3 4 |
<?php $options = ['user_id' => 1]; $user = $this->MeisterAnswers->find('userThreadsByUserId, $options); |
個人的には1番目の方が、完結でわかりやすくて良いと思っています。
まとめ
今回はCakePHPのTableクラスについて紹介しました。
CakePHPのTableクラスでは、主に下記を記載することができます。
1.各テーブルのリレーション
2.各値のバリデーション
3.データベースからデータを取得するメソッド。
他にも色々ありますが、基本的には上記3点を抑えておけば大丈夫かと思います。
他の使用方法が気になる方は、ぜひ公式ドキュメントを見てみてください!
https://book.cakephp.org/3/ja/orm/table-objects.html
この記事がCakePHPのTableクラスってどういう風に使うのだろう、と思っている人の約に立てれば幸いです。