【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データを検索して取得し使用する場合によく使われます。

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

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次