Bei SQL-Abfragen, bei denen man mehrere Werte, z.B. via ids, aus einer Tabelle gleichzeitig abfragen will, kann man Konstrukte wie WHERE `id` IN (18,12,33,4) verwenden. Joomla 3 und 4 haben dafür eine Datenbank-Methode where() dabei. Mit J!4 kam eine weitere Methode whereIn() dazu, die sowohl das Erstellen der Queries erleichtert als auch die Sicherheit erhöht durch automatische prepared Statements.

Aufgabenstellung

Aus der Joomla-Tabelle #__com_content sollen die Titel der Beiträge abgefragt werden, die die ID 18, 12, 33 oder 4 haben.

Dafür sollen ausschließlich die Joomla-PHP-Klassen verwendet werden. Also nicht irgendwelche selbst zusammengepopelten SQL-Strings der Art

SELECT `title` FROM `#__content` WHERE `id` IN (18,12,33,4)

Vergleich der Abfragen

Bei allen folgenden Beispielen gehe ich davon aus, dass keine use-Zeilen in der Datei verwendet werden (anderes Thema), mit denen man sich die Backslash-Würmer sparen könnte.

Auch verzichte ich auf J-Aliase, da diese in Joomla 5 nicht mehr funktionieren werden (nehme ich an). Meint: Nicht JFactory, sondern \Joomla\CMS\Factory.

Variante 1. Old-fashioned Methode where() mit Jomla 3, die auch unter J!4 nutzbar ist

// Die abzufragenden IDs:
$idWerte = array(18, '12', 33, '4');

/* Werte säubern; auch der Sicherheit wegen.
Obwohl gar nicht immer nötig. */
$idWerte = \Joomla\Utilities\ArrayHelper::toInteger($idWerte);

$db = \Joomla\CMS\Factory::getDbo();
$query = $db->getQuery(true);

$query->select($db->quoteName('title'))
	->from($db->quoteName('#__content'))
	->where($db->quoteName('id') . ' IN (' . implode(',', $idWerte) . ')');

// Debug-Ausgabe:
echo ' Query mit where() <pre>' . print_r((string) $query, true) . '</pre>';exit;

Variante 2. Old-fashioned mit Methode where() nur unter J!4 mit etwas modernisiertem Code

// Die abzufragenden IDs:
$idWerte = array(18, '12', 33, '4');

/* Werte säubern; auch der Sicherheit wegen.
Obwohl gar nicht immer nötig. */
$idWerte = \Joomla\Utilities\ArrayHelper::toInteger($idWerte);

$db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true);

$query->select($db->quoteName('title'))
	->from($db->quoteName('#__content'))
	->where($db->quoteName('id') . ' IN (' . implode(',', $idWerte) . ')');

// Debug-Ausgabe:
echo ' Query mit where() etwas moderner: <pre>' . print_r((string) $query, true) . '</pre>';exit;

Varianten 1 und 2 unterscheiden sich nur durch Zeilen 8. Siehe dazu auch JFactory::getDbo()-Ersatz ab Joomla 4

Beide Varianten geben via der Debugzeile 16 aus:

SELECT `title`
FROM `#__content`
WHERE `id` IN (18,12,33,4)

Schaut man sich die PHP-Codes in Zeilen 13 an, die etwas blöd kompliziert anmuten mit ihrem implode() und Klammern, die man nicht vergessen darf, freut man sich vielleicht über Variante 3.

Variante 3. Modern (bis es wieder veraltet ist). Joomla 4 und Methode whereIn().

// Die abzufragenden IDs:
$idWerte = array(18, '12', 33, '4');

/* Werte säubern; auch der Sicherheit wegen.
Obwohl gar nicht immer nötig. */
$idWerte = \Joomla\Utilities\ArrayHelper::toInteger($idWerte);

$db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true);

$query->select($db->quoteName('title'))
	->from($db->quoteName('#__content'))
	->whereIn($db->quoteName('id'), $idWerte));

// Debug-Ausgabe:
echo ' Query mit whereIn(). Zur Zeit modern: <pre>' . print_r((string) $query, true) . '</pre>';

In Zeile 13 wird der Methode das Array $idWerte ohne jegliches, weiteres Kokolores direkt übergeben. Joomla weiß dann schon, wie man das richtig auflöst. Nämlich zu:

SELECT `title`
FROM `#__content`
WHERE `id` IN (:preparedArray1,:preparedArray2,:preparedArray3,:preparedArray4)
Uuuups!? Wo sind die IDs in Variante 3 hin verschwunden?

Wie oben schon erwähnt und verlinkt, arbeitet man heute bevorzugt mit so genannten prepared Statements bei Datenbankabfragen. Eigentlich konnte man das auch schon früher. Es ist jedoch in Joomla 3 noch nicht der Standard und war etwas aufwändiger hinzubekommen.

Ich sage damit nicht, dass prepared Statements in Joomla 4 immer so selbstverständlich und automatisch vom System zusammengebastelt werden. Man kann auch hier ziemlich stolpern.

Wir haben Glück, dass wir im whereIn()-Beispiel mit Integer-Zahlen arbeiten. Da muss man dann nicht noch weitere Parameter übergeben, sondern Joomla nimmt die "Voreinstellungen".

Die eigentlichen ID-Werte werden in einem ersten Schritt durch eindeutige, unverwechselbare Platzhalter im Query ersetzt, beispielweise :preparedArray1 für die Klartext-ID 18. Der Platzhalter, der auch :firlefanz1 heißen könnte, wird an die ID gebunden (siehe auch Methode bind() und zahlreiche Beispiele im Joomla-4-Core-Code für eigene "Binds").

Im Hintergrund wird die Datenbankabfrage so vorbereitet, dass sie dann final weiß, welcher Platzhalter durch welche ID-Zahl ausgetauscht werden muss.

Empfehlen kann ich das Folgende nicht(!!!!!), da 90% aller Standard Webserver "explodieren" und Browser bis Rechner nahezu einfrieren können, trotzdem habe ich mich fluchend für diesen Beitrag mal getraut, aus meiner Debugzeile 16 das (string) zu entfernen und habe die Ausgabe in eine Datei umgeleitet, die riesig ist.

Dort finde ich zu Beginn die "Binds" in der Objekteigenschaft bounded die Joomla dann später auswerten wird. Darin die Platzhalter und ID-Zahlen (siehe jeweils das value).

Joomla\Database\Mysqli\MysqliQuery Object
(
[bounded:protected] => Array
(
	[:preparedArray1] => stdClass Object
	(
		[value] => 18
		[dataType] => int
		[length] => 0
		[driverOptions] => Array
		(
		)
	)

	[:preparedArray2] => stdClass Object
	(
		[value] => 12
		[dataType] => int
		[length] => 0
		[driverOptions] => Array
		(
		)
	)

	[:preparedArray3] => stdClass Object
	(
		[value] => 33
		[dataType] => int
		[length] => 0
		[driverOptions] => Array
		(
		)
	)

	[:preparedArray4] => stdClass Object
	(
		[value] => 4
		[dataType] => int
		[length] => 0
		[driverOptions] => Array
		(
		)
	)
)
... und vieles, vieles mehr ...