findByXXX マジック メソッドは便利な場合もありますが、常にデータを取得する最も効率的な方法とは限りません。
完全に使用を避けるように言うつもりはありませんが、使用する際に考慮すべき点がいくつかあります。
1. それらは「魔法の」メソッドです
__call()
マジック メソッドは、(存在する場合) PHP によって呼び出されるマジック メソッドに依存します。すでにいくつかの議論が存在するため、ここで別の議論を開始するつもりはありません。魔法のメソッドは目的を果たし、多くの状況で使用できます。
注意してください。
- それらは(いくらかの)オーバーヘッドを引き起こします(これはほとんどの場合無視できると思います)
- IDE は追加の PhpDoc なしではそれらを認識しません
- 他のプログラマーにとってはあまり明確ではないかもしれません。なぜなら、彼らが魔法であることを知らなければ、呼び出されたメソッドの宣言を見つけることができないからです (つまり、ソース コードに存在し
findById()
ません)。
find(xxx)
2.提供されるすべての機能を提供しているわけではありません
CakePHP モデルには、多くの「関係」が定義されている場合があります。単純に呼び出すだけでModel->find('all')
必要なすべてのデータが得られますが、ほとんどの場合、必要以上のデータが得られます。Model->find('all')
CakePHP では、SQL でのこのクエリに相当します。
SELECT * FROM tableA JOIN tableB JOIN tableC.....
言い換えると; tableA、tableB、tableC のすべての関連フィールドとレコードを取得します。
ほとんどの場合、そのすべてのデータは必要ありません。このようなクエリは非効率的であり、多くのメモリを使用し、Web サイトのパフォーマンスが低下します。
CakePHP には、データを取得する深recursive
さを指定できるオプションがあります。たとえば、 を設定すると、CakePHP は「メイン」テーブルからのみデータを取得し、関連するテーブルからは取得しません。recursive = -1
SELECT * FROM tableA;
ただし、tableA と tableC からデータを取得したいが、tableB からはデータを取得したくない場合は、recursive
より細かい制御を得る
より細かく制御したい場合は、 を使用しContainable behavior
ます。この動作により、結果に含めるリレーションを正確に指定できます。たとえば、次のようになります。
$this->ModelA->find('all', array(
'fields' => array(
'ModelA.id',
'ModelA.name',
'ModelC.name',
),
'contain' => array(
'ModelC',
)
));
contain
オプションでキーを指定しない限りfind
、ContainableBehavior は何も実行しないため$actsAs
、AppModel の配列に追加することでデフォルトでこの動作を追加しても問題ありません。
具体的に
ContainableBehavior を使用しているかどうかにかかわらず、具体的であることは常に良い習慣です。CakePHP によって実行される SQL クエリを常にチェックして、意味があるかどうかを確認してください。これらのクエリによって返されるデータを常に確認してください。使用しないデータが含まれていないかどうかを確認してください。
- AppModel でrecursive を
-1
デフォルトで設定します ( public $recursive = -1;
)。実際に必要な場合にのみ、再帰を 1 または 2 に設定してください。その場合は、クエリごとにこれを行います。
- Containable 動作を使用します。これにより、クエリによって取得されるものをより細かく制御できます。
- 常に必要なフィールドを正確に指定してください。リレーション内の複数のテーブルに同じ名前のフィールドが含まれている場合にエラーを防ぐために、フィールドに Model-alias のプレフィックスを付けることをお勧めします (たとえば
'ModelA.name'
、単に の代わりに使用します'name'
) 。
データ関連のロジックをモデルに移動 - すべてをまとめる
すべてのデータ関連のロジック/コードをコントローラーから移動し、モデルに移動してみてください。
元の質問に戻るには; たとえば、任意のフィールドでモデルを検索できる独自の「便利な」メソッドを作成します。ユーザーモデルの検索を有効にして、ID、名前、および部門名のみを取得する
User extends AppModel
{
public $actsAs = array('Containable');
public function searchByField($field, $value)
{
return $this->find('all',
array(
'fields' => array(
'User.id',
'User.name',
'Department.name',
),
'conditions' => array(
// this will dynamically search by $field
$field => $value,
),
'contain' => array(
'Department',
)
)
);
}
}
これは多くのコードのように思えるかもしれませんが、CakePHP の経験が豊富になれば、このようなメソッドは 5 分以内に記述できます。プラス面では。取得する内容を完全に制御でき、ニーズに合わせて簡単に変更できます。
コントローラーでは、コードの量はわずか 1 行です。このように使用します。
// Search by email
$data = $this->User->searchByField('User.email', 'foo@example.com');
// Search by name
$data = $this->User->searchByField('User.name', 'admin');