Laravel 5.4 : 除了view、model和repository,我还能在哪里做逻辑?

Laravel 5.4 : apart from the view, the model and the repository, where can I do the logic?

TLDR:在 Laravel 5.4 中,如果我不想从模型向数据库发出 50k 请求并希望在视图中限制逻辑,我可以在哪里执行逻辑?

基本上,我的表格是这样的:

 -----  
|users|  
|-id  |  
 -----  
 -------------
|subscriptions|
|-id          |
|-user_id     |
 -------------
 ----------------
|participations  |
|-subscription_id|
|-activity_id    |
 ----------------
 ---------
|activities|
|-id       |
 ---------

现在的问题是,我有一个看起来像周历的视图,我们可以在其中向用户显示他们有权访问的所有活动,并根据日期指示他们是否参与。

@foreach(datesOfCurrentWeek() as $date)
    <div class="title">
        <i class="dropdown icon"></i>
        {{$date->format("l Y-m-d")}}
    </div>

    <div class="content">
        @foreach($users as $user)
            <div class="accordion">
                <div class="title">
                    <i class="dropdown icon"></i>
                    {{ $user->name }} 
                </div>
                <div class="content">
                    @foreach($user->activitiesAt($date) as $activity)
                        @include('calendar.partials.card', ['activity' => $activity, 'participation' => $activity->participation($user)])
                    @endforeach
                </div>
            </div>
        @endforeach
    </div>
@endforeach

$user->activitiesAt($date) as $activity:我需要用户在给定日期内有权访问的活动。
在模型中:

return Activities::where(['group_id' => $this->group->id, 'date_start_at' => $date->format('Y-m-d')])->get();

然后$activity->participation($user)其中return用户的参与activity。
在模型中:

return $this->participations()->where(['subscription_id' => $user->activeSubscription()->id])->first();

以及用户模型的活跃订阅

public function activeSubscription()
{
    // todo: get the active one
    return $this->subscriptions()->first();
}

calendar.partial.date(此时没有什么特别的)

<div class="ui padded raised segment">

    <p>{{ $activity->start_at->format('H:i') }} - {{ $activity->end_at->format('H:i') }} </p>
    <p>{{ $activity->title }} </p>

    @if($participation)
        <button class="circular ui icon basic green button">
            <i class="check green icon"></i>
        </button>
    @else
        <button class="circular ui icon basic blue button">
            <i class="add blue icon"></i>
        </button>
    @endif

</div>

视图的最终结果是这样的:

> Monday 2017.07.03
  > user1
     - activity1 (participate)
     - activity3 (participate)
  > user2
     - activity1 (participate)
     - activity3
  > user3
     - activity2
     - activity4
> Tuesday 2017.07.04
   > user1
     - activity10 
     - activity30 (participate)
  > user2
     - activity10 
     - activity30
  > user3
     - activity20 (participate)
     - activity40
...

但由于查询有一个 "dynamic" where 子句,我无法使用预加载进行预加载,并且请求会很快变得过于臃肿。 (4 个用户,每个用户 3 个活动,我已经有 100 多个查询)

我认为最优化的方法是使用预加载加载所有内容,然后将逻辑处理到视图中,但这是我试图避免的。那么,知道如何在保持清晰视图的同时执行逻辑吗?

除此之外:我正在使用存储库,我觉得在存储库之外添加 where 子句是错误的。

谢谢!

您将能够使用预先加载,并且您必须对代码进行如此多的更改。

我将对您的代码做出一些假设,例如模型名称和关系类型,但您应该了解要点。我也明白以下内容不会考虑您正在使用存储库这一事实,但您应该能够轻松地重构它们以适应。

首先,在您的 User 模型中(除非您已经这样做)添加以下方法:

/**
 * Activities Relationship
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function activities()
{
    return $this->hasMany(Activities::class, 'group_id', 'group_id');
}

/**
 * Active Subscription Relationship
 *
 * @return mixed
 */
public function activeSubscription()
{
    return $this->hasOne(Subscription::class)
        ->where('active', true); // <-- You would replace this will the actual logic to get the active subscription
}

/**
 * Helper method to get the users activities for the supplied date
 *
 * @param $date
 * @return mixed
 */
public function activitiesForDate($date)
{
    return $this->activities->toBase()
        ->filter(function ($activity) use($date) {
            return $activity->date_start_at->isSameDay($date);
        });
}

然后在您的 Activities 模型中:

/**
 * Get the activities that start between the supplied dates
 *
 * @param $query
 * @param $start
 * @param $end
 */
public function scopeStartsBetween($query, $start, $end)
{
    $query->whereBetween('date_start_at', [$start->format('Y-m-d'), $end->format('Y-m-d')]);
}

/**
 * Helper function to check if the supplied User is a participant
 *
 * @param $user
 * @return bool
 */
public function hasParticipant($user)
{
    return ! $this->participations->toBase()
        ->filter(function ($participation) use($user) {
            return $user->activeSubscription->id == $participation->subscription_id;
        })
        ->isEmpty();
}

您的查询将类似于:

$dates = collect(datesOfCurrentWeek());

$users = User::with(['activeSubscription', 'activities' => function ($query) use($dates) {
    $query->with('participations')->startsBetween($dates->first(), $dates->last());
}])->get();

最后,您的 blade 文件将如下所示:

@foreach(datesOfCurrentWeek() as $date)
    <div class="title">
        <i class="dropdown icon"></i>
        {{ $date->format("l Y-m-d") }}
    </div>

    <div class="content">
        @foreach($users as $user)
            <div class="accordion">
                <div class="title">
                    <i class="dropdown icon"></i>
                    {{ $user->name }}
                </div>
                <div class="content">
                    @foreach($user->activitiesForDate($date) as $activity)
                        @include('calendar.partials.card', ['activity' => $activity, 'participation' => $activity->hasParticipant($user)])
                    @endforeach
                </div>
            </div>
        @endforeach
    </div>
@endforeach

以上内容应允许您需要预先加载的所有内容。

希望对您有所帮助!