もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

LaravelでhasManyなテーブルから1件以上の登録があるものだけ取得する

はじめに

こんばんは。

ちょうあっさりした、かつ、基本的なものですが、備忘録のために残しときます。

タイトルの通り、 hasMany関係のテーブルから1件以上のデータが登録あるものだけ取得する方法です。

さらに、そのテーブルのデータは 登録日降順で取得するものとします。

やってみた

以下みたいなテーブルがあるとします。

CREATE TABLE `categories` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PrimaryKey',
  `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'カテゴリ名',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登録日',
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'カテゴリ管理テーブル';

CREATE TABLE `items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PrimaryKey',
  `category_id` int(11) unsigned NOT NULL COMMENT 'カテゴリID',
  `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'アイテム名',
  `price` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '価格',
  `delivery_cost` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '配送料',
  `stock` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '在庫',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登録日',
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日',
  PRIMARY KEY (`id`),
  KEY `userId` (`name`),
  CONSTRAINT `items_fk_1` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'アイテム管理テーブル';

Eloquentは以下みたいな感じ?

<?php

class EloquentCategory extends Model
{
    protected $table = 'categories';
    

    /**
     * @return HasMany
     */
    public function items(): HasMany
    {
        return $this->hasMany(EloquentItem::class);
    }
}

class EloquentItem extends Model
{
    protected $table = 'items'; 
    
    /**
     * @return BelongsTo
     */
    public function area(): BelongsTo
    {
        return $this->belongsTo(EloquentCategory::class);
    }
}

Itemが1件以上登録があるCategoryを取得する方法は以下

<?php

    /**
     * @return array
     */
    public function findCategories(): array
    {
        return EloquentCategory::query()
            ->with(['items' => function (HasMany $query): void {
                $query->orderBy('created_at', 'DESC');
            }])
            ->orderBy('id', 'asc')
            ->get()->filter(function ($item) {
                return ($item->items->count() >= 1);
            })->toArray();
    }

これで、アイテムが1件以上登録のあるカテゴリのcollectionが取得できます。

withの小技と、collectionのfilterを組み合わせただけなんですが、こういうところって知ってないと使えないですよね。

調べるまでは泥臭く foreach で再現やる感じかな?と想像してました。

終わりに

今日はとりあえずこんな感じです。

12月チャレンジのために来週からは仕込み期間です。

がんばります。