この記事は下記の続きになります。
CakePHP4でブログサイト作るチュートリアル
誰が投稿したのかわかるように、するにはアソシエーションという機能を使ってモデル同士を関連付けする必要があります。
一人のユーザーが複数の投稿をしているので、一対多(hasMany)の関係になります。

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