Laravel - Eloquent 不要重复自己

Posted

技术标签:

【中文标题】Laravel - Eloquent 不要重复自己【英文标题】:Laravel - Eloquent do not repeat yourself 【发布时间】:2020-01-29 22:14:35 【问题描述】:

我有这样的代码:

$totalCount = User::sum('count_fortress');

$lastVisit = User::orderBy('last_visit_fortress', 'DESC')->first('last_visit_fortress');

$topFiveUsers = User::whereNotNull(['count_fortress', 'last_visit_fortress'])
    ->orderBy('count_fortress', 'DESC')
    ->orderBy('last_visit_fortress', 'DESC')
    ->get(['id', 'count_fortress', 'last_visit_fortress'])
    ->take(5);

return response()->json([
    "fortress" => [
        "total_count" => $totalCount,
        "last_visited" => $lastVisit->last_visit_fortress,
        "users" => $topFiveUsers
    ]
]);


$totalCount = User::sum('count_museum');

$lastVisit = User::orderBy('last_visit_museum', 'DESC')->first('last_visit_museum');

$topFiveUsers = User::whereNotNull(['count_museum', 'last_visit_museum'])
    ->orderBy('count_museum', 'DESC')
    ->orderBy('last_visit_museum', 'DESC')
    ->get(['id', 'count_museum', 'last_visit_museum'])
    ->take(5);

return response()->json([
    "museum" => [
        "total_count" => $totalCount,
        "last_visited" => $lastVisit->last_visit_museum,
        "users" => $topFiveUsers
    ]
]);

有没有一种可能的方法可以用一种方法或类似的方法将逻辑放在存储库或服务中而不是控制器中?

【问题讨论】:

接受作为额外的路线参数博物馆或堡垒,然后将参数连接到使用它们的每个实例的末尾 你能给我看看这个例子吗? 您应该查看本地查询范围以使您的查询可重用:laravel.com/docs/5.5/eloquent#local-scopes @LobsterBaz 你能给我解释一下吗? 【参考方案1】:

您可以在用户模型定义中使用范围来重用查询。

public function scopeTopFiveUsers(Builder $query, string $context) 
    ->whereNotNull(['count_' . $context, 'last_visit_' . $context])
    ->orderBy('count_' . $context, 'DESC')
    ->orderBy('last_visit_' . $context, 'DESC')
    ->select(['id', 'count_' . $context, 'last_visit_' . $context])

由于这两种解决方案之间存在关联,因此您可以巧妙地使用列名并使用 访问基于字符串的属性。该解决方案处于聪明的边缘,但这是一个具有不要重复自己的心态的解决方案。还使用了示波器解决方案。

private function calculateResponse(string $context) 
    $topFiveUsers = User::topFiveUsers($context)->take(5);
    $lastVisit = User::orderBy('last_visit_' . $context, 'DESC')->first('last_visit_' . $context)->'last_visit_' . $context;

    return [
        'total_count' => User::sum('count_' . $context),
        'last_visited' => $lastVisit,
        'users' => $topFiveUsers
    ]


public function controllerMethodOne() 
    return response()->json([
        "fortress" => [
            $this->calculateResponse('fortress');
        ]
    ]);


public function controllerMethodTwo() 
    return response()->json([
        "museum" => [
            $this->calculateResponse('museum');
        ]
    ]);

【讨论】:

【参考方案2】:

您可以按照之前的建议创建全局范围,但是如果这只是用作单个实例,那么我可能会选择这样的东西:

Route::get('user/type?', function ($name) 
    //point to your controller
)->where('type', 'museum|fortress');

然后在你的控制器中,当然命名你想要的..

function genericSharedFunction($type)

    $totalCount = User::sum('count_'.$type);

    $lastVisit = User::orderBy('last_visit_'.$type, 'DESC')->first('last_visit_'.$type);

    $topFiveUsers = User::whereNotNull(['count_'.$type, 'last_visit_'.$type])
        ->orderBy('count_'.$type, 'DESC')
        ->orderBy('last_visit_'.$type, 'DESC')
        ->get(['id', 'count_'.$type, 'last_visit_'.$type])
        ->take(5);

    $last_visit_prop = 'last_visit_'.$type;

    return response()->json([
        "$type" => [
            "total_count" => $totalCount,
            "last_visited" => $lastVisit->$last_visit_prop,
            "users" => $topFiveUsers
        ]
    ]);

【讨论】:

您忘记在whereNotNull 子句中将museum 替换为$type

以上是关于Laravel - Eloquent 不要重复自己的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4:如何使用 Eloquent ORM“排序”[重复]

Laravel Eloquent 有很多通过变化,删除重复

Laravel Eloquent - 返回 Where Has + Where [重复]

使用我自己的 Laravel API 时如何遵循不要重复自己的原则?

Laravel 5.1用eloquent删除DB中的重复项

将 Laravel 5 Eloquent 模型移动到它自己的目录中