【问题标题】:Laravel - Eloquent do not repeat yourselfLaravel - Eloquent 不要重复自己
【发布时间】: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 你能给我解释一下吗?

标签: php mysql laravel eloquent orm


【解决方案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
    猜你喜欢
    • 2013-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多