# Базы данных {#top} Kohana 3.0 поставляется с надежным модулем для работы с базами данных. По умолчанию модуль БД содержит драйверы для [MySQL](http://ru.php.net/manual/en/book.mysql.php) и [PDO](http://ru2.php.net/pdo). Модуль Database содержится в дистрибутиве Kohana 3.0, но требует подключение перед использованием. В файле `application/bootstrap.php` измените вызов метода [Kohana::modules], подключив модуль Database: Kohana::modules(array( ... 'database' => MODPATH.'database', ... )); ## Настройка {#configuration} После подключения модуля необходимо создать файл настроек, чтобы модуль знал как соединиться с базой данных. Пример конфигурационного файла можно найти в `modules/database/config/database.php`. Структура группы настроек базы данных ("instance") выглядит следующим образом: string INSTANCE_NAME => array( 'type' => string DATABASE_TYPE, 'connection' => array CONNECTION_ARRAY, 'table_prefix' => string TABLE_PREFIX, 'charset' => string CHARACTER_SET, 'profiling' => boolean QUERY_PROFILING, ), [!!] В одном конфигурационном файле можно определить несколько таких групп. Очень важно понимать каждый параметр конфигурации. INSTANCE_NAME : Соединения могут быть названы как Вы захотите, но одно из них обязательно должно называться "default" (группа по умолчанию). DATABASE_TYPE : Один из установленных драйверов баз данных. Kohana поставляется с драйверами "mysql" и "pdo". CONNECTION_ARRAY : Специфические настройки драйвера для соединения с БД. (Настройки драйвера описаны [ниже](#connection_settings).) TABLE_PREFIX : Префикс, который будет добавлен к названиям таблиц классом [query builder](#query_building). QUERY_PROFILING : Включает [профилирование](debugging.profiling) запросов к БД. ### Пример Ниже описаны два соединения с MySQL, одно локальное, а другое удаленное. return array ( 'default' => array ( 'type' => 'mysql', 'connection' => array( 'hostname' => 'localhost', 'username' => 'dbuser', 'password' => 'mypassword', 'persistent' => FALSE, 'database' => 'my_db_name', ), 'table_prefix' => '', 'charset' => 'utf8', 'profiling' => TRUE, ), 'remote' => array( 'type' => 'mysql', 'connection' => array( 'hostname' => '55.55.55.55', 'username' => 'remote_user', 'password' => 'mypassword', 'persistent' => FALSE, 'database' => 'my_remote_db_name', ), 'table_prefix' => '', 'charset' => 'utf8', 'profiling' => TRUE, ), ); ### Настройки соединения {#connection_settings} Каждый драйвер БД имеет свои настройки соединения. #### MySQL БД MySQL поддерживает следующие параметры массива `connection`: Тип | Параметр | Описание | Значение по умолчанию ----------|------------|-----------------------------| ------------------------- `string` | hostname | Имя сервера или IP-адрес | `localhost` `integer` | port | Номер порта | `NULL` `string` | socket | сокет UNIX | `NULL` `string` | username | Имя пользователя | `NULL` `string` | password | Пароль | `NULL` `boolean` | persistent | Постоянное соединение | `FALSE` `string` | database | Имя базы данных (схемы) | `kohana` #### PDO База данных PDO database принимает следующие опции массива `connection`: Тип | Параметр | Описание | Значение по умолчанию ----------|------------|-----------------------------| ------------------------- `string` | dsn | Идентификатор источника PDO | `localhost` `string` | username | Имя пользователя | `NULL` `string` | password | Пароль | `NULL` `boolean` | persistent | Постоянное соединение | `FALSE` !! Если Вы используете PDO и не уверены, что прописывать в параметре `dsn`, ознакомьтесь с [PDO::__construct](http://php.net/pdo.construct). ## Соединения и сущности {#connections} Каждая группа настроек связана с экземпляром базы данных ("сущность"). Каждая сущность может быть получена через вызов [Database::instance]: $default = Database::instance(); $remote = Database::instance('remote'); Чтобы порвать соединение с базой данных, просто уничтожьте объект: unset($default, Database::$instances['default']); Если Вы хотите разорвать соединения со всеми сущностями за раз: Database::$instances = array(); ## Создаем запросы {#making_queries} Существует два способа создать запросы. Простейший путь - использование [Database_Query] для создания запросов, через [DB::query]. Эти запросы называются "подготовленные выражения" и позволяют устанавливать параметры, которые автоматически экранируются. Второй путь - построение через специальные методы. Это возможно с помощью объекта [query builder](#query_building). [!!] Все запросы выполняются методом `execute`, который принимает объект [Database] или имя сущности. Смотри [Database_Query::execute]. ### Подготовленные выражения Подготовленные выражения позволяют писать SQL-запросы вручную, в то же время значения будут автоматически экранированы, чтобы избежать [SQL-инъекций](http://wikipedia.org/wiki/SQL_Injection). Создать запрос просто: $query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user'); Фабричный метод [DB::query] создает новый класс [Database_Query] и возвращает его, поддерживая цепочки вызовов. Запрос содержит параметр `:user`, которому будет назначено значение: $query->param(':user', 'john'); [!!] Имя параметра может быть любой строкой, в дальнейшем оно будет заменено функцией [strtr](http://php.net/strtr). Рекомендуется **не** использовать знак доллара в составе имени параметра во избежание путаницы. Если Вы хотите увидеть SQL, предназначенный для выполнения, просто преобразуйте объект в строку: echo Kohana::debug((string) $query); // выведет: // SELECT * FROM users WHERE username = 'john' Также Вы можете изменить параметр `:user`, снова вызвав [Database_Query::param]: $query->param(':user', $_GET['search']); [!!] Для задания нескольких параметров за раз используйте [Database_Query::parameters]. После установки всех параметров можно выполнить запрос: $query->execute(); Также допустимо привязать параметр к переменной, используя [ссылки на переменные]((http://php.net/language.references.whatdo)). Это может стать очень полезным при многократном выполнении схожих запросов: $query = DB::query(Database::INSERT, 'INSERT INTO users (username, password) VALUES (:user, :pass)') ->bind(':user', $username) ->bind(':pass', $password); foreach ($new_users as $username => $password) { $query->execute(); } В данном примере переменные `$username` и `$password` меняются в каждой итерации цикла `foreach`. Когда переменные меняются, также изменяют значение и параметры запроса `:user` и `:pass`. Правильное и уместное использование привязки параметров может сделать код более компактным. ### Конструктор запросов {#query_building} Динамическое создание запросов с использованием объектов и методов позволяет писать запросы очень быстро и предсказуемо. Построитель запросов также заключает в кавычки идентификаторы (имена таблиц и полей), также как и экранирует значения. [!!] На данный момент невозможно комбинировать построитель запросов с подготовленными выражениями. #### Выборка (SELECT) Каждый тип запросов представлен отдельным классом со своими методами. К примеру, чтобы создать запрос типа SELECT, используем [DB::select]: $query = DB::select()->from('users')->where('username', '=', 'john'); По умолчанию, [DB::select] будет запрашивать все поля (`SELECT * ...`), но можно указать, какие столбцы извлекать: $query = DB::select('username', 'password')->from('users')->where('username', '=', 'john'); А теперь посмотрим, к чему привела эта цепочка вызовов. Сперва мы создаем новый объект выборки методом [DB::select]. Далее, устанавливаем таблицу(ы) с помощью метода `from`. И напоследок, ищем конкретные записи через метод `where`. Можно посмотреть генерируемый код SQL просто преобразовывая объект к строке: echo Kohana::debug((string) $query); // Покажет: // SELECT `username`, `password` FROM `users` WHERE `username` = 'john' Обратили внимание, что имена полей и таблиц автоматически экранированы, также как и значения? Это одно из ключевых преимуществ использования построителя запросов. Также допустимо создавать псевдонимы `AS` для выборки: $query = DB::select(array('username', 'u'), array('password', 'p'))->from('users'); Сгенерируется следующий SQL-запрос: SELECT `username` AS `u`, `password` AS `p` FROM `users` #### Вставка (INSERT) Чтобы создать записи в базе данных, используйте [DB::insert], создающий запросы INSERT: $query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd')); Запрос сформирует код: INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd') #### Обновление (UPDATE) Для редактирования существующей записи предназначен метод [DB::update], он возвращает запрос UPDATE: $query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john'); В результате получим запрос: UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john' #### Удаление (DELETE) Для удаления записи используется [DB::delete], он создает запрос DELETE: $query = DB::delete('users')->where('username', 'IN', array('john', 'jane')); Получим следующий запрос: DELETE FROM `users` WHERE `username` IN ('john', 'jane') #### Функции работы с базами данных {#database_functions} Иногда Вы можете столкнуться с ситуацией, когда надо вызвать `COUNT` или другую функцию СУБД внутри запроса. Построитель запросов позволяет использовать эти функции двумя способами. Первый - применение кавычек внутри псевдонимов: $query = DB::select(array('COUNT("username")', 'total_users'))->from('users'); Это выглядит почти также, как и стандартные псевдонимы, но имя поля обрамлено двойными кавычками. Каждый раз, когда значение в двойных кавычках обнаруживается внутри имени столбца, **только** часть внутри этих кавычек будет экранирована. Сгенерируется код SQL: SELECT COUNT(`username`) AS `total_users` FROM `users` #### Сложные выражения "Закавыченные" псевдонимы могут решить многие проблемы, но время от времени может понадобиться сложное выражение. В таких случаях надо использовать выражения, создаваемые методом [DB::expr]. Выражение используется для прямого вывода, экранирование не происходит.