m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

cakephp3でモデル(find+xxxx)任意のfindメソッドを準備する

モデルでデータを取得する場合はfindメソッドを使用することが多いと思う

<?php
namespace App\Shell;

use Cake\Console\Shell;
use Cake\ORM\TableRegistry;

/**
 * Sample1 shell command.
 */
class Sample1Shell extends Shell
{

    /**
     * main() method.
     *
     * @return bool|int Success or error code.
     */
    public function main() {

        // table
        $bookmarks = TableRegistry::get('bookmarks');

        // find
        $query = $bookmarks
            ->find()
            ->contain(['users']);

        // SQ
        print_r($query->sql());
        print_r("\n");

    }
}

※findメソッドにいろいろな条件を付与して様々な結果を取得するけど

ある程度まとめたい

毎回findに条件を付与するより、可変パラメータだけを渡したいな〜

find+任意の名前でメソッドを作成

サンプル

<?php
namespace App\Model\Table;

use App\Model\Entity\Bookmark;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

/**
 * Bookmarks Model
 */
class BookmarksTable extends Table
{

    /**
     * Initialize method
     *
     * @param array $config The configuration for the Table.
     * @return void
     */
    public function initialize(array $config)
    {
        $this->table('bookmarks');
        $this->displayField('title');
        $this->primaryKey('id');
        $this->addBehavior('Timestamp');
        $this->belongsTo('Users', [
            'foreignKey' => 'user_id'
        ]);
        $this->belongsToMany('Tags', [
            'foreignKey' => 'bookmark_id',
            'targetForeignKey' => 'tag_id',
            'joinTable' => 'bookmarks_tags'
        ]);
    }

    /**
     * Default validation rules.
     *
     * @param \Cake\Validation\Validator $validator Validator instance.
     * @return \Cake\Validation\Validator
     */
    public function validationDefault(Validator $validator)
    {
        $validator
            ->add('id', 'valid', ['rule' => 'numeric'])
            ->allowEmpty('id', 'create')
            ->add('user_id', 'valid', ['rule' => 'numeric'])
            ->requirePresence('user_id', 'create')
            ->notEmpty('user_id')
            ->allowEmpty('title')
            ->allowEmpty('description')
            ->allowEmpty('url');

        return $validator;
    }

    /**
     * Returns a rules checker object that will be used for validating
     * application integrity.
     *
     * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
     * @return \Cake\ORM\RulesChecker
     */
    public function buildRules(RulesChecker $rules)
    {
        $rules->add($rules->existsIn(['user_id'], 'Users'));
        return $rules;
    }


    // これです
    public function findTagged(Query $query, array $options){
        return 
            $this
                ->find()
                ->matching('Tags', function ($q) use ($options) {
                    return $q->where(['Tags.title IN' => $options['tags']]);
                });
    }
}

※Tableのクラスに追加

それで、Tableのクラスを使用するところでfind以降のメソッド名を指定

<?php
namespace App\Shell;

use Cake\Console\Shell;
use Cake\ORM\TableRegistry;

/**
 * Sample2 shell command.
 */
class Sample2Shell extends Shell
{

    /**
     * main() method.
     *
     * @return bool|int Success or error code.
     */
    public function main() {

        // table
        $bookmarks = TableRegistry::get('bookmarks');

        // find
        $query =  $bookmarks->find('tagged', [
            'tags' => ['111', '222']
        ]);

        // SQ
        print_r($query->sql());
        print_r("\n");

    }
}

※第1引数のパラメータで"find"以降のメソッド名を指定する
こうすることで取得できる
戻り値はまあ好きに対応することが可能と思います

結果

SELECT 
  bookmarks.id AS `bookmarks__id`
  , bookmarks.user_id AS `bookmarks__user_id`
  , bookmarks.title AS `bookmarks__title`
  , bookmarks.description AS `bookmarks__description`
  , bookmarks.url AS `bookmarks__url`
  , bookmarks.created AS `bookmarks__created`
  , bookmarks.updated AS `bookmarks__updated`
  , Tags.id AS `Tags__id`
  , Tags.title AS `Tags__title`
  , Tags.created AS `Tags__created`
  , Tags.updated AS `Tags__updated`
  , BookmarksTags.bookmark_id AS `BookmarksTags__bookmark_id`
  , BookmarksTags.tag_id AS `BookmarksTags__tag_id` 

FROM 
  bookmarks bookmarks 
  INNER JOIN tags Tags ON 
    Tags.title in (:c0,:c1) 
    
  INNER JOIN bookmarks_tags BookmarksTags ON 
      (
        bookmarks.id = (BookmarksTags.bookmark_id) 
        AND Tags.id = (BookmarksTags.tag_id)
      )

所感

チュートリアルをやっていきながら不明な場所を解決して理解を進めていくようにします