Работа с базой данных в Joomla | Joomla API

JDatabase – абстрактный уровень базы данных

Joomla
Добавление в избранное
Сохранить
JDatabase – абстрактный уровень базы данных

Содержание

Общая информация

Группа классов Database является абстрактным уровнем базы данных, который значительно упрощает жизнь разработчику при работе с базами данных, и является составляющей как Joomla! CMS, так и Joomla! Framework. Этот уровень позволяет использовать различные типы SQL баз данных и работать в различных средах с различными префиксами таблиц. Специальный конструктор запросов улучшает читаемость и упрощает SQL кодинг. Использование уровня базы данных гарантирует максимальную совместимость и гибкость при разработке расширений.

В CMS группа классов JDatabase расположена в /libraries/joomla/database. При разработке расширений, мы чаще всего имеем дело с абстрактным классом JDatabaseDriver. Ниже представлена его диаграмма наследования:

Диаграмма наследования класса JDatabaseDriver

Для того чтобы начать работу с базой данных нам нужно получить объект класса JDatabaseDriver:

$db = JFactory::getDbo();

При разработке компонента в модели можно воспользоваться вот таким вызовом:

$db = $this->getDbo();

Составление запросов

При составлении SQL-запросов можно использовать два подхода: строковой или объектно-ориентированный.

Строковые запросы

Вот как выглядит простой строковой запрос:

$query = 'SELECT * FROM #__content WHERE title = JDatabase';

Это обычный SQL-синтаксис.

Обратите внимание, что в качестве префикса таблицы используется строковой элемент #_. При установке запроса он заменяется реальным префиксом таблицы.

Конструктор запросов JDatabaseQuery

Класс JDatabaseQuery позволяет создавать запросы в объектно-ориентированном виде. Вот как выглядит такой запрос:

$query = $db->getQuery(true);
 
$query->select('*')
$query->from('#__content ')
$query->where('title = JDatabase');

Мы также можем использовать цепочку методов:

$query = $db->getQuery(true);
 
$query->select('*')
    ->from('#__content ')
    ->where('title = JDatabase');

Объектно-ориентированный поход более предпочтителен при разработке расширений. Его преимущества – это читаемость и гибкость.

Полную документацию по классу JDatabaseQuery вы найдете в материале JDatabaseQuery - конструктор SQL-запросов.

Установка и выполнение запросов

Для установки SQL-запроса используется метод setQuery($query, $offset = 0, $limit = 0):

  • $query - непосредственно SQL-запрос
  • $offset - с какой записи начинать выборку
  • $limit - сколько записей выбирать

Например, мы хотим установить выборку десяти записей и начать эту выборку с пятой записи:

$query = 'SELECT * FROM #__content';
$db->setQuery($query, 5, 10);

Запрос установлен, но как его выполнить? У JDatabaseDriver для этого есть множество методов, которые условно можно разделить на две группы:

  • выполнение запроса без получения результатов. Обычно используется вместе с INSERT, UPDATE, DELETE.
  • выполнение запроса с получением результатов. Обычно используется вместе с SELECT.

Для выполнения запроса без получения результатов используется всего один метод execute(). Он выполняет последний установленный через метод setQuery() запрос:

$query = 'DELETE FROM #__content WHERE title = JDatabase';
$db->setQuery($query);
$db->execute();

В Joomla 2.5 вместо метода execute() вы должны использовать метод query().

Для выполнения запроса с получением результатов используется большое количество различных методов. Их использование зависит от того, какой запрос мы устанавливаем, и какой результат мы хотим получить. Например, наиболее популярный метод loadObjectList() возвращает массив объектов:

$query = 'SELECT * FROM #__content';
$db->setQuery($query, 5, 10);
$results = $db->loadObjectList();

Для сокращения написания кода мы можем использовать цепочку методов:

$db->setQuery($query)->execute();
$results = $db->setQuery($query)->loadObjectList();

Подробнее о выборке данных, а также о вставке, обновлении и удалении данных, вы сможете прочитать в соответствующей документации, которая сейчас находится на стадии перевода/разработки.

Экранирование строк и входных данных

Перед использованием в запросе строки в обязательном порядке должны быть экранированы. Это один из постулатов безопасного программирования - никогда не доверяйте входным данным, даже если они приходят из предыдущего запроса из вашего же источника данных. Для экранирования строк вы можете использовать методы escape($text, $extra = false) и quote($text, $escape = true).

Метод escape() добавляет обратную косую черту перед небезопасными символами (обычно перед одинарными кавычками, но это зависит от движка базы данных):

echo $db->escape("I'm a developer");

Результат:

I\'m a developer

Он также позволяет включить экранирование дополнительных символов (например, нижнее подчеркивание или символ процента). Для этого необходимо передать вторым параметром true:

echo $db->escape("I'm a good %developer%", true);

Результат:

I\'m a good \%developer\%

В этом случае знак процента будет восприниматься как строковой элемент, а не как специальный групповой символ.

Метод quote() экранирует строку и оборачивает в одинарные кавычки:

echo 'SELECT * FROM #__content WHERE title = ' . $db->quote("I'm a developer");

Результат:

SELECT * FROM #__content WHERE title = 'I\'m a developer'

Однако экранирование может быть выключено, так как в некоторых ситуациях это необходимо. Например, при использовании условия LIKE. Для этого необходимо передать вторым параметром false:

 

$title = "I'm a good %developer%";
$search = $db->quote($db->escape($title, true) . '%', false);
echo 'SELECT * FROM #__content WHERE title LIKE ' . $search;

 

Переменная $title сначала экранируется с помощью метода escape(), причем второй параметр установлен в true, поэтому другие специальные символы тоже будут экранированы (в противном случае вы можете столкнуться с серьезной проблемой производительности, если пользователь укажет слишком много специальных групповых символов). Далее результат передается в метод quote(), но экранирование при этом выключено (потому что оно уже было сделано методом escape()):

SELECT * FROM #__content WHERE title LIKE 'I\'m good \%developer\%%'

Начиная с Joomla 3, метод quote() также принимает массив строк, и возвращает массив экранированных и обернутых в одинарные кавычки строк:

$title = array("I'm a good developer", "I'm using Joomla! CMS");
 
echo 'SELECT * FROM #__content WHERE title IN ('
    . implode(',', $db->quote($title)) . ')';

Результат:

SELECT * FROM #__content WHERE title IN ('I\'m a good developer','I\'m using Joomla! CMS')

Использование quoteName()

Метод quoteName($name, $as = null) необходим для использования зарезервированных имен (таких как: table, count и т.п.) в идентификаторах (таких как: названия таблиц или названия полей) или специальных символах. В разных движках баз данных это происходит по-разному: в MySQL это обратные одинарные кавычки, в SQL-сервер это квадратные скобки, а в стандартном SQL это двойные кавычки:

echo 'SELECT * FROM ' . $db->quoteName('#__content')
    . ' WHERE ' . $db->quoteName('title') . ' = ' . $db->quote('JDatabase');

Результат:

SELECT * FROM `#__content` WHERE `title` = 'JDatabase'

Метод quoteName() также как и метод quote() может принимать массив:

$fields = array('title', 'state');
 
echo 'SELECT ' . $db->quoteName($fields)
    . ' FROM ' . $db->quoteName('#__content')
    . ' WHERE ' . $db->quoteName('title') . ' = ' . $db->quote('JDatabase');

Результат:

SELECT `title`,`state` FROM `#__content` WHERE `title` = 'JDatabase'

Второй параметр $as выступает в качестве условия AS, которое ассоциировано с параметром $name. Это может быть строка или массив. В последнем случае его длина должна совпадать с длиной $name:

echo 'SELECT * FROM ' . $db->quoteName('#__content', 'a')
    . ' LEFT JOIN ' . $db->quoteName('#__users', 'b') . ' ON b.id = a.created_by'
    . ' WHERE ' . $db->quoteName('title') . ' = ' . $db->quote('JDatabase');

Результат:

SELECT * FROM `#__content` AS `a` LEFT JOIN `#__users` AS `b` ON b.id = a.created_by WHERE `title` = 'JDatabase'

Алиасы методов quote() и quoteName()

Для методов quote() и quoteName() существуют алиасы:

  • q() может быть использовано вместо quote()
  • qn() может быть использовано вместо quoteName()

Реализация алиасов построена на магическом методе __call(), поэтому их использование довольно спорно. Ведь бытует мнение, что магические методы более медленные.

Другие методы

getConnectors()

Возвращает массив доступных на данный момент драйверов.

getInstance($options = array())

Возвращает экземпляр класса драйвера с заданными опциями. Существует три глобальные опции, остальные специфичны для конкретного драйвера базы данных. Опция 'driver' определяет, класс какого драйвера необходимо использовать для соединения – по умолчанию это 'mysqli'. Опция 'database' определяет, какую базу данных использовать для соединения – по умолчанию это 'null'. Опция 'select' определяет, должен ли коннектор автоматически выбирать эту базу данных – по умолчанию 'true'.

splitSql($sql)

Разбивает строку с несколькими запросами в массив индивидуальных запросов.

connect()

Подключает к базе данных.

connected()

Вернет true если установлено соединение с базой данных.

disconnect()

Метод для разрыва соединения с базой данных.

dropTable($table, $ifExists = true)

Метод для удаления таблицы из базы данных, если переменная $ifExists установлена в true, то выполняется проверка на существование таблицы.

getAffectedRows()

Возвращает количество строк, которые были затронуты предыдущим SQL-запросом.

getCollation()

Возвращает кодировку текущей базы данных.

getConnection()

Информация о соединении с базой данных.

getCount()

Общее количество выполненных драйвером базы данных SQL-запросов.

getDatabase()

Возвращает имя базы данных текущего соединения.

getDateFormat()

Возвращает совместимую PHP date() функцию для драйвера базы данных.

getMinimum()

Возвращает минимальную поддерживаемую версию базы данных.

getNullDate()

Возвращает null или нулевое представление timestamp для драйвера базы данных.

getNumRows()

Возвращает количество строк, которые попали в результат выполнения предыдущего SQL-запроса.

getPrefix()

Возвращает префикс таблиц для драйвера базы данных.

getExporter()

Получает объект класса exporter.

getImporter()

Получает объект класса importer.

getQuery($new = false)

Получает текущий объект запроса (либо строку запроса) или новый объект запроса, если параметр установлен в true.

getIterator($column = null, $class = '\\stdClass')

Получает новый объект итератора для текущего запроса.

getTableColumns($table, $typeOnly = true);

Возвращает ассоциативный массив, ключами которого будет тип поля в таблице, а значения – данные о типе поля.

getTableCreate($tables)

Показывает запрос CREATE, который создает указанные в параметре $tables таблицы.

getTableKeys($tables)

Возвращает массив ключей таблицы с их характеристиками.

getTableList()

Возвращает массив со списком таблиц текущей базы данных.

hasUTFSupport()

Определяет, поддерживает ли движок базы данных кодировку UTF-8.

getVersion()

Возвращает версию базы данных.

insertid()

Возвращает значение идентификатора последней вставленной записи запроса INSERT.

isMinimumVersion()

Проверяет, поддерживается ли установленная версия базы данных драйвером базы данных.

log($level, $message, array $context = array())

Логирует сообщение.

lockTable($tableName)

Блокирует таблицу в базе данных.

replacePrefix($sql, $prefix = '#__')

Заменяет строковой идентификатор $prefix строкой, содержащейся в свойстве tablePrefix класса.

renameTable($oldTable, $newTable, $backup = null, $prefix = null)

Переименовывает имя таблицы $oldTable в $newTable.

select($database)

Выбирает базу данных для использования.

setDebug($level)

Устанавливает для драйвера состояние отладчика базы данных.

setLogger(Log\LoggerInterface $logger)

Устанавливает логгер.

setUTF()

Устанавливает для соединения использование кодировки UTF-8.

truncateTable($table)

Удаляет все строки в таблице. Счетчик, который используется для уникальности новых записей обнуляется.

unlockTables()

Разблокирует таблицы в базе данных.

Dmitry Rekun
Работаю в банковской сфере, а с веб-разработкой (непосредственно с Joomla) столкнулся в 2007 году. Теперь это моё хобби, а в редких случаях и вторая работа. Какое-то время вёл свой блог, но решил попробовать работать в команде. И вот c 2012 года я здесь :)

Подпишитесь на рассылку новостей CMScafe