今回は、タグ選択機能を改善していきます。コンマ区切りで、記事投稿や編集時にもタグを追加、削除できるようにします。
Model Entity Article.php を編集
まずは下記で、Collection クラスをインポートします。「namespace App\Model\Entity;」の下に追加します。
use Cake\Collection\Collection;
次に、下記をprotected $_accessibleの下に追加します。
protected function _getTagString() { if (isset($this->_properties['tag_string'])) { return $this->_properties['tag_string']; } if (empty($this->tags)) { return ''; } $tags = new Collection($this->tags); $str = $tags->reduce(function ($string, $tag) { return $string . $tag->title . ', '; }, ''); return trim($str, ', '); }
ここまでで、Article.phpの編集は完了です。
Model Table ArticlesTable.php を編集
続いて、ArticlesTable.phpに下記を追加します。
public function beforeSave($event, $entity, $options) { if ($entity->tag_string) { $entity->tags = $this->_buildTags($entity->tag_string); } } protected function _buildTags($tagString) { $newTags = array_map('trim', explode(',', $tagString)); $newTags = array_filter($newTags); $newTags = array_unique($newTags); $out = []; $query = $this->Tags->find() ->where(['Tags.title IN' => $newTags]); foreach ($query->extract('title') as $existing) { $index = array_search($existing, $newTags); if ($index !== false) { unset($newTags[$index]); } } foreach ($query as $tag) { $out[] = $tag; } foreach ($newTags as $tag) { $out[] = $this->Tags->newEntity(['title' => $tag]); } return $out; }
ここまでで、ArticlesTable.phpの編集が完了です。
Template Articles add.ctp edit.ctp を編集
add.ctpとedit.ctpにあるフォーム内の下記の箇所を置き換えます。
// これを echo $this->Form->control('tags._ids', ['options' => $tags]); // これに置き換え echo $this->Form->control('tag_string', ['type' => 'text']);
ここまでで、ctp関連の編集が完了です。
Controller ArticlesController.php を編集
最後にArticlesController.phpを編集して作業完了です。
編集する箇所は、「Add method」と 「Edit method」内です。下記のように編集します。
Add method
public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { $query = $this->request->getData(); $query['user_id'] = $this->Auth->user('id'); $sluggedTitle = Text::slug($this->request->getData('title')); $query['slug'] = substr($sluggedTitle, 0, 191); // ここから追加 $article->tag_string = $this->request->getData('tag_string'); // ここまで追加 $article = $this->Articles->patchEntity($article, $query); if ($this->Articles->save($article)) { $this->Flash->success(__('The article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('The article could not be saved. Please, try again.')); } $users = $this->Articles->Users->find('list', ['limit' => 200]); $tags = $this->Articles->Tags->find('list', ['limit' => 200]); $this->set(compact('article', 'users', 'tags')); }
Edit method
public function edit($slug = null) { $article = $this->Articles->findBySlug($slug)->contain('Tags')->firstOrFail(); if ($this->request->is(['patch', 'post', 'put'])) { $query = $this->request->getData(); $sluggedTitle = Text::slug($this->request->getData('title')); $query['slug'] = substr($sluggedTitle, 0, 191); // ここから追加 $article->tag_string = $this->request->getData('tag_string'); // ここまで追加 $article = $this->Articles->patchEntity($article, $query); if ($this->Articles->save($article)) { $this->Flash->success(__('The article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('The article could not be saved. Please, try again.')); } $users = $this->Articles->Users->find('list', ['limit' => 200]); $tags = $this->Articles->Tags->find('list', ['limit' => 200]); $this->set(compact('article', 'users', 'tags')); }
これで、クイックスタートガイドのコンテンツ管理チュートリアルを元にしたWebアプリが全て動作するようになりました。
MAMP環境で、確認をしながら作業してきましたが、CakePHP3のbake機能はかなり便利だと改めて思いました。
そして何より動かせるというこうとがプログラム初心者には一番嬉しい・楽しいですよね。クイックスタートガイドもわかりやすいので、これからCakePHP3を始める方、プログラムに興味がある方にオススメです。