【CakePHP入門】findでエンティティを検索し取得する方法

こんにちは!フリーランスの長野です。

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テーブル:

idnameagemail
1Taro40taro@gmail.com
2Jiro30jiro@gmail.com
3Saburo25saburo@gmail.com
4Hanako35hanako@gmail.com

テーブル「persons」を作成後、bakemodelを作成しています。

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」:
20170707ListPerson

この場合は、入力した全てのデータが表示されています。

なお、先ほどbakemodelを作成しました。

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」:
20170707ListPerson2

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」:
20170707ListPerson3

このサンプルコードでは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」:
20170707ListPerson4

このサンプルコードではデータベースのテーブル「persons」のフィールド’name’の値で「ro」が含まれるデータを取得し表示しています。

containで関連テーブルからリストを生成する方法(Joinの代替方法)

CakePHP2.xなどでは「JOIN」句を使って関連するテーブルを結合していましたが、CakePHP3.xでは関連テーブルからリストを生成するためにcontainを使用します。

containの記述方法:

find('all')->contain([‘テーブル名1’, ‘テーブル名2’, ・・・])

それではサンプルコードで確認していきましょう。

前述のテーブル「persons」にカラム「job_id」を追加します。

personsテーブル:

idnameagemailjob_id
1Taro40taro@gmail.com1
2Jiro30jiro@gmail.com2
3Saburo25saburo@gmail.com3
4Hanako35hanako@gmail.com4

関連するテーブルとして「jobs」を作成します。

SQLクエリ:

CREATE TABLE  jobs ( 
    id INTEGER PRIMARY KEY AUTO_INCREMENT, 
    name TEXT NOT NULL
);

jobsテーブル:

idname
1teacher
2policeman
3doctor
4nurse

テーブル「jobs」を作成後、bakemodelを作成しています。

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'); // 関連するテーブルの指定
    }
}

実行結果:
20170707ListPerson5

このサンプルコードではテーブル「persons」とテーブル「jobs」のフィールド「job」を結合して表示しています。

まとめ

ここでは、findの使い方について説明しました。

findデータを検索して取得し使用する場合によく使われます。

使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次