Problém s načítáním related položek
- Flaiming
- Člen | 4
Mám problém s podivným způsobem načítání navázaných položek,
zřejmě nějak blbne optimalizace SQL dotazů.
Zde jsou mé kódy:
Komponenta TicketList.php
<?php
class TicketListControl extends \BaseController
{
/** @var \Nette\Database\Table\Selection */
private $selected;
/** @var TicketRepository */
private $ticketRepository;
/** @var Nette\Util\Paginator */
private $paginator;
/** @var int */
private $page;
/** @var string */
private $name;
public function __construct($name, Nette\Database\Table\Selection $selected, TicketRepository $ticketRepository)
{
parent::__construct();
$this->name = $name;
$this->selected = $selected;
$this->ticketRepository = $ticketRepository;
}
public function render()
{
//get repositories
$settingRepository = new \SupportBox\SettingRepository($this->selected->getConnection());
$projectRepository = new \SupportBox\ProjectRepository($this->selected->getConnection());
//get project rewrite
$projectRewrite = $this->presenter->getParameter('project');
//get project ID from his rewrite
$projectId = $projectRepository->findByRewrite($projectRewrite)->id;
//finally get items on page
$itemsOnPage = $settingRepository->findByProject($projectId)->tickets_per_page;
//init aginator
$this->paginator = new Nette\Utils\Paginator;
$this->paginator->setPage($this->presenter->getParameter('page'));
$this->paginator->setItemCount($this->selected->count()); // celkový počet položek (např. článků)
$this->paginator->setItemsPerPage($itemsOnPage); // počet položek na stránce
$this->selected = $this->selected->limit($this->paginator->itemsPerPage, $this->paginator->offset);
//part above should have been in construct, but I couldn't figure out why I can't get GET parameters there...
$page = $this->paginator->page;
if ($this->paginator->pageCount < 2) {
$steps = array($page);
} else {
$arr = range(max($this->paginator->firstPage, $page - 3), min($this->paginator->lastPage, $page + 3));
$count = 4;
$quotient = ($this->paginator->pageCount - 1) / $count;
for ($i = 0; $i <= $count; $i++) {
$arr[] = round($quotient * $i) + $this->paginator->firstPage;
}
sort($arr);
$steps = array_values(array_unique($arr));
}
$this->template->steps = $steps;
$this->template->paginator = $this->paginator;
$this->template->name = $this->name;
$this->template->setFile(__DIR__ . '/TicketList.latte');
$this->template->tickets = $this->selected;
$this->template->render();
}
}
?>
Presenter:
<?php
...
public function createComponentAllTicketsList()
{
return new SupportBox\TicketListControl('Všechny tikety', $this->project->related('ticket'), $this->ticketRepository);
}
public function createComponentMyTicketsList()
{
return new SupportBox\TicketListControl('Moje tikety', $this->project->related('ticket')->where('employee_id', $this->getUser()->getId()), $this->ticketRepository);
}
...
?>
Mám tabulku tiketů a statusů.
Zobrazení stránky:
[ http://vojtechoram.cz/…s/tikety.jpg ]
Problém lze vidět na vygerenované stránce (obrázek) – nenačetla se
mi navázáná položka $ticket->status->name
v latte
šabloně, ale jen u jednoho záznamu. V laděnce jsem si našel vygenerovaný
SQL dotaz:
SELECT `id
, class
, name
FROM status
WHERE (id
IN (5, 3))`
Nenačetlo mi to tedy všechny statusy, které jsem potřeboval. Má to asi
něco společného s tím stránkováním, protože pokud si zobrazím na
jedné stránce v sekci „Všechny tikety“ opravdu všechny tikety bez
stránkování, funguje to ok.
Čím tohle je a jak se této chybě nejlépe vyhnout?
Nette Framework 2.0.6 (revision 6a33aa6 released on 2012–10–01), bez dalších rozšíření
Editoval Flaiming (21. 11. 2012 10:33)
- Flaiming
- Člen | 4
Část TicketList.latte
<?php
...
{foreach $tickets as $ticket}
<tr id="ticket_id_{$ticket->id}">
<td>{$ticket->date_created|date: 'd F Y g:i a'}</td>
<td>#{$ticket->id} {$ticket->title}</td>
<td>{$ticket->employee->name}</td>
<td>{if $ticket->status}
<span class="{$ticket->status->class}">{$ticket->status->name} (ID {$ticket->status_id})</span>
{else}
<span style="color: red;">Zde se nenačte napojený status id ID {$ticket->status_id}</span>
{/if}
</td>
<td>{$ticket->priority|priorityName}</td>
<td><a href="{plink Ticket:detail project => $ticket->project->rewrite, id => $ticket->id}">Detail tiketu</a></td>
</tr>
{/foreach}
...
?>
- enumag
- Člen | 2118
Hmm… musím říct, že mi není přiliš jasné v čem může být
problém. Když před tu poddmínku {if $ticket->status}
dáš
ještě {$ticket->status_id}
, co to vypíše? Není tam náhodou
NULL, že ne?
Jedna nesouvisející chybka, které jsem si všiml:
$this->paginator->setItemCount($this->selected->count());
Tohle vytáhne všechny záznamy a pak je spočítá, což je hrozně neefektivní. Použij tohle:
$this->paginator->setItemCount($this->selected->count('*'));
- enumag
- Člen | 2118
Aha, jasně.
Taháš nějaké řádky už někdy předtím z toho $selected
,
které předáváš do TicketListControl::__contruct? Nejde o to jestli tam
nastavuješ nějaké where podmínky, ale jestli pomocí tohoto konkrétního
selection už něco taháš. Mám z toho pocit, že stejné selection
používáš pro tahání dat do té horní tabulky. Nevím přesně proč, ale
NDB takhle nefunguje. To Selection si raději vytvoř znovu, tak by to mělo
fungovat.
Editoval enumag (21. 11. 2012 16:11)
- Flaiming
- Člen | 4
enumag: No jasně, to je ono, už to funguje :) Díky! Holt budu muset být
na to dotazování opatrnější.
A nebo zkusím NotORM…
Pro úplnost, jak jsem to opravil:
<?php
public function createComponentAllTicketsList()
{
return new SupportBox\TicketListControl('Všechny tikety', $this->ticketRepository->findBy(array('project_id' => $this->project->id)), $this->ticketRepository);
}
public function createComponentMyTicketsList()
{
return new SupportBox\TicketListControl('Moje tikety', $this->ticketRepository->findBy(array('project_id' => $this->project->id, 'employee_id'=> $this->getUser()->getId())), $this->ticketRepository);
}
?>