この記事は下記の続きになります。
CakePHP4でブログサイト作るチュートリアル
誰が投稿したのかわかるように、するにはアソシエーションという機能を使ってモデル同士を関連付けする必要があります。
一人のユーザーが複数の投稿をしているので、一対多(hasMany)の関係になります。
データベース
データベースから編集しましょう。多であるPostsテーブルにuser_idカラムを追加します。
bakeでマイグレーションファイルを作成します。
$ bin/cake bake migration AddUserIdToPosts user_id:integer
生成したマイグレーションファイルを編集します。
config/Migrations/xxxxxxx_AddUserIdToPosts.php
public function change() { $table = $this->table('posts'); $table->addColumn('user_id', 'integer', [ 'default' => 1, 'limit' => 11, 'null' => false, ]); $table->update(); }
マイグレーションを実行します。
$ bin/cake migrations migrate
Model
モデルエンティティにuser_id
を追加。
src/Model/Entity/Post.php
class Post extends Entity { protected $_accessible = [ 'title' => true, 'description' => true, 'body' => true, 'published' => true, 'created' => true, 'modified' => true, 'user_id' => true, // 追加 ]; }
リレーションの設定はテーブルで行います。
一対多の場合は多の方が一に属しているということになるので、
多である投稿(Posts)にはbelongsTo
を指定します。
src/Model/Table/PostsTable.php
class PostsTable extends Table { public function initialize(array $config): void { //... $this->belongsTo('Users'); }
編集&追加機能
編集できるようにコントローラーとビューを編集します。
コントローラーのedit
とadd
アクションではユーザーを選択できるようにする必要があるので、リストで取得してビューに渡しましょう。
src/Controller/Admin/PostsController.php
class PostsController extends AdminController { public function initialize(): void { parent::initialize(); $this->loadModel('Users'); } public function edit($id = null) { // ... // ユーザーリストを取得 $users = $this->Users->find('list'); $this->set(compact('post', 'users')); } }
ビューでは特に考える必要がなく、他の入力と同じようにフォームコントロールでいけます。
ただセレクトボックスになります。
templates/Admin/Posts/edit.php or add.php
echo $this->Form->control('user_id');
詳細画面(view)
詳細画面はgetするときにcontain
に['Users']
を指定します。
src/Controller/Admin/PostsController.php
public function view($id = null) { $post = $this->Posts->get($id, [ 'contain' => ['Users'], ]); $this->set('post', $post); }
ビューではこんな感じで表示します。
templates/Admin/Posts/view.php
<?= h($post->user->username) ?>
一覧画面(index)
一覧はページネートを使ってると思いますが、その場合はpaginate
にcontain
を設定します。
src/Controller/Admin/PostsController.php
public function index() { $this->paginate = [ 'contain' => ['Users'] ]; $posts = $this->paginate($this->Posts); $this->set(compact('posts')); }
ユーザーからの関連付け
投稿からの表示をしたので、今度はユーザーから表示します。
Model
ユーザーモデルは複数の投稿を持つのでhasMany
を設定します。
src/Model/Table/UsersTable.php
class UsersTable extends Table { public function initialize(array $config): void { //... $this->hasMany('Posts'); } }
Controller
例えばユーザー詳細画面に記事一覧を表示させたい場合はコントローラーのViewアクションを下記のようにします。
src/Controller/Admin/UsersController.php
public function view($id = null) { $user = $this->Users->get($id, [ 'contain' => ['Posts'], ]); $this->set(compact('user')); }
View
あとはビューで$user->posts
を展開していけば表示できます。
ただ、一覧の場合はページネートを使用することが多いと思いますのであまりこのような使い方はしないかもしれません。
templates/Admin/Users/view.php
<table> <tbody> <?php foreach ($user->posts as $post): ?> <tr> <td><?= $this->Number->format($post->id) ?></td> <td><?= h($post->title) ?></td> <td><?= $post->published ? __('Yes') : __('No'); ?></td> <td><?= h($post->created) ?></td> </tr> <?php endforeach; ?> </tbody> </table>
ここまでのソースコードはこちら