Создание таблицы Laravel Blade с вложенными циклами по каждому элементу

Во-первых, я новичок в программировании и Laravel в целом, так что не беспокойтесь.

Мне нужно отобразить таблицу на основе двух моделей: ресурсов и событий. Я создал между ними отношения «один ко многим». К сожалению, для этого стола у меня есть особые потребности, которым отношения просто не помогают. Модель событий отслеживает (среди прочего) время оформления и возврата каждого ресурса. (один ресурс может иметь много событий) В основном, если идентификатор ресурса указан в строке события, значит, кто-то проверял его в течение некоторого периода времени. Мне нужно показать, доступен ли ресурс для проверки или уже отключен на дату / время, когда пользователь сайта просматривает.

Модели (чтобы показать отношения)

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

Передав это представлению, я пытаюсь создать нужную мне таблицу. Таблица, в которой перечислены все ресурсы, вне зависимости от того, зарегистрированы они или нет. Те ресурсы, которые находятся вне очереди, будут отображены как извлеченные, и в нем будет указано, у кого есть этот ресурс. Ресурс может извлекаться чаще, чем один раз в день, и если он отсутствует, ему необходимо отображать все экземпляры.

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

С помощью приведенного выше кода лезвия я получаю несколько экземпляров каждого ресурса (по одному для каждого события $), и rowspan просто пугает, когда он должен работать. Я пробовал разные вещи, и ни один из них не дал мне того, что я хочу. Я искал здесь, в Google, Laracasts, и ни одна ситуация не похожа на мою и не помогла мне решить проблему. Надеюсь, здесь кто-то может мне помочь.

Мое намерение для 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   |                |
========================================================

person Packetloss    schedule 31.01.2021    source источник
comment
Я не вижу никаких признаков использования здесь функции связи laravel.   -  person Ahmad Karimi    schedule 01.02.2021
comment
Кроме того, почему вы собираетесь использовать rowspan? Разве вы не хотите добавлять каждое событие в отдельную строку? использование rowspan звучит не так корректно и законно.   -  person Ahmad Karimi    schedule 01.02.2021
comment
@AhmadKarimi, вы правы, отношения не для этой таблицы, потому что я не могу понять, как ее можно использовать в полезной манере. (Эта связь используется в других частях приложения.) Если есть способ ее использования здесь, я бы хотел услышать об этом.   -  person Packetloss    schedule 01.02.2021


Ответы (1)


РЕШЕНИЕ

Хотя могут быть более эффективные способы сделать это, я пришел к следующему решению:

Во-первых, используйте нетерпеливую загрузку с ограничениями, чтобы получить необходимые мне комбинированные данные из базы данных в контроллере.

// 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>&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.

Надеюсь, это поможет кому-то еще в будущем.

person Packetloss    schedule 03.02.2021