Nette\Database: představení
- David Grudl
- Nette Core | 8212
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}
- Pitrsonek
- Člen | 13
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
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
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
Ř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
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
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
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 | 8212
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.
- Honza Marek
- Člen | 1664
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
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
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
@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 | 8212
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?
- David Grudl
- Nette Core | 8212
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.
- srigi
- Nette Blogger | 558
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
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
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
Skalda napsal(a):
To súvisí s chybou v Nette\Database\Selector.
- bojovyletoun
- Člen | 667
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ístoakce_id IN (1,2)
Tableselection -řádek 209.
Editoval bojovyletoun (20. 1. 2011 13:19)
- redhead
- Člen | 1313
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
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.
- Filip Procházka
- Moderator | 4668
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
+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
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
Jakube, joinovat subselecty
pravděpodobně znamená:
SELECT *
FROM tabulka
INNER JOIN (
SELECT * FROM tabulka2
WHERE id = 5
) t2 USING (sloupec)
třeba
- bojovyletoun
- Člen | 667
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
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ístoakce_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
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
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ístoakce_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
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
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
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
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
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
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?
- jiriknesl
- Člen | 56
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.
- tygl
- Člen | 2
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
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.