Dotaz v closure table s možností přidání parametrů
- Jonge
- Člen | 6
Mám klasickou tabulku se články, každý článek má referenci na ID
kategorie. Kategorie může mít další nadřazené a podřazené kategorie.
Tabulka kategorií je klasická closure table.
Potřebuju vybrat poslední články a ke každému jeho kořenovou kategorii
(ne umělý kořen celé closure tabulky, ale uzly první úrovně tohoto
kořene).
To udělám přes následující funkci/dotaz:
public function findRecentArticles()
{
return $this->connection->query('
SELECT a.*, c.name AS root_category
FROM articles a, categories c
JOIN categoriesclosure cc ON (c.id = cc.ancestor)
WHERE cc.descendant = a.category_id
AND c.id != 1
AND cc.depth = (
SELECT MAX(cc.depth)
FROM categories c
JOIN categoriesclosure cc ON (c.id = cc.ancestor)
WHERE cc.descendant = a.category_id
AND c.id != 1
)
AND published = ?
ORDER BY date_added DESC
', TRUE);
}
Ale, na webu na různých místech potřebuju dotaz upravit – například přidat podmínku, že článek musí být z určité kategorie (WHERE article.category_id IN (1,3,8…)), přidat stránkování atd., což kvůli tomu, že to není v NotORM, nemůžu udělat.
Napadají mě následující řešení:
- přepsat dotaz do NotORM (nevím jestli to vůbec jde, jestli jo, tak to bude asi šílenost),
- vytvořit více funkcí (ale kopírování stejného dotazu na několika místech není nejlepší řešení),
- v této funkci přidat parametry, a pak podle nich upravovat dotaz přes if (což bude taky strašný maglajs a při úpravách se v tom půjde špatně vyznat).
Napadá někoho nějaké lepší řešení? Nejschopnější se mi asi zdá přepsání do NotORM, ale nenapadá mě, jak by mohlo vypadat. Byl bych moc vděčný za nakopnutí.
- petr.pavel
- Člen | 535
Obávám se, že zřetězit to všechno nepůjde, protože categoriesclosure se odkazuje do categories dvěma klíči a není způsob, jak říct NotORM, který použít. Něco jako via(), které existuje pro „referencing“ tabulky, ale pro „referenced“ :-) Takže řešení je IMHO rozložit na části a pospojovat v PHP.
To SUBSTRING_INDEX/MAX/CONCAT/LPAD je takový malý hack, jak bez subselectu
získat ancestor řádky, která má maximální hloubku. Předpokládám, že
hloubka je maximálně 9999999999 :-)
(Mimochodem, v poddotazu zbytečně joinuješ categories.)
Nebo si definuj VIEW. To je nejjednodušší a výsledný PHP kód nejčistší. Skryješ ale část logiky.
Tady je řešení bez VIEW.
$clanky = $db->articles()->where('published', $published)->order('date_added DESC');
$idKategorii = $clanky->fetchPairs('category_id', 'category_id');
$idVsechPrarodicu = $db->categoriesclosure()
->where('descendant', $idKategorii)
->where('NOT ancestor', 1)
->group('ancestor')
->fetchPairs('descendant', "SUBSTRING_INDEX(MAX(CONCAT(LPAD(depth, 10, 0), '|', ancestor)), '|', -1)");
$prarodice = $db->categories()->where('id', $idVsechPrarodicu);
foreach ($clanky as $clanek) {
$idPrarodice = $idVsechPrarodicu[ $clanek['category_id'] ];
$kategorie = $prarodice[$idPrarodice];
print $clanek['headline'].': '.$kategorie['name'];
}