Dotaz v closure table s možností přidání parametrů

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

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
+
0
-

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'];
}