Nette\Database: představení

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Grudl
Nette Core | 8172
+
0
-

Součástí Nette už je jeden z pilířů chystané podpory modelu a to databázová vrstva Nette\Database. Celý popis API najdete v dokumentaci.

Nette\Database\Connection

Základem je obálka nad PDO nazvaná Nette\Database\Connection:

$database = new Nette\Database\Connection('mysql:host=localhost;dbname=test', 'root', 'password');

Po připojení se automaticky zobrazí panel na Debug baru.

Oproti klasickému PDO disponuje SQL preprocesorem, kombinuje tak výhody PDO i dibi:

// lze použít i vícenásobný insert
$database->exec('INSERT INTO users', array(
	'name' => 'Jim',
	'created' => new DateTime,
	'avatar' => fopen('image.gif', 'r'),
));

$database->exec('UPDATE users SET ? WHERE id=?', $data, $id);

$database->query('SELECT * FROM categories WHERE id=?', 123)->dump();

Oproti dibi je jednodušší v tom, že nepoužívá modifikátory a drží proto pořadí parametrů query($statement, [$param, [$param, ....]]).

Selector

Pro složitější výběry lze použít nástroj Selector, který vychází z výborné knihovny NotORM Jakuba Vrány a liší se jen syntaxí API. Databázi na obrázku lze procházet takto:

foreach ($database->table('application')->order('title')->limit(5) as $application)
{
	echo $application->title, ' (', $application->author->name, ')';
	// ekvivalentní s $application['title'], ' (', $application['author']['name'], ')';

	foreach ($application->related('application_tag') as $application_tag) {
		echo $application_tag->tag->name . ', ';
	}
}

V šabloně by se použil pochopitelně Latte-zápis:

{foreach $database->table('application')->order('title')->limit(5) as $application}
	<h2>{$application->title} ({$application->author->name})</h2>

	{foreach $application->related('application_tag') as $application_tag}
		{$application_tag->tag->name}{sep}, {/sep}
	{/foreach}
{/foreach}
redhead
Člen | 1313
+
0
-

A to je přesně to, proč jsem zprvu nad NotORM kroutil hlavou. Mít takéto konstrukce v šabloně mi přijde velmi protivné. Vlastně se nemůže ani říct, že jde o model. Chudák kodér, aby si pamatoval celou databázi.

Pitrsonek
Člen | 13
+
0
-

redhead napsal(a):

A to je přesně to, proč jsem zprvu nad NotORM kroutil hlavou. Mít takéto konstrukce v šabloně mi přijde velmi protivné. Vlastně se nemůže ani říct, že jde o model. Chudák kodér, aby si pamatoval celou databázi.

To se mi moc nezdá co píšete, však vám nikdo nebrání udělat si modely s metodami, které budou získávat potřebné data a potom prostřednictvím Presenteru je servírovat kodérovi. Ten stejně musí minimálně znát strukturu dat, které má vykreslit ve View.

Obecně si ale myslím, že není dobré ve View přímo vykonávat příkazy nad DatabaseConnectorem však to má být práce modelu a ani mě nenapadá jak by se řešilo cachování.

Osobně bych ukázku s možností využití notORM ve View klidně nechal, ale striktně upozornil začátečníky atd., že není dobré mastit dotazy nad databází do View vrstvy, protože si to neuvědomí.

Nebo se pletu?

Bohužel ORM by bylo zase v tom lepší, že by získalo všechny výsledky i pro vazby 1:1, 1:n, M:N a poskytlo mi array s objekty záznamů nebo array jak je v CakePHP. Takto si musím v modelu získané údaje zpracovat do rozumného formátu znovu do array.

Například:

<?php
                $applicationsArray = array();
                foreach (Model::$database->table('application')->order('title') as $application)
                {
                    echo $application->title, ' (', $application->author->name, ')';
                        $tagsApplicationArray = array();
                        foreach ($application->related('application_tag') as $application_tag) {
                                $tagsArray[] = $application_tag->tag;
                        }
                         $applicationsArray[] = array('app'=>$application,'tags'=>$tagsArray);
                }

                $this->template->apps= $applicationsArray;
?>

Editoval Pitrsonek (30. 12. 2010 19:01)

redhead
Člen | 1313
+
0
-

To se mi moc nezdá co píšete, však vám nikdo nebrání udělat si modely s metodami, které budou získávat potřebné data a potom prostřednictvím Presenteru je servírovat kodérovi. Ten stejně musí minimálně znát strukturu dat, které má vykreslit ve View.

Model si samozřejmě můžu napsat sám, a já měl pocit, že David chtěl napravit to, že Nette nemělo vlastní modelovou vrstvu. Tuhle ale nějak nechápu.

Běžná praxe je, že se do komentu na začátku šablony napíše, co přesně presenter posílá (a nebo si to člověk dumpne). Takhle ale kodér musí znát tabulky a jejich sloupce, způsob řazení atd. Což je, podle mě, minimálně kontraproduktivní.

Pitrsonek
Člen | 13
+
0
-

Stále nesouhlasím s vašim názorem, sám popíráte co jste napsal: do komentu šablony se napíše co presenter posílá nebo si to dumpne. V tomto se přeci nic nezměnilo. David poskytl řešení pro přístup k DB a záznamům a na vás je v jakém formátu je pošlete kodérovi do view jestliže ho dřív zajímalo jak se data řadí tak ho to bude zajímat i teď a jste nucen ho o tom informovat. Moc nechápu vaše výtky.

redhead
Člen | 1313
+
0
-

Řazení dat snad neřeším v šabloně ale v presenteru, z kterého pošlu maximálně pole s nějakými určenými indexy (které uvedu v komentu). Ale aby kodér, přemýšlel jakou tabulku vlastně má joinovat a aplikovat řazení (jehož offset a počet záznamů budu nejspíš opět posílat z presenteru???). Bavím se teď o kódu šablony, co napsal David v prvním postu (o ničem jiném). To mi přijde opravdu zlé.

Asi si nerozumíme. Můžu si toto napsat do nějakých modelových tříd, ale pak vlastně dělám to samé, co jsem dělal s dibi a o žádnou nativní Nette modelovou vrstvu se nejedná. Pouze o jiný přístup k DB.

Edit: pokud ovšem David nechystá něco dalšího (z toho co psal, to tak vypadá). Jen ta šablona mě prostě dost zarazila. Toť vše.

Editoval redhead (30. 12. 2010 19:41)

Teyras
Člen | 81
+
0
-

redhead napsal(a):

Řazení dat snad neřeším v šabloně ale v presenteru, z kterého pošlu maximálně pole s nějakými určenými indexy (které uvedu v komentu). Ale aby kodér, přemýšlel jakou tabulku vlastně má joinovat a aplikovat řazení (jehož offset a počet záznamů budu nejspíš opět posílat z presenteru???). Bavím se teď o kódu šablony, co napsal David v prvním postu (o ničem jiném). To mi přijde opravdu zlé.

Asi si nerozumíme. Můžu si toto napsat do nějakých modelových tříd, ale pak vlastně dělám to samé, co jsem dělal s dibi a o žádnou nativní Nette modelovou vrstvu se nejedná. Pouze o jiný přístup k DB.

Edit: pokud ovšem David nechystá něco dalšího (z toho co psal, to tak vypadá). Jen ta šablona mě prostě dost zarazila. Toť vše.

Jo, já se v tom taky poněkud ztratil… Je pravda, že řazení a stránkování by model nemusel vůbec řešit (nebo ne přímo), ale aby se kvůli tomu muselo volat NotORM v šabloně? Proč není možné udělat nějakou abstraktní variantu DibiDataSource? Mohl by to třeba být interface, přes který by šablona nějak unifikovaně přistupovala k datům z Modelu

Editoval Teyras (30. 12. 2010 19:47)

na1k
Člen | 288
+
0
-

Součástí Nette už je jeden z pilířů chystané podpory modelu

Nette\Database ještě není ta slibovaná modelová vrstva. Alespoň tak to chápu já.

Co se týče změn, zatím jsem nic nepoužil a nevím, ale už od pohledu se mi nelíbí zápis dotazu, kdy parametry jsou až na konci. Je možná jednodušší toto vnitřně parsovat, ale tenhle zápis mě vytáčel už u Céčkovského printf a dibi v tomhle bylo spásou. Takže za sebe stále zůstávám u dibi a „starého“ neORM přístupu… Až bude hotová celá vrstva modelu, tak to ještě zvážím, ale věřím že David ponechá možnost volby :)

redhead
Člen | 1313
+
0
-

Ok, beru, že to není hotový model, v tom případě by bylo dobré to neuvádět v šablonách, protože by si to mohl někdo špatně vyložit: https://forum.nette.org/…tte-database

David Grudl
Nette Core | 8172
+
0
-

Model !== databáze. Opakuju, model není databáze, model není databáze, model není databáze.

Stejně jako prezentační vrstva nejsou šablony. Šablony mohou být mimo jiné jednou z mnoha součástí prezentační vrstvy, ale zkrátka prezentační vrstva !== šablony.

Žádný „hotový model“ ve frameworku není a nikdy ani nebude. Udělat model je úkolem programátora té které aplikace. Framework může pouze nabídnout nástroje, které zjednodušují složité nebo opakující se činnosti při vývoji modelu.

Nette\Database je jedním z takových nástrojů, stejně tak Nette\Database\Selector. Zkuste to prosím pochopit.

Nette\Database\Selector stejně jako třeba obdobný Nette\Finder samozřejmě lze používat v šablonách, je-li to ku prospěchu věci, a nevidím v tom nejmenší problém.

redhead
Člen | 1313
+
0
-

Neboj, tohle už dávno chápu. Pokud je to tak a žádný nativní model nebude, tak se omlouvám, měl jsem za to, že něco takové hodláš spáchat a věta „jeden z pilířů chystané podpory modelu“ mě v tom jaksi utvrdila (bylo to myšleno jinak, teď to už vidím).

Honza Marek
Člen | 1664
+
0
-

Je to pěkný. Za Doctrinní DBAL bych to s radostí vyměnil. Ale chybí nad tím ta ORM nástavba, která by znamenala ještě sakra hodně práce.

Ped
Člen | 64
+
0
-

Honza: ja jsem docela nalomenej, pri nejblizsim jinem projektu to asi zkusim notORM zpusobem (ze DB de facto definuje velkou cast modelu a neni tam jen jako uloziste dat kam se to nejak naseka dle zvule ORM knihovny bez toho abych na to dohlizel). Myslim ze oba zpusoby maji sve svetle chvilky. :) (a taky asi nocni mury :))

Ped
Člen | 64
+
0
-

redhead napsal(a):

A to je přesně to, proč jsem zprvu nad NotORM kroutil hlavou. Mít takéto konstrukce v šabloně mi přijde velmi protivné. Vlastně se nemůže ani říct, že jde o model. Chudák kodér, aby si pamatoval celou databázi.

Jaky je zasadni principialni rozdil mezi pamatovanim si objektu a schemou databaze? Napoveda v IDE? Nic jineho v tom nevidim, IMHO je to uplne to same. Takze chudak koder, aby si pamatoval cele API modelu…

redhead
Člen | 1313
+
0
-

@Ped:

Tak nevím jestli jsem tu opravdu jediný, komu se mít tohle v šabloně příčí, už jenom složitostí a délkou zápisu, já sám mám v aplikaci i 2–3 JOINy na jeden dotaz s ne zrovna lehkými ONy, to psát v každé šabloně, kde to potřebuju, tak se zblázním (navíc opakuju kód). Na druhou stranu, pokud bych chtěl použít Nette\Database v modelu, je tu ta obtíž, kterou popsal Pitrsonek v příspěvku #3. WOW efekt je opravdu naprosto úžasný, ale až praxe ukáže, jestli se to uchytí. Počkám si na další podpůrné třídy pro model a pak se uvidí.

David Grudl
Nette Core | 8172
+
0
-

Mám pocit, že se bavíš o koze a my o voze. Jaké joiny v šabloně? A proč bys proboha měl dělat něco složitějším způsobem, než to dělat lze?

redhead
Člen | 1313
+
0
-

Možná jo. Já tu celou dobu „kritizuju“ ukázku použití třídy Database v šabloně, která mi prostě přijde ujetá. A teď naposled jsem vyzdvihl to, co říkal Petrsonek v #3. O ničem jiném jsem tu nepsal. Tak mi to když tak vysvětlete :)

David Grudl
Nette Core | 8172
+
0
-

Třída Database ve frameworku vůbec není. Ad Pitrsonek: iterator lze do pole převést pomocí iterator_to_array() nebo různými fetch metodami v PDO.

krissott
Člen | 48
+
0
-

Davide napiš jim malý příkladek využití Database přímo v modelu a způsob předaní dat v šabloně a budeš mít svatý pokoj ;)

srigi
Nette Blogger | 558
+
0
-

redhead neviem ci si cital tento clanok ale tento je IMO Davidovym vstupom k Nette\Database. Principialne asi naozaj mozu existovat tieto dva pristupy k vysypaniu dat do sablony – bud tam nasypes surove data alebo poskytnej nejaky druh DBresultSet a ten si filtrujes, strankujes a pod. Na tebe je aby si si vybral co ti viac vyhovuje.

Honza Marek
Člen | 1664
+
0
-

Klidně to můžeš (a podle mě by se mělo) dát do šablony již na filtrované a nastránkované. Což Nette\Database nebrání v tom, aby se to načetlo až v průběhu vykreslovní šablony.

Skalda
Člen | 8
+
0
-

schéma databáze
Zdravím,
mam tabulky artists a albums ve vztahu many to many (viz schéma)
Ke každému záznamu z artists potřebuji vypsat záznamy z albums, tak aby bylo vše seřazeno hezky podle abecedy (artists podle artist a albums podle album). Zatím se mi podařilo dostat k tomuto:

{foreach $db->table('artists')->order('artist') as $artist}
    - {$artist->artist} <br>
    {foreach $artist->related('albums_artists') as $album}
        -- {$album->albums->album} <br>
    {/foreach}
{/foreach}

jak ale zajistit, aby se i alba řadily abecedně netuším… v notORM stačilo přidat do druhého foreach ->order('albums.album'), ale v Nette to vyhodí chybu o neznámém sloupci. Prosím o radu :) díky

dakota
Člen | 148
+
0
-

Skalda napsal(a):

To súvisí s chybou v Nette\Database\Selector.

https://forum.nette.org/…ase-selector

https://forum.nette.org/…ckova-notace

bojovyletoun
Člen | 667
+
0
-

redhead napsal(a):

Ok, beru, že to není hotový model, v tom případě by bylo dobré to neuvádět v šablonách, protože by si to mohl někdo špatně vyložit: https://forum.nette.org/…tte-database

Chci navázat na (ne)nutnost používání db konstrukcí v šabloně. Dělal jsem jeden projekt (opět kontigenční tabulku, ale složitější – s kategoriemi a pohledy – 9 tabulek) a nejřív jsem použil Nette\Database. V tom se mi nic nedařilo.

Přepnul jsem na dibi. Sice jsem musel psát hromadu joinů(asi 5) a subselectů(2), aby se mi povedlo docílit požadovaného výsledku. Pak stačilo zavolat jednoduše fetchAssoc(|,[],–>,=…) a v šabloně stačily jen jednoduché foreache, žádná logika.

Pak i dibi přestalo stačit, tak jsem se vrhnul na opět na nette\db. Tam se mi povedlo elegantněji napsat. Ale problém nastal, jak dát data do šablony (aniž bych v ní měl složitou logiku jako foreach($…->related->select(), ideálně zustat u stejné šablony).
Takže jsem si asociace musel krkolomně vytvořit sám: clone je tam kvůli tomu, abych tam neměl třeba 20 stejných dotazů SELECT id FROM [clovek] WHERE (clovek_typ_id IN ('1', '2', '3')).

$ak2 = clone $ak;
	$ak2->select('id')->fetchpairs('id');
	$temp = array();
	foreach($cl as $c){
	    $t = $temp[$c->id] = new stdClass();
	    $t->jmeno = $c->jmeno;
	    $t->id = $c->id;
	    $t->metrika = $c->related('ucast')->where('akce_id', $ak2)
			    ->group('clovek_id,metrika_id')->select('count() as cnt,metrika_id') //*
			    ->fetchPairs('metrika_id', 'cnt');
	}
	$this->template->clovek = $temp;
$cl = $this->dbx->table('clovek')->where('clovek_typ_id', $this->dbx->table('viewparam') //**
				->where('view_id', $view)->select('clovek_typ_id'))->order('jmeno');

jak to se vyvaruji duplicit clovek_typ_id?

takže závěr:

  • výhoda dibi = fetchassoc umí dát data do tvaru přijatelného pro šablonu, žádná magie, dostanu, co přesně to, co si napíšu(byť složitě)
  • nevýhoda dibi = musím ošéfovat joiny
  • nevýhoda nette\db = výstup musím nějak transformovat(přeorganizovat), aby byl pro šablonu přijatelný
  • výhoda: jednoduché získávání dat, která si pak musí přeorganizovat, nebo jednoduše vypsat v šabloně(ale zanáší do šablony modelövé funkce)

Dotazy:

  • viz hvězdička- pokud volám >group('clovek_id,metrika_id')->select('count() as cnt,metrika_id'), tak si sloupce musím ručně přidat do selectu – je to očekávané nebo něco dělám špatně
  • podpora fetchassoc
  • podpora fetchAll
  • umí vícenásobné reference?(1:n, nebo n:1?) a to jak v select : ->table('view')->where('id',14)->select('view.clovek_typ.clovek.jmeno), tak i v where :->table('clovek')->where('clovek.clovek_typ.view,14)->select(‚clovek.jmeno‘)
  • umí joinovat subselecty? – resp jsou vůbec potřeba když jde where(col,tableselection)
  • viz 2 hvězdičky: jak zabránit duplicitě clovek_typ_id
  • umí předat pdo parametry do vnořených subselectů? (pokud pokusně opravím chybu změnou "IN ($clone)" na "IN ($clone->sql)", tak se sice poskládá dotaz, ale zůstanou otazníky. Na tu chybu jsem narazil ještě jednou předtím, ale tenkrát to rovnou házelo něco ve smyslu: Cannot pass PDO bounded parameters to nested selects.
  • chyba v related()->WHERE($subselect)- pokud explicitně nezavolám $subselect->select(id) tak vznikne nesmysl akce_id IN ('1', 'PrvniAkce', '1287784800', '4', '2', 'Akcesid2', '1286575200', '4') místo akce_id IN (1,2) Tableselection -řádek 209.

Editoval bojovyletoun (20. 1. 2011 13:19)

Cifro
Člen | 245
+
0
-

1++ fetchAssoc

1++ fetchAll

Tieto veci by sa zišli v Nette\Database. fetchAssoc je killer fičura dibi a mohla by to byť killer fičura aj v Nette.

Editoval Cifro (20. 1. 2011 14:54)

redhead
Člen | 1313
+
0
-

bojovyletoun vystihl přesnou podstatu problému. Takto složité věci mít v šabloně je prostě hrůza. Nicméně i v modelu se musí složitě foreachovat, abych dostal to co chci. V dibi jsou jednoduše-složité věci zapsané hned.

Souhlasím, fetchAll() a fetchAssoc() by to o dost zjednodušilo.

dakota
Člen | 148
+
0
-

bojovyletoun napsal(a):

  • nevýhoda dibi = musím ošéfovat joiny

Nebral by som to ako nevýhodu v prípade ak chceš zostaviť iný dotaz s join ako to vytvára Nette\Database\Selector. Možno nevýhoda že ten join musíš v dibi napísať, v Nette\Database\Selector ti to zostaví samo. Napr. už spomínaný join a odvodená tabuľka.

vrana
Člen | 131
+
0
-

$result->fetchAll() je totéž jako iterator_to_array($result) a podle mě je to potřeba výjimečně. $result->fetchAssoc() je totéž jako iterator_to_array($result->fetch()) a podle mě je to potřeba ještě méně. Do NotORM to dávat nebudu.

potapnik
Člen | 127
+
0
-

V souvislosti s částečnou implementací NotORM v podobě Nette.Database jsem se chtěl zeptat, jestli je v plánu taktéž část modifikace/vkládání nových záznamů, případně jak se bude lišit syntaxe. Předem díky za odpověď.

Filip Procházka
Moderator | 4668
+
0
-

Nejrychleji mě teď napadá ukázka asi tady https://gist.github.com/784438

//edit: V úvodním příspěvku máš ukázku insert i update, co ti v tom chybí?

Editoval HosipLan (20. 1. 2011 22:44)

maio
Člen | 7
+
0
-

+1

Jsem se musel zaregistrovat abych vyjadril podporu. :) Taky mi prijde ten priklad hodne spatny. Je to jen o neco hezci zapis dibi::query a mit takove veci v sablone… Prijde mi to temer jako anti-pattern co se tyce udrzovatelnosti kodu a vlastne i celeho systemu.

redhead napsal(a):

A to je přesně to, proč jsem zprvu nad NotORM kroutil hlavou. Mít takéto konstrukce v šabloně mi přijde velmi protivné. Vlastně se nemůže ani říct, že jde o model. Chudák kodér, aby si pamatoval celou databázi.

vrana
Člen | 131
+
0
-

bojovyletoun napsal(a):

  • viz hvězdička- pokud volám >group('clovek_id,metrika_id')->select('count() as cnt,metrika_id'), tak si sloupce musím ručně přidat do selectu – je to očekávané nebo něco dělám špatně

Byla to chyba, v NotORM jsem ji opravil.

  • umí joinovat subselecty? – resp jsou vůbec potřeba když jde where(col,tableselection)

Nevím, co znamená joinovat subselecty.

  • viz 2 hvězdičky: jak zabránit duplicitě clovek_typ_id

Klasicky pomocí group() nebo select("DISTINCT clovek_typ_id").

  • umí předat pdo parametry do vnořených subselectů?

Nepředávaly se, chybu jsem v NotORM opravil.

  • chyba v related()->WHERE($subselect)

Nechápu, uveď prosím příklad.

Filip Procházka
Moderator | 4668
+
0
-

Jakube, joinovat subselecty pravděpodobně znamená:

SELECT *
FROM tabulka
INNER JOIN (
	SELECT * FROM tabulka2
	WHERE id = 5
) t2 USING (sloupec)

třeba

vrana
Člen | 131
+
0
-

Tak to nejde. K čemu se to hodí?

bojovyletoun
Člen | 667
+
0
-

Myslel jsem toto:
Původně jsem měl toto: (že jsem musel 2× uvádět clovek_typ_id).

$cl = $this->dbx->table('clovek')->where('clovek_typ_id', $this->dbx->table('viewparam')->where('view_id', $view)->select('clovek_typ_id'));

Jestli by to šlo nějak přímočaře.

Tabulka pohledů (view), které obsahuje připravené výběry lidí podle jejich skupin. Popsáno zde
Co chci: začínám u nějakého view(třeba 10) a chci se dostat přes clovek_typ, které patří do daného view ke konkrétním lidím.

Jde to vyřešit nějak elegantně, abych tam nemusel hledat jména primárních klíčů? tj něco jako(pseudokod) table(view)->get(10)->clovek_typ()->clovek. Nebo jít inverzně: table('clovek')->where(clovek_typ in view 10)

Tedy shrnu dotaz:

Pokud, chci probublat přes několik tabulek (view->clovek_typ->clovek),
tak jak mám postupovat (náznak- vícenásobné reference jdou jen na odkazovanou tabluku)?

  • začnout od tabulky s podmínkou `$db->table('view')->get(10)->...select(view.viewparam.clovek_typ.clovek)'
  • začnout od tabulky s výsledkem $db->table('clovek')->where('clovek.clovek_typ.viewparam.view.id',10)

diagram:

Editoval bojovyletoun (21. 1. 2011 13:08)

bojovyletoun
Člen | 667
+
0
-

Příspěvek odděluji kvůli přehlednosti

chybu s related se mi nepovedlo nasimulovat na nějakém pěkném kódu.
Jde o to, že v Tableselection::where@line 208 (případ když volám ssubresultem a hodnoty jdou do dotazu(mysql)), tak:

  • je tam foreach na všechny řádky
  • u každého řádku se k parametrům přidají všechny sloupce subresultu, takže vznikne akce_id IN ('1', 'PrvniAkce', '1287784800', '4', '2', 'Akcesid2', '1286575200', '4') místo akce_id IN (1,2),

ale to je spíš moje chyba ,že explicitně nevyberu právě jeden řádek.

$in = array();
				foreach ($clone as $row) {
					$this->parameters[] = array_values(iterator_to_array($row));
					$in[] = (count($row) === 1 ? '?' : '(?)');
				}
				$condition .= ' IN (' . ($in ? implode(', ', $in) : 'NULL') . ')';

Editoval bojovyletoun (21. 1. 2011 13:11)

dakota
Člen | 148
+
0
-

bojovyletoun napsal(a):

Pokud, chci probublat přes několik tabulek (view->clovek_typ->clovek),
tak jak mám postupovat (náznak- vícenásobné reference jdou jen na odkazovanou tabluku)?

  • začnout od tabulky s podmínkou `$db->table('view')->get(10)->...select(view.viewparam.clovek_typ.clovek)'
  • začnout od tabulky s výsledkem $db->table('clovek')->where('clovek.clovek_typ.viewparam.view.id',10)

Neviem či toto konkrétne by neprinieslo skôr zmätok. Zápis „$table.$column“ sa v súčasnosti používa ako odkaz z tabuľky application_tag na tabuľku application a nie opačne. Jakub sa už viackrát vyjadril že pre odkaz z application na application_tag (tiež by som to rad využil) by musela vzniknúť nová syntax, zatiaľ sa nevie aká a tiež či to niekedy bude implementované.

Editoval dakota (21. 1. 2011 14:12)

dakota
Člen | 148
+
0
-

bojovyletoun napsal(a):

  • u každého řádku se k parametrům přidají všechny sloupce subresultu, takže vznikne akce_id IN ('1', 'PrvniAkce', '1287784800', '4', '2', 'Akcesid2', '1286575200', '4') místo akce_id IN (1,2),

ale to je spíš moje chyba ,že explicitně nevyberu právě jeden řádek.

Podľa mňa toto nie je chyba. Je potrebné uviesť ktorý stĺpec z poddotazu sa má použiť.

Filip Procházka
Moderator | 4668
+
0
-

Jakube, jsi si jistý, že myslíš ten samý fetchAssoc jako my? :)

$result = dibi::select('col1, col2, col3, col4')->from('tabulka');
$assoc = $result->fetchAssoc('col1[]col2|col3=col4');

foreach ($assoc as $col1 => $list1) {
	foreach ($list1 as $col2list) {
		foreach($col2list as $col2 => $col3list) {
			foreach ($col3list as $col3 => $col4) {
				echo $col4;
			}
		}
	}
}

možná jsem se v tom trochu zamotal, ale s fetchAssoc z dibi jsou dělat podobné prasečinky. Jsi si jistý že ekvivalentem je

iterator_to_array($result->fetch());

? :)

bojovyletoun
Člen | 667
+
0
-

jak bych vybral toto?

$db->table('clovek_typ')->get(3)->related('clovek')
->fetchPairs('clovek_typ.jmeno','clovek.jmeno')

vytvoří správný sql

`SELECT [clovek].[clovek_typ_id], clovek_typ.jmeno
FROM [clovek]
LEFT JOIN [clovek_typ] ON [clovek].[clovek_typ_id] = [clovek_typ].[id]
WHERE (clovek.clovek_typ_id IN (3))`,

který vrátí správné hodnoty, ale potom to selže u TableRow:
Unknown column clovek_typ.jmeno,Unknown column clovek.jmeno


PS: fetchAll() by mohlo být realizované takto:

	function fetchAll(){
	    $this->execute();
	    return array_map(function($row){return $row->toArray();},$this->data);
	}

Taky jsem zkusil zprovoznit fetchAssoc z dibi. S jednou malou změnou se to povedlo, jenže nevím jak na odkazované sloupce, bude tam potřeba něco jako getsql, createjoins atd…

Editoval bojovyletoun (22. 1. 2011 18:18)

bojovyletoun
Člen | 667
+
0
-

Mám další návrh ohledně referencí. Nyní jde pomocí through změnit sloupec, podle kterého se hledají odkazující řádky (tedy $user->related('article')->through('published_by)), ale jakto zařídit opačně : $article->related('user')->through?('published_by)

myslíte, že je to užitečné? Popř jak se toho docílí elegantně?

Příklad:

  • table user: id, jmeno
  • table article: id, text, user_id(ref:user.id), published_by(ref:user.id)
/* vypíše uživatele a články, které oni zveřejnili.
Pokud by tam through nebylo, tak by se vypsaly články, jejichž je autorem. */
echo "Publishers:".NL;
foreach ($db->table('user') as $u){
    echo $u->name.":".NL;
    foreach ($u->related('article')->through('published_by') as $a){
	echo "- ".$a->text.NL;
    }
}
echo "<hr>";
/* vypíše články a k nim toho uživatele, který článek zveřejnil.
Pokud by tam through nebylo, tak se vypíše uživatel, který autorem článku. */
echo NL."Articles and publishers?".NL;
foreach ($db->table('article') as $a){
    echo $a->text."-> user_id pomocí ref(user):".$a->ref('user')->through?("published_by")->name.NL;
}

Editoval bojovyletoun (23. 1. 2011 0:47)

dakota
Člen | 148
+
0
-

Asi to nie je doriešené, napr. tiež nie je zatiaľ možné:

$articles = $db->table('article')->order('published_by.name');
$articles = $db->table('article')->order('created_by.name');

Najlepšie by bolo ak by sa to dalo riešiť cez DatabaseReflection. Použite vlastného DatabaseReflection je v kode označené ako TODO.

Editoval dakota (23. 1. 2011 13:57)

vrana
Člen | 131
+
0
-

bojovyletoun napsal(a):

potom to selže u TableRow:
Unknown column clovek_typ.jmeno,Unknown column clovek.jmeno

V NotORM jsem to předělal na číselnou pozici, díky za nahlášení.

vrana
Člen | 131
+
0
-

bojovyletoun napsal(a):

články a k nim toho uživatele, který článek zveřejnil

V NotORM se to napíše prostě jako $article->published_by["name"]. To, že published_by vede na tabulku user, se nastaví pomocí Structure (případně Structure_Discovery to zjistí sama). Je to jasně dané pro celou aplikaci, takže by bylo chyba to psát pokaždé znovu u každého dotazu, když to stačí napsat jednou do struktury (v terminologii Nette Reflection).

srigi
Nette Blogger | 558
+
0
-

Rychlym preletenim kodu (a dokumentacie) zistujem, ze Nette\Database nema moznost nastavenia vlastnych konvencii – plurary ako nazvy tabuliek, cudzie kluce a pod. NotORM tuto moznost ma a kedze som zvyknuty na mnozne cislo v nazvoch tabuliek, kcem sa opyat, ci sa nastavenie vlastnych konvencii planuje?

David Grudl
Nette Core | 8172
+
0
-

Je to v plánu.

jiriknesl
Člen | 56
+
0
-

Tohle

{foreach $database->table('application')->order('title')->limit(5) as $application}
        <h2>{$application->title} ({$application->author->name})</h2>

        {foreach $application->related('application_tag') as $application_tag}
                {$application_tag->tag->name}{sep}, {/sep}
        {/foreach}
{/foreach}

je (sic) syntakticky hezký (ale) špageťák. Pevně věřím, že jsi tohle Davide psal jako vtip. IMO by se proměnná $database nikdy neměla dostat mimo model (do Controlleru a už proboha vůbec ne do View) a nějaké table()->order()->groupBy() by mělo zůstat za Mapperem.

jasir
Člen | 746
+
0
-

Co furt všichni máte :-), prostě v presenteru:

<?php
	$this->template->applications = $database->table('application')->order('title')->limit(5);
?>

a je to ne? IMHO tohle byl jen tento zkrácený příklad.

Editoval jasir (17. 2. 2011 14:19)

tygl
Člen | 2
+
0
-

Mam k reseni ohledne tohoto tematu dve veci.

Zadani asi takoveto: Mam tabulky typu %prefix%_tabulka a pouzivam klice typu id%tabulka%.
Chci-li vyuzit alespon castecne podpory a featur tridy Nette\Database, tak pouziju Reflection\DatabaseReflection k prepsani vychozich hodnot, ze kterych zjistuje primarni klic, nazev tabulky, atp.. Problem nastane ve chvili, kdy se dojde k dotazu.

Pouzivam stable verze nette 2.0, PHP 5.3

Napr. vytvarim spojeni do dtb v jakemsi BaseModelu, ktery dedi ostatni modely, obsahuje statickou promennou $database, ktera drzi soucasne spojeni do dtb.
Inicializace cca takto (:

<?php
public function init( $options ) {
	$conn = new Database\Connection($options->dsn, $options->user, $options->password);

	// trosku znasilneni, naprimo do objektu, ale setter jsem nenasel
	$ref = new Reflection\DatabaseReflection('id%s', null, 'PREFIX_%s');
	$conn->databaseReflection = $ref;

	self::$database;
}
?>

Nyni by melo byt znamo, ze chci aby byl primarni klic ve formatu „idTabulka“ a tabulky ve formatu „PREFIX_tabulka“.

Kdyz vsak provedu jakykoli dotaz, napr.

<?php
$database->table("zakaznik")->insert($data);
?>

tak se vznikne dotaz, ve kterem neni nazev tabulky nahrazen pozadovanou patternou, tj. PREFIX_tabulka, ale pouze tabulka.

Nestudoval jsem kod, jak presne DatabaseReflection funguje v celem kontextu, ale pokud tam muzu definovat pattern u primarniho klice, foregin klice, tak ocekavam ze to jde i u table.

--
Druha vec, co se tyce dotazu do dtb primo z sablony ci presenteru, tak imho to neni moudry napad. S dtb ma komunikovat pouze model, dotaz z view naprosto odporuje MVC/MVP, view zobrazuje data z modelu, takto je model obchazen. Navic to vnasi neporadek do sablon, kdezto v modelu jsou vsechny dotazy pohromade a pripadny update se provadi v ramci jednoho souboru (napr.) … v pripade upravy by to znamenalo projit vsechny sablony.

Editoval tygl (20. 2. 2011 18:14)

dakota
Člen | 148
+
0
-

tygl napsal(a):

Nestudoval jsem kod, jak presne DatabaseReflection funguje v celem kontextu, ale pokud tam muzu definovat pattern u primarniho klice, foregin klice, tak ocekavam ze to jde i u table.

V NotORM bolo nedávno doplnené do Structure možnosť špecifikovať prefix pri názve tabuľky. Treba si počkať na implementáciu v Nette\Database\Selector.