Laravel Blade表创建嵌套Foreach循环



首先,我对编程和Laravel都是新手,所以请原谅我。

我需要显示一个基于两个模型的表:资源和事件。我在它们之间创建了一对多的关系。不幸的是,对于这张桌子,我有特殊的需求,这段关系根本没有帮助。Event模型跟踪每个资源的Checkout和Checkin时间(以及其他事项)。(一个资源可以有许多事件)基本上,如果资源的ID在事件行中列出,那么有人会在一段时间内将其签出。我需要显示资源是否可用于签出或已经为网站用户正在查看的日期/时间。

模型(显示关系)

Resource.php

class Resource extends Model
{
/**
* Define Relationships to other models.
*
*/
// The Event Model
public function events()
{
return $this->hasMany('AppEvent');
}
}

Event.php

class Event extends Model
{
/**
* Define Relationships to other models.
*
*/
// To the User Model
public function user()
{
return $this->belongsTo('AppUser');
}
// To the Resource Model
public function resource()
{
return $this->belongsTo('AppResource');
}
}

在控制器中,我像这样提取应用于日期的所有事件:

$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');

传递给视图后,我尝试创建我想要的表。一个表,列出了所有资源,无论它是否已签出。已借出的资源将显示"已借出";列出谁拥有这种资源。一个资源可能每天被检出不止一次,如果被检出,则需要显示所有实例。

<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>&nbsp;</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>&nbsp;</td>
</tr>
@endif
@endforeach
@endforeach
</tbody>
</table>

使用上面的刀片代码,我将获得每个资源的多个实例(每个$event一个实例),并且rowspan在应该工作的时候会崩溃。我试过各种各样的方法,但没有一种能达到我的目的。我在谷歌和laracast上搜索过,没有任何情况和我的情况完全一样,也没有任何情况能帮助我解决问题。希望这里有人能帮助我。

我对ROWSPAN的意图是使表(正常工作时)看起来像这样:

========================================================
| 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   |                |
========================================================

SOLUTION

虽然可能有更好的方法来做到这一点,但我想到的解决方案是:

首先,使用带约束的Eager Loading从控制器中的数据库中获取所需的组合数据。

// 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">
{{ CarbonCarbon::parse($resource_event->inTime)->format('m/d/Y g:i A') }}
</td>
@else
<td class="text-center">Available</td>
<td>&nbsp;</td>
<td>&nbsp;</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>&nbsp;</td>
<td>&nbsp;</td>
</tr>
@endif
@endforeach
</tbody>
</table>

解决方案的关键是带有适当约束的急切加载。这样我就得到了所有的"资源"。而只是"事件"。我需要。这允许我极大地简化Blade代码,并使我远离非常复杂的循环和if-else块。

我希望这能在将来帮助到别人。

最新更新