プロジェクトが複雑になればなるほど、データベースを用いたやりとりの難易度も上がっていきます。
複数のテーブルをリレーションさせる事はよくあります。
Laravelではリレーション周りの関数も色々用意されており、複雑なリレーションにも柔軟に対応できます。
さて、
今回はリレーションされた要素数を扱いたい場合の方法について記載します。
実装仕様
例えば、ブログサービスを作るとします。
仕様上、ブログの記事にはカテゴリが1つ付与されています。
今回実現したいことは、カテゴリ毎の登録データ数を取得したいです。
テーブル構成
次のようなテーブル構成だったとします。
- 記事(entries)
- 記事カテゴリ(entry_categories)
記事カテゴリと記事をリレーションさせて、リレーションからデータ件数を取得できるようにします。
また、記事によっては公開/非公開のものが分かれているので、公開中の件数だけ取得できるようにします。
モデルのリレーション設定
記事モデル
記事用のEntry
モデルを次のように設定します。
今回の要件では、リレーションの設定は不要ですので省略しても問題ありません。
<?php // Entry.php namespace App; use Illuminate\Database\Eloquent\Model; class Entry extends Model { /** * EntryCategoryのリレーション */ public function entryCategory() { return $this->hasOne(EntryCategory::class); } }
記事カテゴリモデル
カテゴリ用のEntryCategory
モデルを次のように設定します。
公開状況(ER図のpublished
)が有効なものだけ取得したいので、where
を追加します。
<?php // EntryCategory.php namespace App; use Illuminate\Database\Eloquent\Model; class EntryCategory extends Model { /** * Entryのリレーション */ public function entries() { return $this->hasMany(Entry::class); } /** * 公開中のブログのみ */ public function entriesIsPublised() { return $this->entries() ->where('published', 1); } }
リレーションされた要素数を取得する
Laravelが用意しているリレーションはwith
を使用する方法があります。
チェーンメソッドでリレーションされたデータベースに紐づくモデルを呼び出せます。
リレーションされた要素数だけ取得したい場合はwithCount
を使用します。
これを使用する事で、リレーション元のattributeに(リレーション名のスネークケース)_count
と言う要素が追加されます。
例えば、Controllerでカテゴリリレーションされた記事の件数を取得する場合は次のようになります。
<?php namespace App\Http\Controllers; use App\Entry; use App\EntryCategory; class EntryController extends Controller { public function index() { // withCountにリレーションの関数名を指定します $entryCategories = EntryCategory::withCount('entriesIsPublised') ->get(); foreach($entryCategories as $entryCategory) { // キャメルケースが、スネークケースに変換されますので、次のような呼び出し方になります。 dump($entry->entries_is_publised_count); } } }