Problém se zobrazením query v latte
- zeddosx
- Člen | 3
Zdravím, snažím se z databáze dostat do tablu týmy z následujících tabulek (teams¨: id, name) k nim se snažím přiřadit členy týmu (members: id, teamid, racerid) a jejich jména se berou z tabulky závodníků (racers: id, firstname, lastname, type). V „čistém php“ jsem tohoto efektu již docílil, pomocí 3 foreach loopů, a teď se snažím replikovat tento efekt v nette. Z nějakého důvodu se mi vykreslí pouze bloky tablu, ale jména se v nich již nezobrazí. Je možné v nette něco takového udělat, nebo se na to musí jinak?
<?php
namespace App\Presenters;
use Nette;
use Nette\Application\UI\Form;
class TeamsPresenter extends Nette\Application\UI\Presenter
{
private Nette\Database\Explorer $database;
public function __construct(Nette\Database\Explorer $database)
{
$this->database = $database;
}
public function renderDefault(): void
{
$this->template->teams = $this->database->fetchAll('SELECT * FROM teams ORDER BY id');
$this->template->types = $this->database->fetchAll('SELECT * FROM types');
foreach($this->template->teams as $team)
{
foreach($this->template->types as $type)
{
$this->template->members = $this->database->fetchAll('SELECT b.firstname, b.lastname FROM members a JOIN racers b ON b.id = a.racerid WHERE a.teamid = ? AND b.type = ?', $team->id, $type->id);
bdump($this->template->members);
}
}
}
}
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">#</th>
<th scope="col">Tým</th>
<th scope="col" n:foreach="$types as $type" >{$type->name}</th>
</tr>
</thead>
<tbody>
<tr n:foreach="$teams as $team">
<th scope="row">{$team->id}</th>
<td>{$team->name}</td>
<td n:foreach="$types as $type">
<p n:foreach="$members as $member">{$member->firstname} {$member->lastname}</p>
</td>
</tr>
</tbody>
</table>
- David Matějka
- Moderator | 6445
V tom foreachi stále zapisuješ do members, takže tu hodnotu přepisuješ a do šablony se pošle z poslední iterace. Pokud bys to chtěl řešit takhle, musíš si zkonstruovat dvourozměrné pole:
$members = [];
foreach($this->template->teams as $team)
{
foreach($this->template->types as $type)
{
$members[$team->id][$type->id] = $this->database->fetchAll('SELECT b.firstname, b.lastname FROM members a JOIN racers b ON b.id = a.racerid WHERE a.teamid = ? AND b.type = ?', $team->id, $type->id);
bdump($this->template->members);
}
}
$this->template->members = $members;
a v šabloně pak přes tohle iterovat
n:foreach="$members[$team->id][$type->id] as $member"
ale existuje ti tam výkonnostní problém, tvůj kód vygeneruje m*n
dotazů – tedy pokud budeš mít 5 typů a 100 teamů, tak ti to pošle
500 dotazů. Můžeš to třeba vyřešit ručně, že pošleš jeden dotaz s
team_id IN ($ids) AND type_id IN ($ids)
a pak zkonstruuješ to
dvourozměrné pole. Ale vzhledem k tomu, že nijak nefiltruješ teamy ani
typy, tak je zbytečné filtrovat i ty membery. takže si prostě vyber vše
z té tabulky memberů a vytvoř to pole.
další možnost je, že bys použil Nette Database Explorer, který zvládne
některé optimalizace dotazů.
V šabloně bys měl (pokud jsem správně pochopil strukturu db) pak
něco jako:
{foreach $team->related(members)->where(type, $type->id) as $member}{$member->racer->firstname}{/foreach}