Nette\Database a přístup k prvkům přes vazbu M:N
- Honza Marek
- Člen | 1664
Lze nějak jednoduše v Nette\Database přistoupit k něčemu, co je navázané přes M:N?
Jediné funkční řešení, na které jsem přišel, je toto:
$userLanguages = array();
foreach ($connection->table('user')->where('id = ?', $id)->related('user_language') as $ul) {
$userLanguages[] = $ul->ref('language');
}
return $userLanguages;
Nechce se mi ale psát foreach kvůli každému dotazu na prvky z M:N vazby.
Nebo umí to NotORM stručněji?
- Tharos
- Člen | 1030
Takže v NotORM by to řešil následující super stručný zápis:
$userLanguages = $NotORM->user_language('user_id', $id)->select('language.*');
Edit: V Nette\Database
by to mělo jít ekvivalentně (podle
dokumentace tu tečkovou notaci taky podporuje).
Editoval Tharos (20. 2. 2012 22:39)
- Honza Marek
- Člen | 1664
Jednoduše. Mám dejme tomu toho uživatele a chci znát jeho jazyky. Jsou spojený vazební tabulkou.
Budu něco podobného potřebovat často, tak se ptám, jestli na to existuje nějaká stručná syntaxe.
<small>Tip s tečkovou syntaxí mi generuje v SQL nějaké nesmysly. Myslím, že to není to, co potřebuju.</small>
- Tharos
- Člen | 1030
Možná je tečková notace v Nette\Database
bugová, protože
NotORM se zmíněným zápisem vygeneruje následující dotaz:
SELECT language.*
FROM user_language
LEFT JOIN language ON user_language.language_id = language.id
WHERE (user_id = ?)
Což by mělo být přesně to, co potřebuješ…
Editoval Tharos (20. 2. 2012 23:18)
- Honza Marek
- Člen | 1664
$connection->table('user_language')->where('user_id = ?', $id)->select('language.*');
v Nette dopadne jako
SELECT `language`.*
FROM `user_language`
WHERE (`user_id` = ?)
- Tharos
- Člen | 1030
Hmm, tak to je blbý… Tohle evidentně není z NotORMu naportované správně. No, ještě můžeš zkusit, jestli to třeba nějak nesouvisí s tímhle bugem. Je to fakt debilní rada, ale zkus přidat na konec všech řetězců mezeru…
- hrach
- Člen | 1838
- díky za nalezení bugu
- správná „use case“ pro M:N je tato – kod, ktery vy celou dobu resite je jenom 1:N, pac resite jen polovinu vztahu M:N. Tedy M:N se dela takto:
foreach ($db->table('users') as $user) {
echo $user->name;
foreach ($user->related('user_language') as $lang) {
echo $lang->lang->name;
}
}
Editoval hrach (21. 2. 2012 11:58)
- Tharos
- Člen | 1030
hrach napsal(a):
- díky za nalezení bugu
- správná „use case“ pro M:N je tato – kod, ktery vy celou dobu resite je jenom 1:N, pac resite jen polovinu vztahu M:N. Tedy M:N se dela takto:
foreach ($db->table('users') as $user) { echo $user->name; foreach ($user->related('user_language') as $lang) { echo $lang->lang->name; } }
Tohle je ale docela jiný use case. Ty vypisuješ dostupné jazyky pro všechny uživatele, zatímco Honzu zajímají jazyky jenom jednoho uživatele. Pak je přece úplně zbytečné ten vnější foreach, který by se sestával z jedné iterace, psát…
Editoval Tharos (21. 2. 2012 12:47)
- Tharos
- Člen | 1030
nanuqcz napsal(a):
Tohle je jedna z mála věcí, co se mi na Nette\Database / NotORM nelíbí. Mít tohle v šabloně není moc pěkné
{foreach $user->related('user_language') as $lang} {$lang->lang->name} {/foreach}
Presenter:
// ...
$this->template->userLanguages = $NotORM->user_language('user_id', $id)->select('language.*');
// ...
Šablona:
{foreach $userLanguages as $userLanguage}
{$userLanguage[id]}
{/foreach}
Nevidím v tom nic ošklivého. :) No a třeba v mé aplikaci s takovou velmi tenkou nadstavbou nad NotORMem by byl kód v presenteru následující:
// ...
$this->template->userLanguages = $NotORM->getFacade('user')->findAllUserLanguages($userId);
// ...
Ta tenká nadstavba spočívá v možnosti definic různých fasád, které zjednodušují a hlavně zčitelňují různé zápisy. Prostě preferuji například namísto tohoto kódu:
$pages = $NotORM->page('id', $NotORM->page()->select('MAX(id) id')->group('parent, url');
zápis:
$pages = $NotORM->getFacade('page')->findHeadRevisions();
Pak mi to přijde úplně super. Ale jsme off topic. :)
Editoval Tharos (21. 2. 2012 13:09)
- Tharos
- Člen | 1030
hrach napsal(a):
Tharos: ano, ale to je pak vazba 1:N, ne M:N. Proto sem to tam napsal, nicméně jeho přístup se může velmi rychle změnit a bude muset použít moji verzi, například:
foreach ($db->table('users')->where('id', array(1,2,10,18,23)) as $user) { ...
Pak samozřejmě ano.
Nicméně já ve svých aplikacích čtení pouze části M:N vazby využívám velmi často, protože to opravdu šetří řádky, zbytečný foreach a jsou případy, kdy je pravděpodobnost, že budu vůbec někdy na dané stránce potřebovat číst například více uživatelů zároveň, je mizivá (editace uživatele v backendu → chci mít přehled o jeho jazycích, ale vždy budu editovat pouze jednoho uživatele v daný moment atd.).
- Honza Marek
- Člen | 1664
Tharos, hrach: I když budu potřebovat jazyky jen jednoho uživatele, pořád to není klasické 1:N. Nejdřív totiž musim načíst hromadu záznamů ze spojovací tabulky a pak ke každému záznamu donačíst jeden jazyk. Což lze jedině tím hnusným foreachem nebo tím Tharosovým joinem.
- kainashi
- Člen | 1
Ahoj, řeším problém s Nette\Database:
Mám tabulky articles, categories, tags + articles_categories a
articles_tags.
Potřebuji vypsat seznam všech článků + k nim přiřazených tagů,
případně kategorii a do ní přiřazené články.
Kód v šabloně mám následující ($articles je tabulka):
{foreach $articles as $article}
{$article->title}
{foreach $article->related('articles_tags') as $tags}
{$tags->tags->name}{sep}, {/sep}
{/foreach}
{/foreach}
Tedy přibližně stejný, jaký zde již byl uváděn.
K prvnímu článku mám přiřazeny tři tagy, ke druhému jen jeden z těch
tří.
Při prvním načtení – s čistou cache – stránky se vše vypíše
v pořádku, tedy u prvního článku tři tagy, u druhého jeden.
Pokud stránku refreshnu, nebo se na ní vrátím, tak tag přiřazený ke
druhému článku se sice vypíše u druhého, ale naprosto chybí
u prvního.
Mám pocit, že pokud se mi podaří vyřešit tento první problém, vyřeším i druhý, proto jej zatím nebudu popisovat.
Předem děkuji za pomoc.
Editoval kainashi (23. 2. 2012 23:17)
- potty
- Člen | 13
Mám stejný problém jako kainashi.
{foreach $match->related('player_match')->order('number ASC') as $player}
{$player->player->name} {$player->player->surname}
{/foreach}
Když vymažu cache, tak to funguje. Při dalším refreshi se už ale vypisuje pouze jeden řádek.
Editoval potty (11. 3. 2012 14:48)
- leninzprahy
- Člen | 150
Ještě že to tu je, už jsem chtěl ublížit počítači :)
Je to přesně tak, vazební tabulka s primárním klíčem přes dva
sloupce.
Taky moc dík :)