CakePHP2を嗜んでいる人だとよく間違いやすい実装の1つが今回のお題。
CakePHP3でもつい
find(‘list’)とselect([‘id”, ‘name’])等でやれば [key => value] で返せるだろう
って思ってたら、primary keyであるidはkeyとして返してくれるが、valueはselect()の指定では返してくれない。というわけで、どう実装をすれば良かったかをメモがてら残しておく。検証したCakePHPのバージョンは3.6.13。
実装方法1: find(‘list’)時にkeyFieldとvalueFieldを指定する
一番基本的な記述は下記(L26~L32):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<?php namespace App\Controller; use App\Controller\AppController; use Cake\View\View; class ArticlesController extends AppController { public function initialize() { parent::initialize(); $this->loadModel('Articles'); $this->loadModel('ArticleTypes'); } /** * 一覧画面 */ public function index() { $this->paginate = [ 'contain' => ['Authors'], ]; $articles = $this->paginate($this->Articles); // 記事タイプのkey・valueを取得 $articleTypeList = $this->ArticleTypes ->find('list', [ 'keyField' => 'id', 'valueField' => 'name', ]) ->toArray(); $this->set(compact('articles', 'articleTypeList')); } } |
find(‘list’)の際にkeyFieldとvalueFieldを指定する方法。key・valueは好きなcolumnを指定することが可能だ。
実装方法2: 対象Tableのinitialize()にてsetDisplayField()をしておく
もう1つの方法がこちら:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?php namespace App\Model\Table; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; /** * ArticleTypes Model * * @method \App\Model\Entity\ArticleType get($primaryKey, $options = []) * @method \App\Model\Entity\ArticleType newEntity($data = null, array $options = []) * @method \App\Model\Entity\ArticleType[] newEntities(array $data, array $options = []) * @method \App\Model\Entity\ArticleType|bool save(\Cake\Datasource\EntityInterface $entity, $options = []) * @method \App\Model\Entity\ArticleType|bool saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = []) * @method \App\Model\Entity\ArticleType patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) * @method \App\Model\Entity\ArticleType[] patchEntities($entities, array $data, array $options = []) * @method \App\Model\Entity\ArticleType findOrCreate($search, callable $callback = null, $options = []) * * @mixin \Cake\ORM\Behavior\TimestampBehavior */ class ArticleTypesTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->setTable('article_types'); $this->setPrimaryKey('id'); $this->setDisplayField('name'); // bakeすると、デフォルトはidになることが多いので注意 } } |
上記のように、initialize()内でsetDisplayField()というメソッドを活用することで、予めfind(‘list’)で取得してくる際のデフォルトvalueを決め打っておく方法だ。[key => value]で返すcolumnがほぼ決まっている場合に効果的。
上記のようにsetしておくと、Controller側では下記の記述で事足りるようになる:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php namespace App\Controller; use App\Controller\AppController; use Cake\View\View; class ArticlesController extends AppController { public function initialize() { parent::initialize(); $this->loadModel('Articles'); $this->loadModel('ArticleTypes'); } /** * 一覧画面 */ public function index() { $this->paginate = [ 'contain' => ['Authors'], ]; $articles = $this->paginate($this->Articles); // 記事タイプのkey・valueを取得 $articleTypeList = $this->ArticleTypes ->find('list') ->toArray(); $this->set(compact('articles', 'articleTypeList')); } } |
非常にスッキリ。
参考)
https://book.cakephp.org/3/ja/orm/retrieving-data-and-resultsets.html#table-find-list