Работа с БД в Drupal 7 - урок 5 - Extenders (Расширения)
Запросы выборки поддерживают расширения (extenders). Расширение дает возможность добавить функциональность к запросу выборки во время выполнения. Эта функциональность может быть дополнительным методом или обрабатывать поведение существующего метода.
Для этого используется в ООП паттерны (design patterns), расширения реализуют таким образом Decorator Pattern. Они прикрепляют дополнительные обязанности к динамическому объекту через предоставления гибкого альтернативного подкласса для метода расширения.
Использование Extenders (расширений)
Для использования расширения вы должны иметь объект-запрос. Для объекта-запроса метода extend() будет возвращать новый объект, который будет использован вместо текущего объекта-запроса. Например:
<?php $query = $query->extend('PagerDefault'); ?>
В указанном примере создается новый PagerDefault объект-запроса, который содержит в себе оригинальный объект-запроса и возвращает новый объект. $query может использоваться и без расширений, но с ним объект получает дополнительные возможности. Заметьте также что $query будет возвращен методом extend() и старое значение не будет сохранено. Следующий пример пояснит это:
<?php $query = db_select('node', 'n'); $query ->fields('n', array('nid', 'title') ->extend('PagerDefault') // This line returns a new PagerDefault object. ->limit(5); // This line works, because the PagerDefault object is what is called. // The return from extend() was never saved to a variable, so $query is still just the Select object. $query->orderBy('title'); // This line executes the Select object, not the extender. The extender no longer exists. $result = $query->execute(); ?>
Во избежание проблем, рекомендую обозначать для расширения объекта-запроса также как в оригинальном объект-запросе.
<?php $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort'); $query->fields(...); // ... ?>
Это обеспечивает для $query полное расширение объекта для начала. Также расширения могут использоваться несколько раз для объекта, но порядок их использования может иметь значение. Например объект расширенный с помощью table-sort должен сначала быть расширенным с помощью PagerDefault.
Создание новых расширений
Расширение это просто класс который реализует SelectQueryInterface и принимает два параметра в конструкторе: запрос выборки и объект DatabaseConnection. Расширение должно реализовывать методы SelectQueryInterface и передать их через объект-запрос в конструктор.
В большинстве случаев все будет сделано через расширение класса SelectQueryExtender, который обрабатывает все внутри класса.. На практике, расширения это любой класс расширенный SelectQueryExtender. Имя этого класса это то, что должно быть определено в вызове extend() для объект-запроса.
Это добавлять или переопределять методы зависит только от класса расширения. Любой метод который не переопределен будет напрямую передан через объект-запрос. Когда метод переопределяется, расширение может или может не вызывать лежащий в основе объект-запрос, однако расширение должно вернуть такое значение, которые ожидается в интерфейсе SelectQuery. В большинстве случаев передается сам объект-запрос или расширение передает объект другого расширения.
Следующий пример пояснить описанное выше.
<?php class ExampleExtender extends SelectQueryExtender { /** * Сортируем записи. */ public function orderBy($field, $direction = 'ASC') { return $this; } /** * Дописываем свой метод. */ public function orderByForReal($field, $direction = 'ASC') { $this->query->orderBy($field, $direction); return $this; } } ?>
В этом примере мы переписываем метод orderBy() для запроса, при этом не добавляем ничего, но используем дополнительный метод orderByForReal(), это реализует сортировку по возрастанию. Оба метода возвращают объект-запрос. Это используется для того чтобы не потерять уже созданный объект.
Любой модуль может объявлять расширение. Ядро Друпала предоставляет два хороших расширения: PagerDefault и TableSort.
Поддержка нескольких БД
Метод расширения работает как db_select, расширение ищет имя класса которое использует в суффиксе драйвер БД. Поэтому, вы можете определить ExampleExtender_pgsql а также ExampleExtender который и будет использоваться если доступен.