こんにちは!フリーランスの長野です。
findって使ってますか?
findはデータベースを検索してデータを取得する際に使われます。
この記事では、findについて
・findとは
・findの基本的な使い方
という基本的な内容から、
・findの応用的な使い方
など応用的な内容についても解説していきます。
今回はfindについて、使い方をわかりやすく解説します!
findとは
findとはエンティティを検索してデータを取得するためのメソッドです。
エンティティとはデータベースに用意されているテーブルのデータをPHPクラス用に抽象化したものです。
CakePHPでは、データベースに保存したり取り出したりしたデータは、エンティティのインスタンスになります。
したがって、findはデータベースのテーブルを検索してデータを取得する際に使用します。
findの基本的な使い方
findは下記のように記述して使用します。
findの記述方法:
find(‘all’, 連想配列);
第1引数には’all’や‘list’などを指定します。
・’all’ 全データを取得
・’list’ レコードのリストを取得
第2引数には連想配列で’limit’、‘conditions’などのオプションを設定します。
それではまずは第1引数に’all’や’list’などを指定する方法について確認していきましょう。
allで全データを取得する方法
findメソッドの第1引数に’all’を指定すると、全データを取得することができます。
サンプルコードで確認していきましょう。
なお、サンプルコードでは下記のSQLクエリで作成したテーブル「persons」を使用しています。
SQLクエリ:
CREATE TABLE persons (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name TEXT NOT NULL,
age INTEGER,
mail TEXT
);
personsテーブル:
| id | name | age | |
|---|---|---|---|
| 1 | Taro | 40 | taro@gmail.com |
| 2 | Jiro | 30 | jiro@gmail.com |
| 3 | Saburo | 25 | saburo@gmail.com |
| 4 | Hanako | 35 | hanako@gmail.com |
テーブル「persons」を作成後、bakeでmodelを作成しています。
bakeの実行例(linux):
bin/cake bake model persons
findメソッドの第1引数に‘all’を使用して全データを取得するソースコード「/src/Controller/PersonsController.php」は下記のとおりです。
URL「/persons/index」を指定した場合に、findメソッドで取得したデータを表示するように記述しています。
URL「/persons/index」のテンプレートは「/src/Template/Persons/index.ctp」で記述しています。
/src/Controller/PersonsController.php:
<?php
namespace App\Controller;
use App\Controller\AppController;
class PersonsController extends AppController
{
public function index()
{
// Entity全ての取得
$this->set('persons', $this->Persons->find('all'));
}
}
/src/Template/Persons/index.ctp:
<div>
<h3>List Persons</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>AGE</th>
<th>MAIL</th>
</tr>
</thead>
<tbody>
<?php foreach ($persons as $person): ?>
<tr>
<td><?=$person->id ?></td>
<td><?=h($person->name) ?></td>
<td><?=h($person->age) ?></td>
<td><?=h($person->mail) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
実行結果 URL「/persons/index」:

この場合は、入力した全てのデータが表示されています。
なお、先ほどbakeでmodelを作成しました。
bakeの詳しい説明についてはこちらを参照してくださいね。
listでリストを配列で取得する方法
findメソッドの第1引数に’list’を指定すると、レコードのリストを配列で取得することができます。
‘list’を指定する際に、第2引数の連想配列で‘keyField’と‘valueField’オプションを使うことで、取得する配列のキーと値に使われるフィールドを設定することも出来ます。
サンプルコードで確認していきましょう。
このサンプルコードでは、findメソッドの第2引数の連想配列に‘limit’を指定してリストの取得数を指定しています。
また、‘keyField’と‘valueField’オプションを使い、取得する配列のキーと値を設定しています。
/src/Controller/PersonsController.php:
<?php
namespace App\Controller;
use App\Controller\AppController;
class PersonsController extends AppController
{
public function index()
{
// データの値を配列として取得
$this->set('persons', $this->Persons->find('list', ['limit'=>3]));
$this->set('data', $this->Persons->find('list', ['keyField' => 'name', 'valueField' => 'mail', 'limit'=>3]));
}
}
/src/Template/Persons/index.ctp:
<div>
<h3>List Persons</h3>
<table>
<thead>
<tr>
<th>NAME</th>
</tr>
</thead>
<tbody>
<?php foreach ($persons as $person): ?>
<tr>
<td><?=$person ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<pre><?php print_r($persons->toArray()) ?></pre>
<table>
<thead>
<tr>
<th>MAIL</th>
</tr>
</thead>
<tbody>
<?php foreach ($data as $datum): ?>
<tr>
<td><?=$datum ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<pre><?php print_r($data->toArray()) ?></pre>
</div>
実行結果 URL「/persons/index」:

findメソッドの第2引数の連想配列に‘limit’を指定してリストの取得数を3に指定していますので、1つ目の表には3つのレコードのデータが表示されています。
また、リストの配列もあわせて表示しています。
なお、データとしてフィールド’name’の値が表示されています。
これはmodelをbakeした際に生成された「src/Model/Table/PersonsTable.php」の記述でdisplayFieldメソッドの引数が’name’で指定されているためです。
注意しましょう!
また、‘keyField’と‘valueField’オプションを使い、取得する連想配列のキーを’name’に、値を’mail’に設定しているので、2つ目の表には‘mail’の値が表示されています。
こちらもリストの配列をあわせて表示しています。
src/Model/Table/PersonsTable.php:
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class PersonsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('persons');
$this->displayField('name'); // 'list'で取得するフィールドの設定
$this->primaryKey('id');
}
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->requirePresence('name', 'create')
->notEmpty('name');
$validator
->integer('age')
->allowEmpty('age');
$validator
->allowEmpty('mail');
return $validator;
}
}
findの応用的な使い方
findメソッドは第2引数の連想配列でオプションを設定することができます。
また、findメソッドの後ろに「->」(アロー演算子)を使ってオプションを設定することもできます。
firstで1つ目の結果を取得する方法
findメソッドの後ろに「->」(アロー演算子)を使ってfirstを記述することで1つ目の結果を取得することができます。
firstの記述方法:
find('all')->first()
それではサンプルコードで確認していきましょう。
/src/Controller/PersonsController.php:
<?php
namespace App\Controller;
use App\Controller\AppController;
class PersonsController extends AppController
{
public function index()
{
// Entity全ての取得
$query = $this->Persons->find('all');
// 1つ目の結果を取得
$this->set('person', $query->first());
}
}
/src/Template/Persons/index.ctp:
<div>
<h3>List Persons</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>AGE</th>
<th>MAIL</th>
</tr>
</thead>
<tbody>
<tr>
<td><?=$person->id ?></td>
<td><?=h($person->name) ?></td>
<td><?=h($person->age) ?></td>
<td><?=h($person->mail) ?></td>
</tr>
</tbody>
</table>
</div>
実行結果 URL「/persons/index」:

このサンプルコードではfind(‘all’)で全てのデータを取得し、firstを使って1つ目のデータを取得し表示しています。
firstの他にも、lastを使用すると最後のデータを取得することができます。
また、countを使用するとレコード数を取得することができます。
conditionsで条件を設定する方法
findメソッドの第2引数の連想配列のキーに‘conditions’を指定することで条件を設定してデータを取得することができます。
それではサンプルコードで確認していきましょう。
/src/Controller/PersonsController.php:
<?php
namespace App\Controller;
use App\Controller\AppController;
class PersonsController extends AppController
{
public function index()
{
// フィールド’name’の値で「ro」が含まれるデータを取得
$this->set('persons', $this->Persons->find('all', ['conditions' => ['name like' => '%ro%']]));
}
}
/src/Template/Persons/index.ctp:
<div>
<h3>List Persons</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>AGE</th>
<th>MAIL</th>
</tr>
</thead>
<tbody>
<?php foreach ($persons as $person): ?>
<tr>
<td><?=$person->id ?></td>
<td><?=h($person->name) ?></td>
<td><?=h($person->age) ?></td>
<td><?=h($person->mail) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
実行結果 URL「/persons/index」:

このサンプルコードではデータベースのテーブル「persons」のフィールド’name’の値で「ro」が含まれるデータを取得し表示しています。
containで関連テーブルからリストを生成する方法(Joinの代替方法)
CakePHP2.xなどでは「JOIN」句を使って関連するテーブルを結合していましたが、CakePHP3.xでは関連テーブルからリストを生成するためにcontainを使用します。
containの記述方法:
find('all')->contain([‘テーブル名1’, ‘テーブル名2’, ・・・])
それではサンプルコードで確認していきましょう。
前述のテーブル「persons」にカラム「job_id」を追加します。
personsテーブル:
| id | name | age | job_id | |
|---|---|---|---|---|
| 1 | Taro | 40 | taro@gmail.com | 1 |
| 2 | Jiro | 30 | jiro@gmail.com | 2 |
| 3 | Saburo | 25 | saburo@gmail.com | 3 |
| 4 | Hanako | 35 | hanako@gmail.com | 4 |
関連するテーブルとして「jobs」を作成します。
SQLクエリ:
CREATE TABLE jobs (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name TEXT NOT NULL
);
jobsテーブル:
| id | name |
|---|---|
| 1 | teacher |
| 2 | policeman |
| 3 | doctor |
| 4 | nurse |
テーブル「jobs」を作成後、bakeでmodelを作成しています。
bakeの実行例(linux):
bin/cake bake model jobs
/src/Controller/PersonsController.php:
<?php
namespace App\Controller;
use App\Controller\AppController;
class PersonsController extends AppController
{
public function index()
{
// 関連テーブルのリスト取得
$this->set('persons', $this->Persons->find('all')->contain(['Jobs']));
}
}
/src/Template/Persons/index.ctp:
<div>
<h3>List Persons</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>AGE</th>
<th>MAIL</th>
<th>JOB</th>
</tr>
</thead>
<tbody>
<?php foreach ($persons as $person): ?>
<tr>
<td><?=$person->id ?></td>
<td><?=h($person->name) ?></td>
<td><?=h($person->age) ?></td>
<td><?=h($person->mail) ?></td>
<td><?=h($person->job->name) ?></td> // 関連テーブルのフィールド
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
またテーブル「src/Model/Table/PersonsTable.php」にbelongsToを使って関連するテーブルを指定する記述を行う必要があります。
src/Model/Table/PersonsTable.php:
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
class PersonsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('persons');
$this->displayField('name');
$this->primaryKey('id');
$this->belongsTo('Jobs'); // 関連するテーブルの指定
}
}
実行結果:

このサンプルコードではテーブル「persons」とテーブル「jobs」のフィールド「job」を結合して表示しています。
まとめ
ここでは、findの使い方について説明しました。
findはデータを検索して取得し使用する場合によく使われます。
使いこなすことができるように、この記事を何度も参考にして下さいね!






