Laravel の Eloquent リレーションはとても便利で、リレーションを定義すればモデルと紐づくデータが取得できたり、操作を行うことができます。
ただ操作で少し迷ったので備忘録としてまとめます。
user と post というモデルがあり、以下のような関係を定義します。
class User extends Authenticatable
{
/* 省略 */
public function posts()
{
return $this->hasMany(Post::class);
}
}
class Post extends Model
{
/* 省略 */
public function user()
{
return $this->belongsTo(User::class);
}
}
hasOne と belongsTo どっちを使えばいいんだっけ?
ここで毎回どちらが hasOne/hasMany か belongsTo/belongsToMany なのかを間違うのですが、分かりやすくどちらのテーブルにモデル名と同じ ID を含むかで判別することで覚えました。
users テーブルのカラムに対して post_id を含むように設計した場合、post_id だけが違う user の同じデータが並んでしまうことになります。認証に使われているデータが post_id だけを除いて同じになるのはおかしいので、posts テーブルに user_id というのがある方が自然です。
そうすると xxxx(テーブル名)_id とある方が has(所有)、ないほうが belongs(従属) という覚え方で解決しました。
モデルデータの取得方法
単純に user の一覧を取得したければ以下のように書けます。
$users = User::all();
特定のユーザ 1 人を取得したければ以下のようにします。
$id = 1;
$user = User::find($id);
次にユーザの投稿したデータを取得したい場合以下のようになります。
$users_posts = User::all()->with('posts');
// -> すべてのユーザにpostsを付け加えて取得
$id = 1;
$user_posts = User::find($id)->load('posts');
// -> idが1のユーザにpostsを付け加えて取得
$posts = User::all()->posts;
// -> ユーザのデータを含まずにpostsだけを取得
// $posts = Post::all(); と同じ
$post = User::find($id)->posts;
// -> idが1のユーザのデータを含まずにpostsだけを取得
// $post = Post::where('user_id', $id); と同じ
with/load を使って取得する場合とユーザのデータに posts という連想配列が含まれた状態でユーザのデータが返ってきます。
リレーションを使う場合は user
にネストした形ではなく、直接データが渡されます。
このときにposts()
のようにメソッド呼び出しを行うと、データではなくモデルとして取得されます。
データの追加
リレーションが定義されているモデルではクエリビルダによる操作が可能です。
ユーザが投稿を行うとき、ユーザの id を紐付けたい場合は以下のように書くことができます。
$user = Auth::user();
$post = $user->posts()->create($request->all());
リレーションであれば id
は自動的に付与されるので、$request
に対して上書き等の操作は不要です($request
がネストしている場合excerpt
で取り除く必要がある)。
更にログインしているユーザにのみできる操作であれば、$request
を参照してユーザを特定することができます。
$user = $request->user();
$post = $user->posts()->create($request->all());