Возврат логики из контроллера в представление Laravel 5

У меня есть таблицы:

REGIONS

 id | name
----+------------------
 1  | South Luzon
----+------------------
 2  | North West Luzon
----+------------------
 3  | North East Luzon

=====================================

BRANCHES

machinenum | name      | region_id 
-----------+-----------+-----------
108        | Alaminos  | 1
-----------+-----------+-----------
104        | Alexander | 3
-----------+-----------+-----------
131        | Santiago  | 3
-----------+-----------+-----------
114        | Apalit    | 1
-----------+-----------+-----------
137        | Baliuag   | 1
-----------+-----------+-----------
115        | Baguio    | 2
-----------+-----------+-----------
116        | Bantay    | 2
-----------+-----------+-----------
130        | San Jose  | 3

=======================================

USERS

id | name  | machinenum
---+-------+-------------
1  | user1 | 108
---+-------+-------------
2  | user2 | 104
---+-------+-------------
3  | user3 | 131

========================================

PENDINGS

user_id | docdate 
--------+------------
2       | 2016-07-14
--------+------------
1       | 2016-07-13
--------+------------
1       | 2016-07-14
--------+------------
3       | 2016-07-13

Я хочу отображать все ожидающие отправления, отправленные пользователями, сгруппированные по филиалам и регионам. Таким образом, мой запрос подобен выбору всех регионов, и внутри цикла выберите ветви, которые соответствуют region_id, inner join таблице users, чтобы получить user_id, и внутри этого выберите все ожидающие, которые соответствуют, которые соответствуют user_id, и отобразите docdate, если запрос возвращает NOT NULL иначе отобразить 0.

Вот мой запрос внутри моего контроллера:

$regions = DB::select('SELECT * FROM regions');
        foreach ($regions as $region) {
            echo $region->name . "<br>";
            $branches = DB::select('SELECT b.machinenum, b.name AS bname, u.id as uid
                                    FROM branches AS b
                                    INNER JOIN users AS u ON b.machinenum=u.machinenum
                                    WHERE region_id=:id
                                    ORDER BY b.name ASC',
                                    ['id' => $region->id]);
            foreach ($branches as $branch) {
                echo $branch->bname . "<br>";
                $pendings = DB::select('SELECT * FROM pendings WHERE user_id=:id', ['id' => $branch->uid]);
                if ($pendings) {
                    foreach ($pendings as $pending) {
                        echo $pending->docdate . "<br>";
                    }
                    echo "<br>";
                } else {
                    echo "0 <br>";
                }
            }
            echo "<br>";
        }

Результат будет:

South Luzon
Alaminos
2016-07-14 -- docdate

Apalit
0          -- return 0 if no pending
Baliuag
0          -- return 0 if no pending

North West Luzon
Baguio
0          -- return 0 if no pending
Bantay
0          -- return 0 if no pending

North East Luzon
Alexander
2016-07-13 -- docdate
2016-07-14 -- docdate

San Jose
0          -- return 0 if no pending
Santiago
2016-07-13 -- docdate

Ну, это именно то, что я хочу. Но эта логика внутри моего контроллера. Я хочу, чтобы это было в моем представлении. Как я могу вернуть эту логику, на мой взгляд? Есть ли способ сделать это? Все, что я могу сделать, на мой взгляд, это @foreach and @if.

Вот мой текущий код, на мой взгляд (не обращайте внимания на связь между пользователями и ветвями, она уже есть в моей модели):

// Note! In controller I have:

$regions = Region::all();
$branches = Branch::all();
$pendings = Pending::all();
return view('pending.index', compact('regions', 'branches', 'pendings'));



<table class="table table-noborder table-extra-condensed">
    <thead>
        <tr>
            <th class="custom-td text-center">Date</th>
        </tr>
    </thead>
    <tbody>
        @foreach ($regions as $region)
            <tr>
                <th colspan="19">{{ $region->name }}</th>
            </tr>
            @foreach ($branches as $branch)
                @if ($region->id === $branch->region_id)
                    <tr>
                        <td>{{ $branch->name }}</td>
                    </tr>
                    @foreach ($pendings as $pending)
                        @if ($branch->machinenum === $pending->user->machinenum)
                            <tr>
                                <td class="custom-td text-center">{{ $pending->docdate->format('d') }}</td>
                            </tr>
                        @endif
                    @endforeach
                @endif
            @endforeach
        @endforeach
    </tbody>
</table>

person Lekz Flores    schedule 15.07.2016    source источник


Ответы (1)


Давайте сломаем это.

Вы можете сопоставить эти отношения с вашей моделью региона и просто назвать их «ожидающими», чтобы сделать их более читабельными, и просто вызвать Region::with('branches')->get(); и пусть он возвращает вещи, как вы хотите. Проверьте это.

Вот как мы это сделаем.

//Region.php
function branches(){
    return $this->hasMany('App\Branch')->with('usermachines');
}

Вот сложная часть, давайте представим, что таблица пользователей представляет собой таблицу отношений «многие ко многим» между ветвями и ожиданиями, и используем ветки hasManyThrough, чтобы сделать сложную часть за нас:

//Branch.php
function usermachines(){
    return $this->hasManyThrough('App\Pending','App\User','machinenum','user_id')->with('pendings');
}

Сделанный! Со всей этой настройкой все, что вам нужно сделать, это:

в вашем контроллере:

$regions = Region::with('branches')->get();
return view('pending.index', compact('regions'));

и, по вашему мнению: я удаляю ваш второй foreach и использую forelse, это похоже на foreach, но с else, когда ожидание равно нулю, проверьте это:

<table class="table table-noborder table-extra-condensed">
<thead>
    <tr>
        <th class="custom-td text-center">Date</th>
    </tr>
</thead>
<tbody>
    @foreach ($regions as $region)
        <tr>
            <th colspan="19">{{ $region->name }}</th>
        </tr>
        @foreach ($region->branches as $branch)
                <tr>
                    <td>{{ $branch->name }}</td>
                </tr>
                @forelse($branch->pendings as $pending)
                        <tr>
                            <td class="custom-td text-center">{{ $pending->docdate->format('d') }}</td>
                        </tr>
                @empty
                        <tr>
                           <td>0</td>
                        </tr>
                @endforelse
        @endforeach
    @endforeach
</tbody>

person Magus    schedule 18.07.2016
comment
Я получаю эту ошибку. Не знаю почему: BadMethodCallException в строке Builder.php 2345: вызов неопределенного метода Illuminate\Database\Query\Builder::all(). И добавьте td в свой tr. - person Lekz Flores; 18.07.2016
comment
извините, вместо all() должно быть get() - person Magus; 18.07.2016
comment
В вашем @forelse, не так ли $branch->usermachines->pendings as $pending? Потому что у меня это работает, а не просто $branch->pendings as $pending. - person Lekz Flores; 19.07.2016
comment
это должно быть в ожидании.. id сделал этот код в спешке и не проверял его. рад, что вы смогли заставить его работать! не стесняйтесь редактировать мой ответ. - person Magus; 19.07.2016
comment
Я приму это как правильный ответ. Спасибо! Только один вопрос, как я могу отфильтровать дату, я имею в виду, что хочу использовать пункт where, как я хочу показать все pendings в определенную дату. Я пробовал $regions = Region::with('branches)->where('branches->usermachines->pendings->created_at', '=', '2016-07-14 09:48:55')->get();, но я думаю, что он не может получить вложенные данные json, где я хочу использовать предложение where. Есть идеи по этому поводу? - person Lekz Flores; 20.07.2016
comment
см. мой дополнительный вопрос здесь: stackoverflow.com/questions/38471609/ - person Lekz Flores; 20.07.2016