Laravel Blade Table 创建嵌套的 Foreach 循环
Laravel Blade Table Creation Nested Foreach Loops
首先,我是编码新手,一般来说 Laravel,所以请放轻松。
我需要显示一个基于两个模型的 table:资源和事件。我在它们之间创建了一对多的关系。不幸的是,对于这个 table,我有特殊的需求,这种关系根本无法帮助。事件模型跟踪(除其他事项外)每个资源的签出和签入时间。 (一个资源可以有很多事件)基本上,如果资源的 ID 列在事件行中,那么有人已经检查了一段时间。我需要显示资源是否可供检出或已经检出 date/time 网站用户正在查看。
模型(显示关系)
Resource.php
class Resource extends Model
{
/**
* Define Relationships to other models.
*
*/
// The Event Model
public function events()
{
return $this->hasMany('App\Event');
}
}
Event.php
class Event extends Model
{
/**
* Define Relationships to other models.
*
*/
// To the User Model
public function user()
{
return $this->belongsTo('App\User');
}
// To the Resource Model
public function resource()
{
return $this->belongsTo('App\Resource');
}
}
在控制器中,我提取所有适用于日期的事件,如下所示:
$formStartOfDay = Carbon::parse($formDate)->startOfDay();
$formEndOfDay = Carbon::parse($formDate)->endOfDay();
$caseOne = Event::whereDate('outTime', '>=', $formStartOfDay)
->whereDate('inTime', '<=', $formEndOfDay);
$caseTwo = Event::whereDate('outTime', '=', $formStartOfDay)
->whereDate('inTime', '>', $formEndOfDay);
$caseThree = Event::whereDate('outTime', '<', $formStartOfDay)
->whereDate('inTime', '=', $formEndOfDay);
$caseFour = Event::whereDate('outTime', '<', $formStartOfDay)
->whereDate('inTime', '>', $formEndOfDay);
$events = $caseOne->union($caseTwo)
->union($caseThree)
->union($caseFour)
->orderBy('outTime')
->get();
同时拉取我需要的所有资源:
$resources = Resource::whereIn('type', ['SUV', 'Truck', 'Car'])->get()->sortby('name');
将其传递给视图后,我尝试创建我想要的 table。 table 列出了所有资源,无论是否已检出。那些已用完的资源将显示为“已签出”并列出谁拥有该资源。一个资源一天可能被检出不止一次,如果检出则需要显示所有实例。
<thead class="bg-primary text-white">
<tr class="text-center">
<th scope="col">Vehicle</th>
<th scope="col">Description</th>
<th scope="col">Status</th>
<th scope="col">Checked Out To</th>
</tr>
</thead>
<tbody>
@foreach ($resources as $resource)
@foreach ($events as $resource_event)
@if ($resource_event['resource_id'] == $resource->id)
<tr class="table-default" id="{{ $resource->id }}">
@if ($loop->first)
<td rowspan="{{ count($events->where('resource_id', $resource->id)) }}">
{{ $resource->name }}
</td>
<td>{{ $resource->description }}</td>
@endif
@if ($resource_event->inOrOut($resource_event->outTime,
$resource_event->inTime) === "Out" )
<td class="text-center">Checked Out</td>
<td class="text-center">{{ $resource_event->user->name }}</td>
@else
<td class="text-center">Available</td>
<td> </td>
@endif
</tr>
@else
<tr class="table-default" id="{{ $resource->id }}">
<td>{{ $resource->name }}</td>
<td>{{ $resource->description }}</td>
<td class="text-center">Available</td>
<td> </td>
</tr>
@endif
@endforeach
@endforeach
</tbody>
</table>
使用上面的 blade 代码,我得到了每个资源的多个实例(每个 $event 一个),并且 rowspan 在它应该工作的时候只是吓坏了。我尝试了各种方法,其中 none 给了我想要的东西。我在 Google 上的 Laracasts 上搜索过,没有任何情况与我的情况完全相同或帮助我解决了问题。希望这里有人能帮助我。
我对 ROWSPAN 的意图是使 table(正常工作时)看起来像这样:
========================================================
| Vehicle | Description | Status | Checked Out To |
|------------------------------------------------------|
| Truck 1 | 4x4 Truck | Available | |
|------------------------------------------------------|
| Truck 2 | 4x4 Truck | Checked Out | Person 1 |
| | |------------------------------|
| | | Checked Out | Person 2 |
|------------------------------------------------------|
| Truck 3 | 2WD Truck | Available | |
========================================================
解决方案
虽然可能有更好的方法,但我想出的解决方案是:
首先,使用带约束的预加载从控制器中的数据库中获取我需要的组合数据。
// Establish the earliest and latest times of the form's date
$formStartOfDay = Carbon::parse($formDate)->startOfDay();
$formEndOfDay = Carbon::parse($formDate)->endOfDay();
// Gather needed data from the database.
// Get the data via Eager Loading
$resources = Resource::whereIn('type', ['SUV', 'Truck', 'Car'])->orderBy('name')
->with(['events' => function ($query) use ($formStartOfDay, $formEndOfDay) {
$query->whereDate('outTime', '>=', $formStartOfDay)->whereDate('inTime', '<=', $formEndOfDay)
->orWhereDate('outTime', '=', $formStartOfDay)->whereDate('inTime', '>', $formEndOfDay)
->orWhereDate('outTime', '<', $formStartOfDay)->whereDate('inTime', '=', $formEndOfDay)
->orWhereDate('outTime', '<', $formStartOfDay)->whereDate('inTime', '>', $formEndOfDay)
->orderBy('outTime');
}])->get();
接下来我修改了 Blade 模板以使用新集合:
<table class="table table-bordered table-sm">
<thead class="bg-primary text-white">
<tr class="text-center">
<th scope="col">Vehicle</th>
<th scope="col">Description</th>
<th scope="col">Status</th>
<th scope="col">Checked Out To</th>
<th scope="col" style="width: 9%">Returning</th>
</tr>
</thead>
<tbody>
@foreach ($resources as $resource)
@if ($resource->events->contains('resource_id', $resource->id))
@foreach ($resource->events as $resource_event)
<tr class="table-default" id="{{ $resource->id }}">
<td>{{ $resource->name }}</td>
<td>{{ $resource->description }}</td>
@if ($resource_event->inOrOut($resource_event->outTime, $resource_event->inTime) === "Out" )
<td class="text-center">Checked Out</td>
<td class="text-center">
{{ $resource_event->user->name }}<br />
</td>
<td class="text-center">
{{ \Carbon\Carbon::parse($resource_event->inTime)->format('m/d/Y g:i A') }}
</td>
@else
<td class="text-center">Available</td>
<td> </td>
<td> </td>
@endif
</tr>
@endforeach
@else
<tr class="table-default" id="{{ $resource->id }}">
<td>{{ $resource->name }}</td>
<td>{{ $resource->description }}</td>
<td class="text-center">Available</td>
<td> </td>
<td> </td>
</tr>
@endif
@endforeach
</tbody>
</table>
解决方案的关键是使用适当的约束进行预加载。这样我就收到了所有的“资源”,但只收到了我需要的“事件”。这使我能够极大地简化 Blade 代码并使我远离非常复杂的循环和 if-else 块。
我希望这对以后的其他人有所帮助。
首先,我是编码新手,一般来说 Laravel,所以请放轻松。
我需要显示一个基于两个模型的 table:资源和事件。我在它们之间创建了一对多的关系。不幸的是,对于这个 table,我有特殊的需求,这种关系根本无法帮助。事件模型跟踪(除其他事项外)每个资源的签出和签入时间。 (一个资源可以有很多事件)基本上,如果资源的 ID 列在事件行中,那么有人已经检查了一段时间。我需要显示资源是否可供检出或已经检出 date/time 网站用户正在查看。
模型(显示关系)
Resource.php
class Resource extends Model
{
/**
* Define Relationships to other models.
*
*/
// The Event Model
public function events()
{
return $this->hasMany('App\Event');
}
}
Event.php
class Event extends Model
{
/**
* Define Relationships to other models.
*
*/
// To the User Model
public function user()
{
return $this->belongsTo('App\User');
}
// To the Resource Model
public function resource()
{
return $this->belongsTo('App\Resource');
}
}
在控制器中,我提取所有适用于日期的事件,如下所示:
$formStartOfDay = Carbon::parse($formDate)->startOfDay();
$formEndOfDay = Carbon::parse($formDate)->endOfDay();
$caseOne = Event::whereDate('outTime', '>=', $formStartOfDay)
->whereDate('inTime', '<=', $formEndOfDay);
$caseTwo = Event::whereDate('outTime', '=', $formStartOfDay)
->whereDate('inTime', '>', $formEndOfDay);
$caseThree = Event::whereDate('outTime', '<', $formStartOfDay)
->whereDate('inTime', '=', $formEndOfDay);
$caseFour = Event::whereDate('outTime', '<', $formStartOfDay)
->whereDate('inTime', '>', $formEndOfDay);
$events = $caseOne->union($caseTwo)
->union($caseThree)
->union($caseFour)
->orderBy('outTime')
->get();
同时拉取我需要的所有资源:
$resources = Resource::whereIn('type', ['SUV', 'Truck', 'Car'])->get()->sortby('name');
将其传递给视图后,我尝试创建我想要的 table。 table 列出了所有资源,无论是否已检出。那些已用完的资源将显示为“已签出”并列出谁拥有该资源。一个资源一天可能被检出不止一次,如果检出则需要显示所有实例。
<thead class="bg-primary text-white">
<tr class="text-center">
<th scope="col">Vehicle</th>
<th scope="col">Description</th>
<th scope="col">Status</th>
<th scope="col">Checked Out To</th>
</tr>
</thead>
<tbody>
@foreach ($resources as $resource)
@foreach ($events as $resource_event)
@if ($resource_event['resource_id'] == $resource->id)
<tr class="table-default" id="{{ $resource->id }}">
@if ($loop->first)
<td rowspan="{{ count($events->where('resource_id', $resource->id)) }}">
{{ $resource->name }}
</td>
<td>{{ $resource->description }}</td>
@endif
@if ($resource_event->inOrOut($resource_event->outTime,
$resource_event->inTime) === "Out" )
<td class="text-center">Checked Out</td>
<td class="text-center">{{ $resource_event->user->name }}</td>
@else
<td class="text-center">Available</td>
<td> </td>
@endif
</tr>
@else
<tr class="table-default" id="{{ $resource->id }}">
<td>{{ $resource->name }}</td>
<td>{{ $resource->description }}</td>
<td class="text-center">Available</td>
<td> </td>
</tr>
@endif
@endforeach
@endforeach
</tbody>
</table>
使用上面的 blade 代码,我得到了每个资源的多个实例(每个 $event 一个),并且 rowspan 在它应该工作的时候只是吓坏了。我尝试了各种方法,其中 none 给了我想要的东西。我在 Google 上的 Laracasts 上搜索过,没有任何情况与我的情况完全相同或帮助我解决了问题。希望这里有人能帮助我。
我对 ROWSPAN 的意图是使 table(正常工作时)看起来像这样:
========================================================
| Vehicle | Description | Status | Checked Out To |
|------------------------------------------------------|
| Truck 1 | 4x4 Truck | Available | |
|------------------------------------------------------|
| Truck 2 | 4x4 Truck | Checked Out | Person 1 |
| | |------------------------------|
| | | Checked Out | Person 2 |
|------------------------------------------------------|
| Truck 3 | 2WD Truck | Available | |
========================================================
解决方案
虽然可能有更好的方法,但我想出的解决方案是:
首先,使用带约束的预加载从控制器中的数据库中获取我需要的组合数据。
// Establish the earliest and latest times of the form's date
$formStartOfDay = Carbon::parse($formDate)->startOfDay();
$formEndOfDay = Carbon::parse($formDate)->endOfDay();
// Gather needed data from the database.
// Get the data via Eager Loading
$resources = Resource::whereIn('type', ['SUV', 'Truck', 'Car'])->orderBy('name')
->with(['events' => function ($query) use ($formStartOfDay, $formEndOfDay) {
$query->whereDate('outTime', '>=', $formStartOfDay)->whereDate('inTime', '<=', $formEndOfDay)
->orWhereDate('outTime', '=', $formStartOfDay)->whereDate('inTime', '>', $formEndOfDay)
->orWhereDate('outTime', '<', $formStartOfDay)->whereDate('inTime', '=', $formEndOfDay)
->orWhereDate('outTime', '<', $formStartOfDay)->whereDate('inTime', '>', $formEndOfDay)
->orderBy('outTime');
}])->get();
接下来我修改了 Blade 模板以使用新集合:
<table class="table table-bordered table-sm">
<thead class="bg-primary text-white">
<tr class="text-center">
<th scope="col">Vehicle</th>
<th scope="col">Description</th>
<th scope="col">Status</th>
<th scope="col">Checked Out To</th>
<th scope="col" style="width: 9%">Returning</th>
</tr>
</thead>
<tbody>
@foreach ($resources as $resource)
@if ($resource->events->contains('resource_id', $resource->id))
@foreach ($resource->events as $resource_event)
<tr class="table-default" id="{{ $resource->id }}">
<td>{{ $resource->name }}</td>
<td>{{ $resource->description }}</td>
@if ($resource_event->inOrOut($resource_event->outTime, $resource_event->inTime) === "Out" )
<td class="text-center">Checked Out</td>
<td class="text-center">
{{ $resource_event->user->name }}<br />
</td>
<td class="text-center">
{{ \Carbon\Carbon::parse($resource_event->inTime)->format('m/d/Y g:i A') }}
</td>
@else
<td class="text-center">Available</td>
<td> </td>
<td> </td>
@endif
</tr>
@endforeach
@else
<tr class="table-default" id="{{ $resource->id }}">
<td>{{ $resource->name }}</td>
<td>{{ $resource->description }}</td>
<td class="text-center">Available</td>
<td> </td>
<td> </td>
</tr>
@endif
@endforeach
</tbody>
</table>
解决方案的关键是使用适当的约束进行预加载。这样我就收到了所有的“资源”,但只收到了我需要的“事件”。这使我能够极大地简化 Blade 代码并使我远离非常复杂的循环和 if-else 块。
我希望这对以后的其他人有所帮助。