Problém s načítáním related položek

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Flaiming
Člen | 4
+
0
-

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)

enumag
Člen | 2118
+
0
-

nenačetla se mi navázáná položka $ticket->status->name v latte šabloně

Mohl bys ukázat i tu šablonu (respektive relevantní část)?

Flaiming
Člen | 4
+
0
-

Čá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
+
0
-

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('*'));
Flaiming
Člen | 4
+
0
-

enumag: Jak lze vidět z toho přiloženého obrázku, tak tam to ID zadané je (hodnota 2). Tohle bylo samozřejmě první, co jsem kontroloval, tedy že to vůbec mám napojené ;)

Jinak count upravím, díky.

enumag
Člen | 2118
+
0
-

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

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);
}
?>
enumag
Člen | 2118
+
0
-

Super. :-) Budu se muset zeptat @hracha, jestli o tom ví.

EDIT: Aha, asi nemusím. Bude to stejný problém jako zde.

Editoval enumag (21. 11. 2012 16:08)