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
以上内容应允许您需要预先加载的所有内容。
希望对您有所帮助!
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
以上内容应允许您需要预先加载的所有内容。
希望对您有所帮助!