Основы конфигурации базы данных

Слой доступа к базе данных CakePHP предоставляет слой абстракции и доступ к большинству аспектов взаимодействия с реляционными базами данных, включая поддержку соединений с сервером, построение запросов, предотвращение SQL инъекций, проверка и изменение схемы БД, отладку и создание профилей запросов, направляемых базе данных.

Краткий обзор

Функции, описанные в даннйо главе дают представление о возможностях взаимодействия с API базы данных на низком уровне. Если вместо этого вы хотите узнать больше о нолных возможностях ORM, обратитесь к разделам Query Builder и Табличные объекты.

Самый простой способ создать соединение с базой данных - использовать DSN строку:

use Cake\Datasource\ConnectionManager;

$dsn = 'mysql://root:password@localhost/my_database';
ConnectionManager::config('default', ['url' => $dsn]);

После создания, появится возможность получить доступ к объекту соединения и начать его использовать:

$connection = ConnectionManager::get('default');

Поддерживаемые базы данных

CakePHP поддерживаем следующие редяционные базы данных:

  • MySQL 5.5+
  • SQLite 3
  • PostgreSQL 8.3+
  • SQLServer 2008+
  • Oracle (с использованием плагина)

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

База данных Oracle поддерживается с использованием плагина: Драйвер для базы данных Oracle

Выполнение выражений Select

Выполнение сырых SQL запросов осуществляется очень просто:

use Cake\Datasource\ConnectionManager;

$connection = ConnectionManager::get('default');
$results = $connection->execute('SELECT * FROM articles')->fetchAll('assoc');

Используйте подготовленные выражения для добавления параметров:

$results = $connection
    ->execute('SELECT * FROM articles WHERE id = :id', ['id' => 1])
    ->fetchAll('assoc');

Также можно использовать сложные типы данных в качестве аргументов:

use Cake\Datasource\ConnectionManager;
use DateTime;

$connection = ConnectionManager::get('default');
$results = $connection
    ->execute(
        'SELECT * FROM articles WHERE created >= :created',
        ['created' => new DateTime('1 day ago')],
        ['created' => 'datetime']
    )
    ->fetchAll('assoc');

Вместо написания SQL запросов вручную, используйте конструктор:

$results = $connection
    ->newQuery()
    ->select('*')
    ->from('articles')
    ->where(['created >' => new DateTime('1 day ago')], ['created' => 'datetime'])
    ->order(['title' => 'DESC'])
    ->execute()
    ->fetchAll('assoc');

Выполнение выражений Insert

Вставка строк в базу данных обычно состоит всего из нескольких строк кода:

use Cake\Datasource\ConnectionManager;
use DateTime;

$connection = ConnectionManager::get('default');
$connection->insert('articles', [
    'title' => 'A New Article',
    'created' => new DateTime('now')
], ['created' => 'datetime']);

Выполнение выражений Update

Обновление строк в базе данных также интуитивно понятно, следующий пример обновляет элемент article с id 10:

use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
$connection->update('articles', ['title' => 'New title'], ['id' => 10]);

Выполнение выражений Delete

Точно так же метод delete() используется для удаления строк из базы данных. В следующем примере удаляется элемент article с id 10:

use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
$connection->delete('articles', ['id' => 10]);

Настройка

Согласно правилу, соединение с базой данных настраивается в config/app.php. Информация о соединении в этом файле используется в классе Cake\Datasource\ConnectionManager, создавая настройку соединения, которая будет использоваться вашим приложением. Пример настройки соединения находится в файле config/app.default.php. Пример конфигурации выглядит следующим образом:

'Datasources' => [
    'default' => [
        'className' => 'Cake\Database\Connection',
        'driver' => 'Cake\Database\Driver\Mysql',
        'persistent' => false,
        'host' => 'localhost',
        'username' => 'my_app',
        'password' => 'sekret',
        'database' => 'my_app',
        'encoding' => 'utf8mb4',
        'timezone' => 'UTC',
        'cacheMetadata' => true,
    ]
],

Вышеуказанный код создаст соединение „default“ с предоставленными параметрами. Вы можете определить столько соединений, сколько нужно в конфигурационном файле. Вы можете также определить дополнительные соединения во время выполнения, используя Cake\Datasource\ConnectionManager::config(). Пример:

use Cake\Datasource\ConnectionManager;

ConnectionManager::config('default', [
    'className' => 'Cake\Database\Connection',
    'driver' => 'Cake\Database\Driver\Mysql',
    'persistent' => false,
    'host' => 'localhost',
    'username' => 'my_app',
    'password' => 'sekret',
    'database' => 'my_app',
    'encoding' => 'utf8mb4',
    'timezone' => 'UTC',
    'cacheMetadata' => true,
]);

Параметры конфигурации также могут быть представлены в виде строки DSN. Это полезно при работе с переменными окружения или провайдерами PaaS:

ConnectionManager::config('default', [
    'url' => 'mysql://my_app:sekret@localhost/my_app?encoding=utf8&timezone=UTC&cacheMetadata=true',
]);

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

По умолчанию, все объекты Таблицы используют default соединение. Для использования соединения не по умолчанию, смотрите Настройка соединений.

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

className
Полное имя класса с указанием пространства имён, предоставляющее соединение с сервером базы данных. Этот класс несет отвечает за загрузку драйвера базы данных, обеспечивая механизм транзакций и подготавливая выражения SQL среди прочего.
driver
Имя класса драйвера, используемого для реализации всех особенностей механизма базы данных. Это может быть как короткое имя класса с использованием синтаксиса плагина, полное имя класса или созданный экземпляр драйвера. Примеры сокращенных наименований класса: Mysql, Sqlite, Postgres, и Sqlserver
persistent
Следует ли использовать постоянное соединение с базой данных. Эта опция не поддерживается SqlServer. Начиная с версии 3.4.13 CakePHP, исключение выбрасывается, если вы пытаетесь установить persistent в true с помощью SqlServer.
host
Имя хоста сервера базы данных (или IP-адрес).
username
Имя пользователя учетной записи.
password
Пароль учетной записи.
database
Имя базы данных для этого соединения. Избегайте использования . названии вашей базы данных. Из-за того, что экранирование символов осложнено, CakePHP не поддерживает . в имени базы данных. Путь к базе данных SQLite должен быть абсолютным (например, ROOT. DS. 'My_app.db'), чтобы избежать неправильного указания пути из-за использования относительного пути.
port (при необходимости)
Порт TCP или сокет Unix, используемый для подключения к серверу.
encoding
Определяет кодировку, используемую при отправке SQL выражений на сервер. Этот параметр определяет кодировку по умолчнию для всех баз данных кроме DB2.
timezone
Часовой пояс, установленный на сервере.
schema
Настройка в базе данных, используемая в PostgreSQL для указания используемой схемы.
unix_socket
Используется драйверами для подключения через файлы Unix сокетов. Если вы используете PostgreSQL и хотите использовать Unix сокеты, оставьте значение хоста пустым.
ssl_key
Путь до файла SSL ключа. (Поддерживается только MySQL).
ssl_cert
Путь до файла SSL сертификата. (Поддерживается только MySQL).
ssl_ca
Путь до файла издателя SSL сертификата. (Поддерживается только MySQL).
init
Список запросов, которые должны быть отправлены серверу базы данных, когда создается соединение.
log
Установите значение на true для включения логирования запросов. При включеннои режиме запросы будут логироваться на уровне debug с областью действий queriesLog.
quoteIdentifiers
Установите значение на true, если используются зарезервированные слова или специальные символы в названиях таблиц или столбцов. Включение этого параметра приведёт к тому, что в запросах, сформированных с использованием Query Builder, будут использоваться идентификаторы, заключенные в кавычки при создании SQL. Необходимо отметить, что это снизит производительность так как каждый запрос должен быть отслежен и обработан до выполнения.
flags
Ассоциативный массив констант PDO, которые должны быть переданы в базовый экземпляр PDO. Смотрите документацию PDO для флагов, поддерживаемых драйвером, который вы используете.
cacheMetadata
Либо логическое true, либо строка, содержащая конфигурацию кэша для хранения метаданных. Отключение кэширования метаданных не рекомендуется и может привести к очень низкой производительности. Смотрите раздел: ref: database-metadata-cache для получения дополнительной информации.
mask
Установите разрешения для сгенерированного файла базы данных. (Поддерживается только SQLite)

На данном этапе будет полезно обратить внимание на Соглашения CakePHP. Правильное наименование для таблиц (и добавление некоторых столбцов) может дать некоторые дополнительные функции и избежать настройки. Например, если назвать таблицу базы данных big_boxes, таблицу BigBoxesTable и контроллер BigBoxesController, то все вместе будет работать автоматически. Согласно правилам, необходимо использовать знак нижнего подчеркивания, нижний регистр и множественное число в наименованиях таблиц баз данных - например: bakers, pastry_stores и savory_cakes.

Управление соединениями

class Cake\Datasource\ConnectionManager

Класс ConnectionManager действует как реестр для доступа к соединениям базы данных, которые существуют в приложении. Это место, где другие объекты могут получить ссылки на существующие соединения.

Доступ к соединениям

static Cake\Datasource\ConnectionManager::get($name)

Настроенные один раз, соединения могут быть получены с использованием Cake\Datasource\ConnectionManager::get(). Данный метод создаст и загрузит соединение, если оно не было создано до этого или возвратит существующее известное соединение:

use Cake\Datasource\ConnectionManager;

$conn = ConnectionManager::get('default');

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

Создание соединений во время выполнения

Используя config() и get() можно создавать новые соединения, которые не определены в файлах конфигурации, во время выполнения приложения:

ConnectionManager::config('my_connection', $config);
$conn = ConnectionManager::get('my_connection');

Смотрите раздел Настройка для получения дополительной информации по конфигурационным данным, используемым при создании соединений.

Типы данных

class Cake\Database\Type

Так как каждая база данных включает в себя разный набор типов данных или одинаковые имена, используются для схожих типов данных, CakePHP предоставляет набор абстрактных типов данных для использования со слоем базы данных. Типы, которые поддерживает CakePHP:

string
Обычно поддерживается столбцами типа CHAR или VARCHAR. Использование опции fixed преобразует столбец в тип CHAR. Для SQL Server используются типы NCHAR и NVARCHAR.
text
Соответствует типам TEXT.
uuid
Соответствует типу UUID, если база данных имеет таковой, в противном случае генерируется поле CHAR(36).
binaryuuid
Соответствует типу UUID, если база данных имеет таковой, в противном случае генерируется столбец BINARY(16).
integer
Соответствует типу INTEGER, предоставляемому базой данных. BIT на данный момент не поддерживается.
smallinteger
Соответствует типу SMALLINT, предоставляемому базой данных.
tinyinteger
Соответствует типу TINYINT или SMALLINT, предоставляемому базой данных. Для MySQL TINYINT(1) является логическим типом.
biginteger
Соответствует типу BIGINT, предоставляемому базой данных.
float
Соответствует либо DOUBLE, либо FLOAT в зависимости от базы данных. Опция precision используется для определения кол-ва знаков после запятой.
decimal
Соответствует типу DECIMAL. Поддерживаются опции length и precision.
boolean
Соответствует BOOLEAN, кроме MySQL, где TINYINT(1) используется для представления булевых значений. BIT(1) на данный момент не поддерживается.
binary
Соответствует типу BLOB или BYTEA, в зависимости от базы данных.
date
Соответствует простому типу часового пояса столбца DATE. Возвращаемое значение столбца этого типа - Cake\I18n\Date, которое расширяет основной класс DateTime.
datetime
Соответствует простому типу часового пояса столбца DATETIME. В PostgreSQL и SQL Server преобразуется в тип TIMESTAMP. Возвращаемое значение по умолчанию столбца этого типа - Cake\I18n\Time, которое расширяет встроенный класс DateTime и Chronos.
timestamp
Соответствует типу TIMESTAMP.
time
Соответствует типу TIME во всех базах данных.
json
Соответствует типу JSON, если он доступен, иначе преобразуется в TEXT. Тип JSON был добавлен в версии 3.3.0

Эти типы используются как для функций отражения схемы, которые предоставляет CakePHP, так и для функций создания схемы, которые CakePHP использует при проведении тестов.

Каждый тип предоставляет функции преобразования между представлениями PHP и SQL. Эти методы вызываются на основе подсказок для типов данных при выполнении запросов. Например, столбец, помеченный как „datetime“ будет автоматически конвертировать входные параметры из экземпляров DateTime во временные метки или форматированные строки представляющие даты. Аналогично, столбцы с „двоичными“ данными принимают файловые дескрипторы и генерируют файловые дескрипторы при чтении данных.

Изменено в версии 3.3.0: Был добавлен тип json.

Изменено в версии 3.5.0: Были добавлены типы smallinteger и tinyinteger.

Изменено в версии 3.6.0: Был добавлен тип binaryuuid.

Добавление пользовательских типов

static Cake\Database\Type::map($name, $class)

Если необходимо использовать особые типы, которые не встроены в CakePHP, можно добавить новые дополнительные типы в систему типов CakePHP. Классы типов имплементируют следующие методы:

  • toPHP: Преобразует данное значение из типа базы данных в эквивалент PHP.
  • toDatabase: Преобразует данное значение из типа PHP в один из подходящих базе данных.
  • toStatement: Преобразует данное значение в эквивалент выражения.
  • marshal: Сериализирует необработанные данные в объекты PHP.

Простой способ реализовать базовый интерфейс - расширить класс Cake\Database\Type. Например, если необходимо добавить тип JSON, нужно написать следуюий класс для типа:

// в src/Database/Type/JsonType.php

namespace App\Database\Type;

use Cake\Database\Driver;
use Cake\Database\Type;
use PDO;

class JsonType extends Type
{

    public function toPHP($value, Driver $driver)
    {
        if ($value === null) {
            return null;
        }
        return json_decode($value, true);
    }

    public function marshal($value)
    {
        if (is_array($value) || $value === null) {
            return $value;
        }
        return json_decode($value, true);
    }

    public function toDatabase($value, Driver $driver)
    {
        return json_encode($value);
    }

    public function toStatement($value, Driver $driver)
    {
        if ($value === null) {
            return PDO::PARAM_NULL;
        }
        return PDO::PARAM_STR;
    }

}

По умолчанию метод toStatement () обрабатывает значения как строки, которые предназначены для нового типа. Как только новый тип создан, необходимо добавить его в отображение типа. Во время начальной загрузки приложения необходимо сделать следующее:

use Cake\Database\Type;

Type::map('json', 'App\Database\Type\JsonType');

Добавлено в версии 3.3.0: Тип Json, описанный в этом примере был добавлен в ядро фреймворка.

Затем мы можем перезагрузить данные отраженной схемы для использования нового типа, и слой базы данных CakePHP автоматически конвертирует JSON данные при создании запросов. Пользовательские типы можно использовать в вашей Таблице с помощью метода _initializeSchema():

use Cake\Database\Schema\TableSchema;

class WidgetsTable extends Table
{

    protected function _initializeSchema(TableSchema $schema)
    {
        $schema->columnType('widget_prefs', 'json');
        return $schema;
    }

}

Сопоставление пользовательских типов данных выражениям SQL

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

Предыдущий пример сопоставляет пользовательский тип данных для столбца типа „json“, который легко выразить в виде строеи в выражении SQL. Сложные типы данных SQL не могут быть выражены строками/числами в SQL запросах. При работе с этими типами данных класс Типа должен имплементировать интерфейс Cake\Database\Type\ExpressionTypeInterface. Этот интерфейс даёт возможность пользовательскому типу представлять значение в виде SQL выражения. Например, построим простой класс Типа для обработки типа данных POINT из MySQL. Сначала определим объект „value“, который используется для представления данных POINT в PHP:

// в src/Database/Point.php
namespace App\Database;

// Наш объект-значение не изменяем.
class Point
{
    protected $_lat;
    protected $_long;

    // Factory метод.
    public static function parse($value)
    {
        // Парсинг данных из MySQL.
        return new static($value[0], $value[1]);
    }

    public function __construct($lat, $long)
    {
        $this->_lat = $lat;
        $this->_long = $long;
    }

    public function lat()
    {
        return $this->_lat;
    }

    public function long()
    {
        return $this->_long;
    }
}

После создания объекта-значения понадобится класс Типа для сопоставления данных в этот объект-значение и в выражение SQL:

namespace App\Database\Type;

use App\Database\Point;
use Cake\Database\Expression\FunctionExpression;
use Cake\Database\Type as BaseType;
use Cake\Database\Type\ExpressionTypeInterface;

class PointType extends BaseType implements ExpressionTypeInterface
{
    public function toPHP($value, Driver $d)
    {
        return Point::parse($value);
    }

    public function marshal($value)
    {
        if (is_string($value)) {
            $value = explode(',', $value);
        }
        if (is_array($value)) {
            return new Point($value[0], $value[1]);
        }
        return null;
    }

    public function toExpression($value)
    {
        if ($value instanceof Point) {
            return new FunctionExpression(
                'POINT',
                [
                    $value->lat(),
                    $value->long()
                ]
            );
        }
        if (is_array($value)) {
            return new FunctionExpression('POINT', [$value[0], $value[1]]);
        }
        // Обработка других случаев.
    }
}

Вышеуказанный класс выполняет несколько интересных вещей:

  • Метод toPHP парсит результаты SQL запроса в объект-значение.
  • Метод marshal преобразовывает данные запроса в объект-значение. Здесь принимаются такие строковые значения, как '10.24,12.34 и массивы.
  • Метод toExpression обрабатывает преобразование объект-значения в эквивалент выражения SQL. В этом примере полученный в результате SQL будет выглядеть как POINT(10.24, 12.34).

Как только будет создан пользовательский тип, понадобится подключить тип к таблице классов.

Использование неизменяемых объектов DateTime

Добавлено в версии 3.2: Неизменяемые объекты date/time были добавлены в версии 3.2.

Так как объекты Date/Time легко изменить, CakePHP дает возможность использовать неизменяемые объект-значения. Наилучшим образом это можно сделать в файле config/bootstrap.php:

Type::build('datetime')->useImmutable();
Type::build('date')->useImmutable();
Type::build('time')->useImmutable();
Type::build('timestamp')->useImmutable();

Примечание

В новых приложениях неизменяемые объекты используются по умолчанию.

Классы подключений

class Cake\Database\Connection

Классы подключений предоставляют простой интерфейс для согласованного взаимодействия с соединениями базы данных. Они предназначены для более абстрактного интерфейса для слоя драйвера и предоставляют функции выполнения запросов, логирования запросов и выполнения транзакционных операций.

Выполнение запросов

Cake\Database\Connection::query($sql)

Получив объект подключения, вы вероятно захотите выполнить с ним несколько запросов. Слой абстракции базы данных CakePHP предоставляет функции обёртки поверх PDO и собственных драйверов. Данные обертки предоставляют схожий интерфейс аналогичный PDO. Существует несколько различных способов выполнения запросов в зависимости от его типа, который необходимо выполнить и того какие результаты нужны в ответ. Наиболее простой метод - query(), который позволяет запускать уже выполненные SQL запросы:

$stmt = $conn->query('UPDATE articles SET published = 1 WHERE id = 2');
Cake\Database\Connection::execute($sql, $params, $types)

Метод query() не допускает применение дополнительных параметров. Если нужны дополнительные параметры, необходимо использовать метод execute(), который дает возможность использовать шаблон для подстановки:

$stmt = $conn->execute(
    'UPDATE articles SET published = ? WHERE id = ?',
    [1, 2]
);

Без явного указания типов, execute предположит, что все подстановочные значения имеют строковый тип. Если необходимо привязать определенные типы данных, можно использовать абстрактные имена типов при создании запроса:

$stmt = $conn->execute(
    'UPDATE articles SET published_date = ? WHERE id = ?',
    [new DateTime('now'), 2],
    ['date', 'integer']
);
Cake\Database\Connection::newQuery()

Это позволяет использовать расширенные типы данных в ваших приложениях и правильно конвертировать их в SQL выражения. Последний и наиболее гибкий способ создания запросов - использование Query Builder. Данный подход позволяет сконструировать сложные и выразительные запросы без использования платформенно-ориентированного SQL:

$query = $conn->newQuery();
$query->update('articles')
    ->set(['published' => true])
    ->where(['id' => 2]);
$stmt = $query->execute();

При использовании конструктора запросов, ни один SQL запрос не будет послан на сервер базы данных до вызова метода execute() или пока запрос не будет повторён. При итерации запроса, сначала он выполняется, а затем его результатирующий набор данных будет проитерирован:

$query = $conn->newQuery();
$query->select('*')
    ->from('articles')
    ->where(['published' => true]);

foreach ($query as $row) {
    // Сделать что-нибудь со строкой.
}

Примечание

Если есть экземпляр Cake\ORM\Query, можно использовать all() для получения результатирующего набора SELECT запросов.

Использование транзакций

Объекты соединения предоставляют несколько простых способов выполнения транзакций базы данных. Наиболее простой способ выполнения - используя методы begin(), commit() и rollback(), которые преобразуются в их SQL эквиваленты:

$conn->begin();
$conn->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]);
$conn->execute('UPDATE articles SET published = ? WHERE id = ?', [false, 4]);
$conn->commit();
Cake\Database\Connection::transactional(callable $callback)

В дополнение к этим экземплярам интерфейсов соединений в том числе предоставляется метод transactional(), который делает обработку вызовов begin/commit/rollback еще проще:

$conn->transactional(function ($conn) {
    $conn->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]);
    $conn->execute('UPDATE articles SET published = ? WHERE id = ?', [false, 4]);
});

В дополнение к базовым запросам, вы можете выполнить более сложные запросы, используя Query Builder или Табличные объекты. Транзакционный метод сделает следующее:

  • Вызов begin.
  • Вызов замыкания.
  • Если замыкание выбрасывает исключение, то вызывается откат изменений. Будет выброшено первоначальное исключение.
  • Если замыкание возвращает false, будет вызван откат изменений.
  • Если замыкание выполняется успешно, транзакция будет завершена.

Взаимодействие с выражениями

При использовании нижнего уровня API базы данных, вы будете часто сталкиваться с объектами выражения. Эти объекты позволяют манипулировать подготовленными выражениями из драйвера. После создания и выполнения объекта запроса или использования execute(), у вас появится экземпляр StatementDecorator. Он оборачивает основной объект выражения и предоставляет несколько дополнительных функций.

Подготовка выражения

Вы можете создать объект выражения, используя execute() или prepare(). Метод execute() возвращает выражение с привязанными к нему значениями. При использовании prepare() возвращается неполное выражение:

// Выражения execute уже имеют связанные значения.
$stmt = $conn->execute(
    'SELECT * FROM articles WHERE published = ?',
    [true]
);

// Выражения из метода prepare будут параметрами полей для подстановки.
// Необходимо привязать параметры до того как их использовать.
$stmt = $conn->prepare('SELECT * FROM articles WHERE published = ?');

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

Привязка значений

После того как подготовленное выражение создано, можно привязть дополнительные ланные. Можно привязать множество значений сразу, используя метод bind() или привязать отдельные элементы, используя bindValue:

$stmt = $conn->prepare(
    'SELECT * FROM articles WHERE published = ? AND created > ?'
);

// Привязка множества значений
$stmt->bind(
    [true, new DateTime('2013-01-01')],
    ['boolean', 'date']
);

// Привязка одного значения
$stmt->bindValue(1, true, 'boolean');
$stmt->bindValue(2, new DateTime('2013-01-01'), 'date');

При создании выражений, можно использовать именованные ключи массива вместо индексных:

$stmt = $conn->prepare(
    'SELECT * FROM articles WHERE published = :published AND created > :created'
);

// Привязка множества значений
$stmt->bind(
    ['published' => true, 'created' => new DateTime('2013-01-01')],
    ['published' => 'boolean', 'created' => 'date']
);

// Привязка одного значения
$stmt->bindValue('published', true, 'boolean');
$stmt->bindValue('created', new DateTime('2013-01-01'), 'date');

Предупреждение

Нельзя смешивать индексные и именованные ключи массива в одном и том же выражении.

Выполнение и получение строк

После подготовки выражения и привязки к нему данных, можно выполнить его и получить строки. Выражения должны быть выполнены с использованием метода execute(). После выполнения, результаты можно получить, используя fetch(), fetchAll() или проитерировать выражение:

$stmt->execute();

// Прочитать одну строку.
$row = $stmt->fetch('assoc');

// Прочитать все строки.
$rows = $stmt->fetchAll('assoc');

// Прочитать строки путем итерации.
foreach ($stmt as $row) {
    // Выполнить задачу
}

Примечание

Считывание строк итерированием подтягивает строки в „обеих“ режимах. Это означает, что можно получить как нумерованные индексные и ассоциированные индексные результаты.

Получение количества строк

После выполнения выражения, можно получить количество затронутых строк:

$rowCount = count($stmt);
$rowCount = $stmt->rowCount();

Коды ошибок

Если запрос не был выполнен успешно, можно получить соответствующую информацию об ошибке, используя методы errorCode() и errorInfo(). Эти методы работают также, как те, что предоставляются PDO:

$code = $stmt->errorCode();
$info = $stmt->errorInfo();

Логирование запросов

Логирование запросов может быть включено при настройке соединения, установив параметр log на значение true. Также можно включить логирование запросов во время выполнения, используя enableQueryLogging:

// До 3.7.0 используйте logQueries()
// Включить логирование.
$conn->enableQueryLogging(true);

// Отключить логирование
$conn->enableQueryLogging(false);

Когда логирование запросов включено, запросы логируются в Cake\Log\Log, используя уровень „debug“ и область действия „queriesLog“. Необхоимо, чтобы логгер был настроен на этот уровень и область действия. Логирование с опцией stderr может быть полезно при работе с юнит тестами и логирование в files/syslog может быть полезно при работе с веб-запросами:

use Cake\Log\Log;

// Консольное логирование
Log::config('queries', [
    'className' => 'Console',
    'stream' => 'php://stderr',
    'scopes' => ['queriesLog']
]);

// Логирование в файле
Log::config('queries', [
    'className' => 'File',
    'path' => LOGS,
    'file' => 'queries.log',
    'scopes' => ['queriesLog']
]);

Примечание

Логирование запросов предназначено только для процесса отладки/разработки. Никогда не оставляйте логирование запросов включенным в рабочем режиме, так как это может негативно сказаться на производительности приложения.

Использование кавычек в идентификаторах

По умолчанию CakePHP не использует кавычки идентификаторов в сгенерированных SQL запросах. Причина этого заключается в том, что использование кавычек в идентификаторах имеет несколько недостатков:

  • Снижение производительности - использование кавычек в идентификаторах намного медленнее и сложнее чем их неиспользование.
  • Не нужно в большинстве случаев - в неунаследованных базах данных, которые соответствуют правилам CakePHP, нет причины использовать кавычки в идентификаторах.

Для унаследованной схемы, в которой требуются кавычки в идентификаторах, можно включить настройку quoteIdentifiers в Настройка. Эта функция включается в том числе и при выполении:

$conn->getDriver()->enableAutoQuoting();

При включенном режиме, использование кавычек в идентификаторах

Когда использование кавычек в идентификаторах включено, вызывается дополнительный проход запроса, который ковертирует все идентификаторы в объекты IdentifierExpression.

Примечание

SQL фрагменты, содержащиеся в объектах QueryExpression не изменяются.

Кэширование метаданных

Функция объектно-реляционного отображения данных CakePHP использует отражение базы данных для определения схемы, индексов и внешних ключей, которые содержит приложение. Так как эти метаданные изменяются нечасто и требуют много ресурсов при доступе, они обычно кэшируются. По умолчанию, метаданные хранятся в конфигурации кэша _cake_model_. Можно определить пользовательскую конфигурацию кэша, используя опцию cacheMetatdata в конфигурации источника данных:

'Datasources' => [
    'default' => [
        // Other keys go here.

        // Use the 'orm_metadata' cache config for metadata.
        'cacheMetadata' => 'orm_metadata',
    ]
],

В том числе можно определить конфигурацию кэширования метаданных во время выполенния с помощью метода cacheMetadata():

// Отключить кэширование
$connection->cacheMetadata(false);

// Включить кэширование
$connection->cacheMetadata(true);

// Использование пользовательской конфигурации кэширования
$connection->cacheMetadata('orm_metadata');

CakePHP вклчюает инструмент CLI для управления кэшированием метаданных. Обратитесь к разделу /console-and-shells/schema-cache для получения дополнительной информации.

Создание баз данных

Если необходимо создать соединение без выбора базы даных, можно опустить название базы данных:

$dsn = 'mysql://root:password@localhost/';

Теперь можно использовать объект соединения для выполнения запросов, которые создают/изменяют базы данных. Например, для создания базы данных:

$connection->query("CREATE DATABASE IF NOT EXISTS my_database");

Примечание

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