Toto je jen stručný článek pro vývojáře, kteří potřebují v Drupalu 7 či 8 alterovat SQL query. Pokud mu nebudete rozumět, nezoufejte, možná není pro vás.
Při práci na alterování SQL query jsem narazil na neočekávané chování některých metod, které ač se zdají být zcela pasivní, mají nečekané důsledky.
Hooky pro query alter slouží k tomu, abychom mohli již vytvořený SelectQuery objekt modifikovat, např. joinovat další tabulku, nebo častěji upravit podmínky, které se nacházejí v části za WHERE, a to těsně před tím, než je query provedena a vytvořený SQL dotaz zaslán na MySQL (či jiný) server.
Pokud ovšem před modifikací query použijete některou z následujících funkcí
$query->__toString(), např. ve spojení s print($query->__toString()) pro výpis vzniklého dotazu, nebo
$query->getArguments(), pro zjištění, jaké jsou v query argumenty (to jsou ty proměnné označované jako :db_placeholder_x),
budete překvapeni nečekanými výsledky. Jakmile totiž funkci getArguments použijete v domnění, že vám pouze vrátí argumenty, nevšimnete si, že funkce k vrácení argumentů potřebuje SelectQuery objekt nejprve zkompilovat. Pokud pak provedete požadované změny v SelectQuery objektu, např. změníte podmínku, nemá tato změna efekt, protože query je již zkompilována. Můžete se pak dostat do situace, že kód, který by měl normálně fungovat a vy v něm nevidíte žádnou chybu, prostě nefunguje. S funkcí __toString() je to podobné.
Pro vývojáře je podstatný fakt, že tyto funkce nečekaně mění výsledky kódu, a to i přesto, že podle svých názvů působí zcela pasivně, pouze jako něco, co má získat data či zkonvertovat SelectQuery objekt do řetězce.
Příklad:
/**
* Implements hook_query_TAG_alter().
*/
function hook_query_TAG_alter(QueryAlterableInterface &$query) {
/** @var \SelectQuery $query */
// S následují řádkou nebude mít další kód žádný efekt.
$query_argumants = $query->getArguments();
$conditions = &$query->conditions();
/** @var \DatabaseCondition $condition_field */
$condition_field = &$conditions[0]['field'];
$inner_conditions = &$condition_field->conditions();
// Zde si představte konkrétní manipulace s conditions...
}
Komentáře
Workaround?
Děkuju za popis problému. Mohl bys prosím ještě doplnit, jak jsi to vyřešil?
Přidat komentář