SQL Dotaz na vice tabulek v šabloně

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

Omlouvám se za tento, pro vás asi směšný dotaz, ale nikde na fóru jsem na to nic nenašel.
Jde mi o vypisování (např. kategorií a subkategorií) na jednom místě stránek.

Mám vytvořený model pro kategorie:

namespace Model;

use dibi;

class Category extends BaseModel {

    public static function getAllCategories(){
        return dibi::fetchAll('SELECT * FROM [categories], [subcategories]
            WHERE [categories.id] = [subcategories.category_id]
            GROUP BY [categories.category] ORDER BY
            [categories.category], [subcategories.subcategory] ', dibi::DESC);
    }


}

V BasePresenteru si potom předám proměnnou s načteným polem do view. Ale ve view nevím jak obsah zobrazit. Potřebuju něco ve smyslu:

{foreach $categories as $cat}

{$cat[‚category‘]}
// zde vypsat dané subkategorie ke kategorii

{/foreach}

A na závěr: Je něco špatně na tom, že tento kód je přímo v layoutu? Nemělo by to být oddělené? Je vhodné cashování tohoto bloku z hlediska zrychlení?

Moc děkuji

Editoval fejtis (16. 2. 2011 21:38)

Šaman
Člen | 2668
+
0
-

Není to špatně. Zobrazovací logika patří do View (tedy i to, že mám zobrazit každý prvek pole), proto tam ta makra jsou. Špatné by bylo, kdybys ten SQL dotaz měl v šabloně.

Co se cachování týče: záleží na tom, jaká data taháš. Ale obecně se optimalizuje až když zjistíš, že je to potřeba.

fejtis
Člen | 16
+
0
-

Díky za postřehy.

Problém jsem vyřešil v šabloně takto

{foreach $categories as $cat}

                                <optgroup label="{$cat['category']}">

                                {foreach Model\Category::getSubcategories($cat['id']) as $subcat}
                                    <option value="{$subcat['id']}">{$subcat['subcategory']}</option>
                                {/foreach}
                                </optgroup>

                            {/foreach}
Šaman
Člen | 2668
+
0
-

Aha, teď jsem teprve pochopil v čem je háček. To volání Model\Category::getSubcategories by ve VIEW asi být nemělo. Ideální by bylo kdyby objekt kategorie už měl v sobě podkategorie a pak by stačilo procházet přímo ten objekt. Prostě jen zobrazit co dodal presenter, ne ještě načítat něco nového.

Čistější by bylo, pokud bys nevolal statickou metodu, ale $cat->getSubcategories(), resp. dá se to zkrátit i na $cat->subcategories (pokud Model dědíš od Nette\Object).

Filip Procházka
Moderator | 4668
+
0
-
namespace Model;

use dibi;

class Category extends BaseModel
{

	public static function getAllCategories()
	{
		$categories = dibi::select('*')
			->from('categories')
			->orderBy(array('category' => dibi::DESC))
			->fetchAssoc('id');

		$subcategories = dibi::select('*')
			->from('subcategories')
			->orderBy(array('subcategory' => dibi::DESC))
			->where('category_id IN %l', array_keys($categories))
			->fetchAssoc('category[]->');

		foreach ($categories as $id => &$category) {
			$category['sub'] = $subcategories[$id];
		}

		return $categories;
	}

}

no a vypíšeš to následovně

{foreach $categories as $cat}
	<optgroup label="{$cat['category']}" n:inner-foreach="$cat['sub'] as $subcat">
		<option value="{$subcat['id']}">{$subcat['subcategory']}</option>
	</optgroup>
{/foreach}

Ale pokud to chceš použít ve formulářích.

namespace Model;

use dibi;

class Category extends BaseModel
{

	public static function getAllCategories()
	{
		$categories = dibi::select('id,category')
			->from('categories')
			->orderBy(array('category' => dibi::DESC))
			->fetchPairs();

		$subcategories = dibi::select('id,subcategory')
			->from('subcategories')
			->orderBy(array('subcategory' => dibi::DESC))
			->where('category_id IN %l', array_keys($categories))
			->fetchAssoc('category_id[]->');

		$options = array();
		foreach ($categories as $id => $category) {
			$options[$category] = $subcategories[$id];
		}

		return $options;
	}

}

A pak jednoduše

$form = new Nette\Application\AppForm();

// ...
$form->addSelect('category', 'Kategorie', Category::getAllCategories());
//...