将查询构建的一部分重构为 Eloquent 模型,并使其可与其他构建器链接

发布于 2025-01-11 02:15:04 字数 3432 浏览 1 评论 0原文

我想重构以下代码中的 withCount 部分以重用它并使控制器更短。

class GroupController extends Controller
{
    public function show(int $group = 1)
    {
        return Group::where('id', '>', 0)  // to simulate starting the query with some builder
            ->withCount([
                "requests",
                'requests AS requests_count_pending' => function ($query) {
                    $query->where('state', 'pending');
                },
                'requests AS requests_count_accepted' => function ($query) {
                    $query->where('state', 'accepted');
                },
                'requests AS requests_count_refused' => function ($query) {
                    $query->where('state', 'refused');
                }
            ])
            ->find($group);
    }
}

我想使用以下语法构建查询:

$group = Group::where('id', '>', 0)
    ::withCountRequests()
    ->find($group);


我尝试过的内容(补丁)

public static function withRequestsCount()
{
    return self::withCount([
        "requests",
        'requests AS requests_count_pending' => function ($query) {
            $query->where('state', 'pending');
        },
        'requests AS requests_count_accepted' => function ($query) {
            $query->where('state', 'accepted');
        },
        'requests AS requests_count_refused' => function ($query) {
            $query->where('state', 'refused');
        }
    ]);
}
public function show(int $group = 1)
{
    return Group::withRequestsCount()
        ->where('id', '>', 0)
        ->find($group);
}

该解决方案仅在我首先调用静态方法时才有效。但我想像任何其他 Builder



复制

php .\artisan make:model -mcrf Group
php .\artisan make:model -mcrf Request

迁移

public function up(): void
{
    Schema::create('groups', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
    });
}
public function up(): void
{
    Schema::create('requests', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
        $table->set('state', ['pending', 'accepted', 'refused']);
        $table->foreignId('group_id');
    });
}

模型

class Group extends Model
{
    use HasFactory;

    public function requests()
    {
        return $this->hasMany(Request::class);
    }
}

工厂和播种器

class RequestFactory extends Factory
{
    public function definition(): array
    {
        return [
            'group_id' => 1,
            'state' => $this->faker->randomElement(['pending', 'accepted', 'refused']),
        ];
    }
}
class DatabaseSeeder extends Seeder
{
    public function run()
    {
        DB::table('groups')->insertOrIgnore(['id' => 1]);

        Request::factory(50)->create();
    }
}

路线一样流畅地链接它

Route::get('the_group', [GroupController::class, 'show']);

I want to refactor the withCount part from the following code to reuse it and make the controller shorter.

class GroupController extends Controller
{
    public function show(int $group = 1)
    {
        return Group::where('id', '>', 0)  // to simulate starting the query with some builder
            ->withCount([
                "requests",
                'requests AS requests_count_pending' => function ($query) {
                    $query->where('state', 'pending');
                },
                'requests AS requests_count_accepted' => function ($query) {
                    $query->where('state', 'accepted');
                },
                'requests AS requests_count_refused' => function ($query) {
                    $query->where('state', 'refused');
                }
            ])
            ->find($group);
    }
}

I want to build the query with the following syntax:

$group = Group::where('id', '>', 0)
    ::withCountRequests()
    ->find($group);


What I tried (Patch)

public static function withRequestsCount()
{
    return self::withCount([
        "requests",
        'requests AS requests_count_pending' => function ($query) {
            $query->where('state', 'pending');
        },
        'requests AS requests_count_accepted' => function ($query) {
            $query->where('state', 'accepted');
        },
        'requests AS requests_count_refused' => function ($query) {
            $query->where('state', 'refused');
        }
    ]);
}
public function show(int $group = 1)
{
    return Group::withRequestsCount()
        ->where('id', '>', 0)
        ->find($group);
}

The solution works only when I call the static method first. But I want to chain it fluently like any other Builder



Reproducing

php .\artisan make:model -mcrf Group
php .\artisan make:model -mcrf Request

Migrations

public function up(): void
{
    Schema::create('groups', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
    });
}
public function up(): void
{
    Schema::create('requests', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
        $table->set('state', ['pending', 'accepted', 'refused']);
        $table->foreignId('group_id');
    });
}

Models

class Group extends Model
{
    use HasFactory;

    public function requests()
    {
        return $this->hasMany(Request::class);
    }
}

Factory and seeder

class RequestFactory extends Factory
{
    public function definition(): array
    {
        return [
            'group_id' => 1,
            'state' => $this->faker->randomElement(['pending', 'accepted', 'refused']),
        ];
    }
}
class DatabaseSeeder extends Seeder
{
    public function run()
    {
        DB::table('groups')->insertOrIgnore(['id' => 1]);

        Request::factory(50)->create();
    }
}

Route

Route::get('the_group', [GroupController::class, 'show']);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久而酒知 2025-01-18 02:15:04

使用查询范围。它与您在 withRequestCount 函数中尝试的类似。

public static function scopeWithRequestsCount($query)
{
    return $query->withCount([
        "requests",
        'requests AS requests_count_pending' => function ($query) {
            $query->where('state', 'pending');
        },
        'requests AS requests_count_accepted' => function ($query) {
            $query->where('state', 'accepted');
        },
        'requests AS requests_count_refused' => function ($query) {
            $query->where('state', 'refused');
        }
    ]);
}

https://laravel.com/docs/eloquent#local-scopes

Use a query scope. It's similar to what you tried with the withRequestCount function.

public static function scopeWithRequestsCount($query)
{
    return $query->withCount([
        "requests",
        'requests AS requests_count_pending' => function ($query) {
            $query->where('state', 'pending');
        },
        'requests AS requests_count_accepted' => function ($query) {
            $query->where('state', 'accepted');
        },
        'requests AS requests_count_refused' => function ($query) {
            $query->where('state', 'refused');
        }
    ]);
}

https://laravel.com/docs/eloquent#local-scopes

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文