Werken met de database in Drupal 7 – les 5 – Extenders (uitbreidingen)
Select-query’s in Drupal ondersteunen zogenaamde extenders (uitbreidingen). Een extender maakt het mogelijk om extra functionaliteit toe te voegen aan een query tijdens de uitvoering. Deze functionaliteit kan bestaan uit aanvullende methoden of wijzigingen in het gedrag van bestaande methoden.
In de objectgeoriënteerde programmeerprincipes (OOP) wordt hiervoor een ontwerppatroon gebruikt, namelijk het Decorator Pattern. Extenders voegen dynamisch extra verantwoordelijkheden toe aan een bestaand queryobject door middel van een flexibele alternatieve subklasse die het querygedrag uitbreidt.
Gebruik van extenders
Om een extender te gebruiken, moet je eerst een queryobject hebben. De methode extend() van het queryobject retourneert een nieuw object dat de originele query bevat, maar uitgebreid is met extra mogelijkheden. Bijvoorbeeld:
<?php $query = $query->extend('PagerDefault'); ?>
In dit voorbeeld wordt een nieuw PagerDefault-object aangemaakt dat de oorspronkelijke query bevat en teruggeeft als een nieuw object. Het oorspronkelijke $query
-object kan ook zonder uitbreidingen worden gebruikt, maar door een extender toe te voegen krijgt het extra functionaliteit. Let op dat de methode extend()
een nieuw object retourneert en het oude niet automatisch vervangt. Het volgende voorbeeld verduidelijkt dit:
<?php $query = db_select('node', 'n'); $query ->fields('n', array('nid', 'title')) ->extend('PagerDefault') // Deze regel retourneert een nieuw PagerDefault-object. ->limit(5); // Werkt, omdat nu het PagerDefault-object actief is. // De returnwaarde van extend() is niet opgeslagen, dus $query blijft een standaard Select-object. $query->orderBy('title'); // Deze regel voert de oorspronkelijke query uit, niet de extender. De extender bestaat niet meer. $result = $query->execute(); ?>
Om dit soort problemen te vermijden, is het aanbevolen om de uitbreiding op dezelfde variabele toe te passen:
<?php $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort'); $query->fields(...); // ... ?>
Op deze manier behoudt $query
alle uitbreidingen vanaf het begin. Let op dat extenders meerdere keren kunnen worden toegepast, maar de volgorde kan van belang zijn. Bijvoorbeeld: een object dat TableSort gebruikt, moet eerst met PagerDefault worden uitgebreid.
Een eigen extender maken
Een extender is in feite een klasse die het SelectQueryInterface implementeert en twee parameters aanneemt in de constructor: het queryobject en een DatabaseConnection-object. De extender moet de methoden van SelectQueryInterface implementeren en deze doorgeven aan het queryobject binnen de constructor.
In de meeste gevallen wordt de functionaliteit vereenvoudigd door de klasse SelectQueryExtender uit te breiden, die de standaardafhandeling verzorgt. In de praktijk is elke klasse die SelectQueryExtender uitbreidt een extender. De naam van deze klasse wordt vervolgens gebruikt als argument in extend().
Welke methoden worden toegevoegd of overschreven, hangt af van de implementatie van de extender. Alle methoden die niet worden overschreven, worden direct doorgegeven aan het onderliggende queryobject. Wanneer een methode wel wordt overschreven, kan de extender ervoor kiezen om de oorspronkelijke querymethode aan te roepen of niet. In beide gevallen moet de returnwaarde voldoen aan de verwachte structuur van SelectQuery. Meestal retourneert de methode het queryobject zelf of een ander uitbreidingsobject.
Onderstaand voorbeeld illustreert dit principe:
<?php class ExampleExtender extends SelectQueryExtender { /** * Overschrijft de sorteerfunctie. */ public function orderBy($field, $direction = 'ASC') { return $this; } /** * Voegt een eigen sorteermethode toe. */ public function orderByForReal($field, $direction = 'ASC') { $this->query->orderBy($field, $direction); return $this; } } ?>
In dit voorbeeld wordt de bestaande methode orderBy() overschreven, maar zonder functionaliteit toe te voegen. In plaats daarvan wordt een nieuwe methode orderByForReal() gedefinieerd die daadwerkelijk de sorteermethode van de originele query aanroept. Beide methoden retourneren het queryobject, zodat het method chaining mogelijk blijft.
Elke module kan eigen extenders definiëren. De Drupal core biedt twee nuttige standaardextenders: PagerDefault en TableSort.
Ondersteuning voor meerdere databases
Het extensiemechanisme werkt op dezelfde manier als db_select(): Drupal zoekt automatisch naar een klassennaam met het database-driverachtervoegsel. Dat betekent dat je bijvoorbeeld ExampleExtender_pgsql kunt definiëren voor PostgreSQL, naast ExampleExtender als standaardoptie. Drupal zal automatisch de juiste variant gebruiken afhankelijk van de actieve databaseverbinding.