Уровень абстракции базы данных

Phalcon\Db является компонентом, располагающимся под Phalcon\Mvc\Model, который управляет слоем моделей в фреймворке. Он состоит из независимых абстракций высокого уровня для баз данных, полностью написанных на C.

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

Адаптеры баз данных

Этот компонент использует адаптеры для инкапсуляции определенных сведений о системе базы данных. Phalcon использует PDO для подключения к базам данных. Следующие СУБД поддерживаются:

КлассОписание
Phalcon\Db\Adapter\Pdo\Mysql Наиболее часто используемая реляционная система управления базами данных (RDBMS), которая работает как сервер, обеспечивающий многопользовательский доступ к некоторому набору баз данных.
Phalcon\Db\Adapter\Pdo\Postgresql PostgreSQL- мощная реляционная система баз данных с открытым исходным кодом. Это более чем 15 лет активного развития и проверенная архитектура, которая завоевала прочную репутацию за надежность, целостность данных и точность.
Phalcon\Db\Adapter\Pdo\Sqlite Библиотека SQLite реализует автономную, бессерверную, не требующую конфигурации и при этом поддерживающую транзакции базу данных на основе языка SQL.

Константы

Класс Phalcon\Db\Enum предоставляет ряд констант,которые можно использовать на уровне DB.

  • FETCH_ASSOC = \Pdo::FETCH_ASSOC
  • FETCH_BOTH = \Pdo::FETCH_BOTH
  • FETCH_BOUND = \Pdo::FETCH_BOUND
  • FETCH_CLASS = \Pdo::FETCH_CLASS
  • FETCH_CLASSTYPE = \Pdo::FETCH_CLASSTYPE
  • FETCH_COLUMN = \Pdo::FETCH_COLUMN
  • FETCH_FUNC = \Pdo::FETCH_FUNC
  • FETCH_GROUP = \Pdo::FETCH_GROUP
  • FETCH_INTO = \Pdo::FETCH_INTO
  • FETCH_KEY_PAIR = \Pdo::FETCH_KEY_PAIR
  • FETCH_LAZY = \Pdo::FETCH_LAZY
  • FETCH_NAMED = \Pdo::FETCH_NAMED
  • FETCH_NUM = \Pdo::FETCH_NUM
  • FETCH_OBJ = \Pdo::FETCH_OBJ
  • FETCH_PROPS_LATE = \Pdo::FETCH_PROPS_LATE
  • FETCH_SERIALIZE = \Pdo::FETCH_SERIALIZE
  • FETCH_UNIQUE = \Pdo::FETCH_UNIQUE

Дополнительные константы доступны в объекте Phalcon\Db\Column. Этот объект используется для описания столбца (или поля) в таблице базы данных. Эти константы также определяют, какие типы поддерживаются ORM.

Типы Привязки

  • BIND_PARAM_BLOB - Blob
  • BIND_PARAM_BOOL - Логический
  • BIND_PARAM_DECIMAL - Десятичный
  • BIND_PARAM_INT - Целое число
  • BIND_PARAM_NULL - Null
  • BIND_PARAM_STR - Строка
  • BIND_SKIP - Пропускать обязательные

Тип столбца

  • TYPE_BIGINTEGER - Большое целое число
  • TYPE_BIT - Bit
  • TYPE_BLOB - Blob
  • TYPE_BOOLEAN - Логический
  • TYPE_CHAR - Символ
  • TYPE_DATE - Дата
  • TYPE_DATETIME - Дата-время
  • TYPE_DECIMAL - Десятичный
  • TYPE_DOUBLE - Двойной
  • TYPE_ENUM - Перечисление
  • TYPE_FLOAT - Плавающий
  • TYPE_INTEGER - Целое число
  • TYPE_JSON - JSON
  • TYPE_JSONB - JSONB
  • TYPE_LONGBLOB - Длинный Blob
  • TYPE_LONGTEXT - Длинный текст
  • TYPE_MEDIUMBLOB - Средний Blob
  • TYPE_MEDIUMINTEGER - Среднее Целое Число
  • TYPE_MEDIUMTEXT - Средний Текст
  • TYPE_SMALLINTEGER - Малое Целое Число
  • TYPE_TEXT - Текст
  • TYPE_TIME - Время
  • TYPE_TIMESTAMP - Отметка времени
  • TYPE_TINYBLOB - Крошечный Blob
  • TYPE_TINYINTEGER - Крошечное Целое Число
  • TYPE_TINYTEXT - Крошечный Текст
  • TYPE_VARCHAR - Тип varchar

Примечание: В зависимости от вашей СУБД, некоторые типы будут недоступны (например, JSON не поддерживается для Sqlite).

Методы

public function addColumn(
    string $tableName, 
    string $schemaName, 
    ColumnInterface $column
): bool

Добавляет столбец в таблицу

public function addIndex(
    string $tableName, 
    string $schemaName,
    IndexInterface $index
): bool

Добавляет индекс к таблице

public function addForeignKey(
    string $tableName, 
    string $schemaName, 
    ReferenceInterface $reference
): bool

Добавляет внешний ключ к таблице

public function addPrimaryKey(
    string $tableName, 
    string $schemaName, 
    IndexInterface $index
): bool

Добавляет первичный ключ к таблице

public function affectedRows(): int

Возвращает количество затронутых строк по последней INSERT/UPDATE/DELETE, сообщенное системой базы данных

public function begin(
    bool $nesting = true
): bool

Запуск транзакции в соединении

public function close(): bool

Закрывает активное соединение, возвращая успех. Phalcon автоматически закрывает и уничтожает активные соединения

public function commit(
    bool $nesting = true
): bool

Фиксирует активную транзакцию в соединении

public function connect(
    array $descriptor = null
): bool

Этот метод автоматически вызывается в конструкторе Phalcon\Db\Adapter\Pdo\AbstractPdo. Вызовите его, когда вам нужно восстановить соединение с базой данных

public function createSavepoint(
    string $name
): bool

Создает новую точку сохранения

public function createTable( string $tableName, string $schemaName, array $definition ): bool

Создаёт новую таблицу.

Creates a table

```php
public function createView(
    string $viewName, 
    array $definition, 
    string $schemaName = null
): bool

Создает новый вид.

public function delete(
    mixed $table, 
    mixed $whereCondition = null, 
    mixed $placeholders = null, 
    mixed $dataTypes = null
): bool

Удаляет данные из таблицы с помощью пользовательского синтаксиса SQL СУБД

public function describeColumns(
    string $table, 
    string $schema = null
): ColumnInterface[]

Возвращает массив объектов Phalcon\Db\Column, описывающих таблицу

public function describeIndexes(
    string $table, 
        string $schema = null
): IndexInterface[]

Возвращает  список  индексов таблицы

public function describeReferences(
    string $table, 
    string $schema = null
): ReferenceInterface[]

Возвращает  список ссылок на таблицу

public function dropColumn(
    string $tableName, 
    string $schemaName, 
    string $columnName
): bool

Удаляет столбец из таблицы

public function dropForeignKey(
    string $tableName, 
    string $schemaName, 
    string $referenceName
): bool

Удаление внешнего ключа из таблицы

public function dropIndex(
    string $tableName, 
    string $schemaName, 
    string $indexName
): bool

Удаление индекса из таблицы

public function dropPrimaryKey(
    string $tableName, 
    string $schemaName
): bool

Удаление первичного ключа из таблицы

public function dropTable(
    string $tableName, 
    string $schemaName = null, 
    bool $ifExists = true
): bool

Удаление таблицы из схемы / базы данных

public function dropView(
    string $viewName, 
    string $schemaName = null, 
    bool $ifExists = true
): bool

Удаление представления.

public function escapeIdentifier(
    mixed identifier
): string

Экранирует  имя столбца/таблицы/схемы.

public function escapeString(string $str): string

Экранирует строку, чтобы избежать SQL-инъекции.

public function execute(
    string $sqlStatement, 
    mixed $placeholders = null, 
    mixed $dataTypes = null
): bool

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

public function fetchAll(
    string $sqlQuery, 
    int $fetchMode = 2, 
    mixed $placeholders = null
): array

Выводит полный результат запроса в массив

public function fetchColumn(
    string $sqlQuery, 
    array $placeholders = [], 
    mixed $column = 0
): string | bool

Возвращает n '-е поле первой строки в результате запроса SQL

// Получение количества роботов
$robotsCount = $connection->fetchColumn("SELECT count(*) FROM robots");
print_r($robotsCount);

// Получение имени последнего отредактированного робота
$robot = $connection->fetchColumn(
     "SELECT id, name FROM robots order by modified desc",
     1
 );
 print_r($robot);

 

public function fetchOne(
    string $sqlQuery, 
    int $fetchMode = 2, 
    mixed $placeholders = null
): array

Возвращает первую строку в результате запроса SQL

public function forUpdate(
    string $sqlQuery
): string

Возвращает SQL, измененный с параметром FOR UPDATE

public function getColumnDefinition(
    ColumnInterface $column
): string

Возвращает определение столбца SQL из столбца

public function getColumnList(
    mixed $columnList
): string

Получение списка столбцов

public function getConnectionId(): string

Получение уникального идентификатора активного подключения

public function getDescriptor(): array

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

public function getDialect(): DialectInterface

Возвращает экземпляр внутреннего диалекта

public function getDialectType(): string

Возвращает название используемого диалекта

public function getDefaultIdValue(): RawValue

Возвращает значение идентификатора по умолчанию для вставки в столбец идентификаторов

public function getInternalHandler(): \PDO

Возвращает внутренний обработчик PDO

public function getNestedTransactionSavepointName(): string

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

public function getRealSQLStatement(): string

Активный оператор SQL в объекте без привязки параметров replace

public function getSQLStatement(): string

Активный оператор SQL в объекте

public function getSQLBindTypes(): array

Активный оператор SQL в объекте

public function getSQLVariables(): array

Активный оператор SQL в объекте

public function getType(): string

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

public function insert(
    string $table, 
    array $values, 
    mixed $fields = null, 
    mixed $dataTypes = null
): bool

Вставка данных в таблицу с использованием пользовательского синтаксиса SQL СУБД

public function insertAsDict(
    string $table, 
    mixed $data, 
    mixed $dataTypes = null
): bool

Вставка данных в таблицу с использованием пользовательского синтаксиса RBDM SQL

// Вводить новый счет
$success = $connection->insertAsDict(
    'co_invoices',
    [
        'inv_cst_id' => 1,
        'inv_title'  => 'Invoice for ACME Inc.',
    ]
)

// Следующее предложение SQL отправляется в систему базы данных
INSERT INTO `co_invoices` 
    ( `inv_cst_id`, `inv_title` ) 
VALUES 
    ( 1, 'Invoice for ACME Inc.' )
public function isNestedTransactionsWithSavepoints(): bool

Возвращает, если вложенные транзакции должны использовать точки сохранения

public function isUnderTransaction(): bool

Проверяет, находится ли соединение в транзакции

public function lastInsertId(
    mixed $sequenceName = null
)

Возвращает идентификатор вставки для столбца auto_increment, вставленного в последнюю инструкцию SQL

public function limit(
    string $sqlQuery, 
    int $number
): string

Добавляет предложение LIMIT к аргументу sqlQuery

public function listTables(
    string $schemaName = null
): array

Список всех таблиц в базе данных

public function listViews(
    string $schemaName = null
): array

Список всех представлений в базе данных

public function modifyColumn(
    string $tableName, 
    string $schemaName, 
    ColumnInterface $column, 
    ColumnInterface $currentColumn = null
): bool

Изменяет столбец таблицы на основе определения

public function query(
    string $sqlStatement, 
    mixed $placeholders = null, 
    mixed $dataTypes = null
): ResultInterface | bool

Отправляет инструкции SQL на сервер базы данных, возвращая состояние успешного выполнения. Используйте этот метод только тогда, когда инструкция SQL, отправленная на сервер, возвращает строки

public function releaseSavepoint(
    string $name
): bool

Релизы с заданной точкой сохранения

public function rollback(
    bool $nesting = true
): bool

Откаты активной транзакции в соединении

public function rollbackSavepoint(
    string $name
): bool

Возвращает SQL, измененный предложением LOCK IN SHARE MODE

public function setNestedTransactionsWithSavepoints(
    bool $nestedTransactionsWithSavepoints
): AdapterInterface

Установить, должны ли вложенные транзакции использовать точки сохранения

public function supportSequences(): bool

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

public function tableExists(
    string $tableName, 
    string $schemaName = null
): bool

Генерирует SQL-проверку на наличие схемы.стол

public function tableOptions(
    string $tableName, 
    string $schemaName = null
): array

Получает параметры создания из таблицы

public function update(
    string $table, 
    mixed $fields, 
    mixed $values, 
    mixed $whereCondition = null, 
    mixed $dataTypes = null
): bool

Обновление данных в таблице с использованием пользовательского синтаксиса SQL СУБД

public function updateAsDict(
    string $table, 
    mixed $data, 
    mixed $whereCondition = null, 
    mixed $dataTypes = null
): bool

Обновляет данные в таблице с помощью пользовательского синтаксиса RBDM SQL. Другой, более удобный синтаксис

// Обновление существующего счета-фактуры
$success = $connection->updateAsDict(
    'co_invoices',
    [
        'inv_title' => 'Invoice for ACME Inc.',
    ],
    'inv_id = 1'
)

// Следующее предложение SQL отправляется в систему базы данных
UPDATE `co_invoices` 
SET    `inv_title` = 'Invoice for ACME Inc.' 
WHERE   inv_id = 1
public function useExplicitIdValue(): bool

Проверяет, требуется ли системе базы данных явное значение для столбцов идентификаторов

public function viewExists(
    string $viewName, 
    string $schemaName = null
): bool

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

Пользовательский адаптер

Интерфейс Phalcon\Db\Adapter\AdapterInterface должен быть реализован для создания собственных адаптеров баз данных или расширения существующих. Кроме того, вы можете расширить Phalcon\Db\Adapter\AbstractAdapter, который уже имеет некоторую реализацию для вашего пользовательского адаптера.

Экранирование

Экранирование идентификаторов включено по умолчанию. Однако если вам нужно отключить эту функцию, вы можете сделать это с помощью метода setup():

<?php

\Phalcon\Db::setup(
    [
        'escapeIdentifiers' => false,
    ]
);

Фабрика

newInstance()

Хотя все классы адаптеров могут быть созданы с помощью ключевого слова new, Phalcon предлагает класс Phalcon\Db\Adapter\PdoFactory , так что вы можете легко создавать экземпляры адаптеров PDO. Все вышеперечисленные адаптеры зарегистрированы на заводе и лениво загружаются при вызове. Фабрика позволяет регистрировать дополнительные (пользовательские) классы адаптеров. Единственное, что нужно учитывать, - это выбор названия адаптера по сравнению с существующими. Если вы определяете одно и то же имя, вы перезапишете встроенное. Объекты кэшируются на заводе, поэтому, если вы вызовете метод newInstance() с теми же параметрами во время того же запроса, вы получите тот же объект обратно.

Зарезервированные имена::

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

<?php

use Phalcon\Db\Adapter\Pdo\MySQL;

$connection = new MySQL(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => '',
        'dbname'   => 'test',
    ]
);
<?php

use Phalcon\Db\Adapter\Pdo\PdoFactory;

$factory    = PdoFactory();
$connection = $factory
    ->newInstance(
        'mysql',
        [
            'host'     => 'localhost',
            'username' => 'root',
            'password' => '',
            'dbname'   => 'test',
        ]
    )
;

load()

Вы также можете использовать метод load() для создания адаптера с помощью объекта конфигурации или массива. В приведенном ниже примере используется ini -файл для создания экземпляра подключения к базе данных с помощью load().

[database]
host = TEST_DB_MYSQL_HOST
username = TEST_DB_MYSQL_USER
password = TEST_DB_MYSQL_PASSWD
dbname = TEST_DB_MYSQL_NAME
port = TEST_DB_MYSQL_PORT
charset = TEST_DB_MYSQL_CHARSET
adapter = mysql
<?php

use Phalcon\Config\Adapter\Ini;
use Phalcon\Di;
use Phalcon\Db\Adapter\Pdo\Factory;

$container = new Di();

$config = new Ini('config.ini');

$container->set('config', $config);

$container->set(
    'db', 
    function () {
        return (new Factory())->load($this->config->database);
    }
);

Диалекты

Встроенный

Phalcon инкапсулирует конкретные детали каждого компонента database engine в диалектах.  Phalcon\Db\Dialect предоставляет адаптерам общие функции и генератор SQL.

КлассОписание
Phalcon\Db\Dialect\Mysql Специфический диалект SQL для системы баз данных MySQL
Phalcon\Db\Dialect\Postgresql Специфический диалект SQL для системы баз данных PostgreSQL
Phalcon\Db\Dialect\Sqlite Специфический диалект SQL для системы баз данных SQLite

Пользовательский диалект

С помощью Phalcon интерфейса Phalcon\Db\DialectInterface должны быть реализованы для того, чтобы создавать свои собственные диалекты базу или расширить уже существующие. Вы также можете улучшить свой текущий диалект, добавив больше команд / методов, которые поймет PHQL. Например, при использовании адаптера MySQL, вы, возможно, захотите, чтобы PHQL признать MATCH ... AGAINST ... синтаксис. Мы связываем этот синтаксис с MATCH_AGAINST

Мы создаем экземпляр диалекта. Мы добавляем пользовательскую функцию, чтобы PHQL понимал, что делать, когда он находит ее в процессе синтаксического анализа. В приведенном ниже примере мы регистрируем новую пользовательскую функциюMATCH_AGAINST. После этого все, что нам нужно сделать, это добавить настроенный объект диалекта в наше соединение.

<?php

use Phalcon\Db\Dialect\MySQL as SqlDialect;
use Phalcon\Db\Adapter\Pdo\MySQL as Connection;

$dialect = new SqlDialect();

$dialect->registerCustomFunction(
    'MATCH_AGAINST',
    function ($dialect, $expression) {
        $arguments = $expression['arguments'];
        return sprintf(
            ' MATCH (%s) AGAINST (%)',
            $dialect->getSqlExpression($arguments[0]),
            $dialect->getSqlExpression($arguments[1])
         );
    }
);

$connection = new Connection(
    [
        'host'          => 'localhost',
        'username'      => 'root',
        'password'      => '',
        'dbname'        => 'test',
        'dialectClass'  => $dialect,
    ]
);

Теперь мы можем использовать эту новую функцию в PHQL, которая, в свою очередь, переведет ее на правильный синтаксис SQL:

<?php

$phql = '
  SELECT *
  FROM   Invoices
  WHERE  MATCH_AGAINST(title, :pattern:)';
  
$posts = $modelsManager->executeQuery(
    $phql,
    [
        'pattern' => $pattern,
    ]
);

Примечание: существует больше примеров о том, как расширить PHQL в документе PHQL.

Подключить

Для создания соединения необходимо создать экземпляр класса adapter. Для этого требуется только массив с параметрами подключения. В приведенном ниже примере показано, как создать соединение, передающее как обязательные, так и необязательные параметры:

АдаптерПараметрСтатус
MySQL host обязательный
  username обязательный
  password обязательный
  dbname обязательный
  persistent необязательный
PostgreSQL host обязательный
  username обязательный
  password обязательный
  dbname обязательный
  schema необязательный
Sqlite dbname обязательный

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

<?php

use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\Db\Adapter\Pdo\Postgresql;
use Phalcon\Db\Adapter\Pdo\Sqlite;

$config = [
    'host'     => '127.0.0.1',
    'username' => 'mike',
    'password' => 'sigma',
    'dbname'   => 'test_db',
];

$connection = new Mysql($config);

$config = [
    'host'     => 'localhost',
    'username' => 'postgres',
    'password' => 'secret1',
    'dbname'   => 'template',
];

$connection = new Postgresql($config);

$config = [
    'dbname' => '/path/to/database.db',
];
$connection = new Sqlite($config);

Дополнительные опции PDO

Вы можете установить параметры PDO во время подключения, передав параметры options:

<?php

use Phalcon\Db\Adapter\Pdo\Mysql;

$connection = new Mysql(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'sigma',
        'dbname'   => 'test_db',
        'options'  => [
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
            PDO::ATTR_CASE               => PDO::CASE_LOWER,
        ]
    ]
);

Создание.

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

<?php

$sql     = "
INSERT INTO `co_invoices` 
    ( `inv_cst_id`, `inv_title` ) 
VALUES 
    ( 1, 'Invoice for ACME Inc.' )
";
$success = $connection->execute($sql);

Raw SQL

<?php

$sql     = '
INSERT INTO `co_invoices` 
    ( `inv_cst_id`, `inv_title` ) 
VALUES 
    ( ?, ? )
';
$success = $connection->execute(
    $sql,
    [
        1,
        'Invoice for ACME Inc.',
    ]
);

Подстановки

<?php

$success = $connection->insert(
    'co_invoices',
    [
        1,
        'Invoice for ACME Inc.',
    ],
    [
        'inv_cst_id',
        'inv_title', 
    ]
);

Динамическая генерация

<?php

$success = $connection->insertAsDict(
    'co_invoices',
    [
        'inv_cst_id' => 1,
        'inv_title'  => 'Invoice for ACME Inc.',
    ]
);

Динамическая генерация (альтернативный синтаксис)

Обновление

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

<?php

$sql     = "
UPDATE 
    `co_invoices` 
SET 
    `inv_cst_id`= 1, 
    `inv_title` = 'Invoice for ACME Inc.'
WHERE
    `inv_id` = 4
";
$success = $connection->execute($sql);

Raw SQL

<?php

$sql     = "
UPDATE 
    `co_invoices` 
SET 
    `inv_cst_id`= ?, 
    `inv_title` = ?
WHERE
    `inv_id` = ?
";
$success = $connection->execute(
    $sql,
    [
        1,
        'Invoice for ACME Inc.',
        4,
    ]
);
<?php

$sql     = "
UPDATE 
    `co_invoices` 
SET 
    `inv_cst_id`= ?, 
    `inv_title` = ?
WHERE
    `inv_id` = ?
";
$success = $connection->execute(
    $sql,
    [
        1,
        'Invoice for ACME Inc.',
        4,
    ]
);

Подстановки

<?php

$success = $connection->update(
    'co_invoices',
    [
        'inv_cst_id',
        'inv_title',
    ],
    [
        1,
        'Invoice for ACME Inc.',
    ],
    'inv_id = 4'
);

Динамическая генерация

Примечание: с синтаксисом выше, переменные для where части update (inv_id = 4) не экранируются!

<?php

$success = $connection->updateAsDict(
    'co_invoices',
    [
        'inv_cst_id' => 1,
        'inv_title'  => 'Invoice for ACME Inc.',
    ],
    'inv_id = 4'
);

Динамическая генерация (альтернативный синтаксис)

Примечание: с синтаксисом выше, переменные для where части update (inv_id = 4) не экранируются!

<?php

$success = $connection->update(
    'co_invoices',
    [
        'inv_cst_id',
        'inv_title',
    ],
    [
        1,
        'Invoice for ACME Inc.',
    ],
    [
        'conditions' => 'id = ?',
        'bind'       => [
            4
        ],
        'bindTypes'  => [
            \PDO::PARAM_INT
        ],
    ]
);

С экранированными символами

<?php

$success = $connection->updateAsDict(
    'co_invoices',
    [
        'inv_cst_id' => 1,
        'inv_title'  => 'Invoice for ACME Inc.',
    ],
    [
        'conditions' => 'id = ?',
        'bind'       => [
            4
        ],
        'bindTypes'  => [
            \PDO::PARAM_INT
        ],
    ]
);

С экранированными символами (альтернативный синтаксис)

Удалить

<?php

$sql     = '
DELETE 
   `co_invoices` 
WHERE
   `inv_id` = 4
';
$success = $connection->execute($sql);

Raw SQL

<?php

$sql     = '
DELETE 
   `co_invoices` 
WHERE
   `inv_id` = ?
';
$success = $connection->execute(
    $sql, 
    [
        4
    ]
);

Подстановки

<?php

$success = $connection->delete(
    'co_invoices',
    'inv_id = ?',
    [
        4,
    ]
);

Динамическая генерация

Параметры

Адаптеры Phalcon\Db предоставляют несколько методов для запроса строк из таблиц. В этом случае требуется определенный синтаксис SQL целевого компонента database engine:

<?php

$sql = '
SELECT 
    inv_id,
    inv_title
FROM 
    co_invoices
ORDER BY 
    inv_created_at
';
$result = $connection->query($sql);
while ($invoice = $result->fetch()) {
   echo $invoice['inv_title'];
}

$invoices = $connection->fetchAll($sql);
foreach ($invoices as $invoice) {
   echo $invoice['inv_title'];
}

$invoice = $connection->fetchOne($sql);

По умолчанию эти вызовы создают массивы как с ассоциативными, так и с числовыми индексами. Это поведение можно изменить с помощью функции Phalcon\Db\Result::setFetchMode(). Этот метод получает константу, определяющую, какой тип индекса требуется.

ПостоянныйОписание
Phalcon\Db\Enum::FETCH_NUM Возвращает массив с числовыми индексами
Phalcon\Db\Enum::FETCH_ASSOC Возвращает массив с ассоциативными индексами
Phalcon\Db\Enum::FETCH_BOTH Возвращает массив с ассоциативными и числовыми индексами
Phalcon\Db\Enum::FETCH_OBJ Возвращает объект вместо массива
<?php

$sql = '
SELECT 
    inv_id,
    inv_title
FROM 
    co_invoices
ORDER BY 
    inv_created_at
';
$result = $connection->query($sql);

$result->setFetchMode(
    Phalcon\Db\Enum::FETCH_NUM
);

while ($invoice = $result->fetch()) {
   echo $invoice[0];
}

Метод query() возвращает экземпляр Phalcon\Db\Result\Pdo. Эти объекты инкапсулируют всю функциональность, связанную с возвращаемым результирующим набором, т. е. обход, поиск определенных записей, подсчет и т. д.

<?php

$sql = '
SELECT 
    inv_id,
    inv_title
FROM 
    co_invoices
ORDER BY 
    inv_created_at
';
$result = $connection->query($sql);

while ($invoice = $result->fetch()) {
   echo $invoice['name'];
}

$result->seek(2);

$invoice = $result->fetch();

echo $result->numRows();

Связывание

Привязанные параметры также поддерживаются. Хотя использование связанных параметров оказывает минимальное влияние на производительность, настоятельно рекомендуется использовать эту методологию, чтобы исключить возможность того, что ваш код будет подвержен атакам SQL-инъекций. Поддерживаются как строковые, так и позиционные заполнители.

<?php

$sql = '
SELECT 
    inv_id,
    inv_title
FROM 
    co_invoices
WHERE
    inv_cst_id = ?
ORDER BY 
    inv_created_at
';

$result = $connection->query(
    $sql,
    [
        4,
    ]
);

Привязка с числовыми заполнителями

<?php

$sql     = "
UPDATE 
    `co_invoices` 
SET 
    `inv_cst_id`= :cstId, 
    `inv_title` = :title
WHERE
    `inv_id` = :id
";
$success = $connection->query(
    $sql,
    [
        'cstId' => 1,
        'title' => 'Invoice for ACME Inc.',
        'id'    => 4,
    ]
);

Привязка с именованными местозаполнителями

При использовании числовых заполнителей вам нужно будет определить их как целые числа, т. е.  1 или 2. В этом случае '1' или '2' или ' 2 ' считаются строками, а не числами, поэтому заполнитель не может быть успешно заменен. С любым адаптером данные автоматически экранируются с помощью PDO Quote. Эта функция учитывает кодировку соединения, поэтому рекомендуется определить правильную кодировку в параметрах соединения или в конфигурации сервера базы данных, так как неправильная кодировка приведет к нежелательным последствиям при хранении или извлечении данных.

Кроме того, вы можете передать свои параметры непосредственно в методы execute или query. В этом случае привязанные параметры передаются непосредственно в PDO:

<?php

$sql = '
SELECT 
    inv_id,
    inv_title
FROM 
    co_invoices
WHERE
    inv_cst_id = ?
ORDER BY 
    inv_created_at
';

$result = $connection->query(
    $sql,
    [
        1 => 4,
    ]
);

Связывание с заполнителями PDO

Типизация

Заполнители позволяют привязывать параметры, чтобы избежать SQL-инъекций:

<?php

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_cst_id = :customerId:
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'customerId' => 4,
        ]
    )
;

Однако некоторые системы баз данных требуют дополнительных действий при использовании заполнителей, таких как указание типа связанного параметра:

<?php

use Phalcon\Db\Column;

// ...

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_cst_id = :customerId:
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'customerId' => 4,
        ],
        Column::BIND_PARAM_INT
    )
;
<?php

use Phalcon\Db\Column;

// ...

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_cst_id = :customerId:
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'customerId' => 4,
        ],
        Column::BIND_PARAM_INT
    )
;

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

<?php

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_cst_id = {customerId:int}
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'customerId' => 4,
        ],
    )
;

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_title <> {title:str}
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'title' => 'Invoice for ACME Inc',
        ],
    )
;

Вы также можете опустить тип, если вам не нужно его указывать:

<?php

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_cst_id = {customerId}
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'customerId' => 4,
        ],
    )
;

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

<?php

$phql = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
WHERE
    inv_cst_id IN ({ids:array})
ORDER BY 
    inv_created_at
';

$invoices = $this
    ->modelsManager
    ->executeQuery(
        $phql,
        [
            'ids' => [1, 3, 5],
        ],
    )
;

Доступны следующие типы:

Тип ПривязкиКонстанта Типа ПривязкиПример
str Column::BIND_PARAM_STR {name:str}
int Column::BIND_PARAM_INT {number:int}
double Column::BIND_PARAM_DECIMAL {price:double}
bool Column::BIND_PARAM_BOOL {enabled:bool}
blob Column::BIND_PARAM_BLOB {image:blob}
null Column::BIND_PARAM_NULL {exists:null}
array Array of Column::BIND_PARAM_STR {codes:array}
array-str Array of Column::BIND_PARAM_STR {names:array-str}
array-int Array of Column::BIND_PARAM_INT {flags:array-int}

Cast

По умолчанию привязанные параметры не приводятся в поле пользователя PHP к указанным типам привязки. Эта опция позволяет делать значения Phalcon cast перед привязкой их с PDO. Распространенным сценарием является передача строки в местозаполнитель LIMIT/OFFSET:

<?php

$number = '100';
$phql   = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
LIMIT 
    {number:int}
';

$invoices = $modelsManager->executeQuery(
    $phql,
    [
        'number' => $number,
    ]
);

Это приводит к следующему исключению:

Fatal error: Uncaught exception 'PDOException' with message 
'SQLSTATE[42000]: Syntax error or access violation: 1064. 
You have an error in your SQL syntax; check the manual that 
corresponds to your MySQL server version for the right
syntax to use near ''100'' at line 1' in ....

Это происходит потому, что '100' является строковой переменной. Он легко фиксируется путем ввода значения в целое число:

<?php

$number = '100';
$phql   = '
SELECT 
    inv_id,
    inv_title
FROM 
    Invoices
LIMIT 
    {number:int}
';

$invoices = $modelsManager->executeQuery(
    $phql,
    [
        'number' => (int) $number,
    ]
);

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

<?php

\Phalcon\Db::setup(
    [
        'forceCasting' => true,
    ]
);

Следующие действия выполняются в соответствии с указанным типом привязки:

Тип ПривязкиДействие
Column::BIND_PARAM_STR Приведение значения в виде собственной строки PHP
Column::BIND_PARAM_INT Приведение значения в виде собственного целого числа PHP
Column::BIND_PARAM_BOOL Приведение значения как собственное логическое значение PHP
Column::BIND_PARAM_DECIMAL Привести значение как собственный PHP-двойная

Гидратация

Значения, возвращаемые из системы баз данных, всегда представляются PDO в виде строковых значений, независимо от того, принадлежит ли значение столбцу типа numeric или boolean. Это происходит потому, что некоторые типы столбцов не могут быть представлены соответствующими собственными типами PHP из-за их ограничений по размеру. Например, BIGINT в MySQL может хранить большие целые числа, которые не могут быть представлены как 32-битное целое число в PHP. Поэтому PDO и ORM по умолчанию принимают безопасное решение оставить все значения в виде строк.

Вы можете настроить ORM для автоматического приведения этих типов к соответствующим собственным типам PHP:

<?php

use Phalcon\Mvc\Model;

Model::setup(
    [
        'castOnHydrate' => true,
    ]
);

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

<?php

$invoice = Invoices::findFirst();
if (11 === $invoice->inv_id) {
    echo $invoice->inv_title;
}

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

<?php

$invoice = Invoices::findFirst();
if (11 === $invoice->inv_id) {
    echo $invoice->inv_title;
}

Примечание: Если вы хотите вернуть первичный ключ при использовании lastInsertId в качестве integer, вы можете использовать функцию castLastInsertIdToInt => true в модели.

Транзакции

Работа с транзакциями поддерживается так же, как и с PDO. Использование транзакций повышает производительность в большинстве систем баз данных, а также обеспечивает целостность данных:

<?php

try {
    $connection->begin();

    $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 1');
    $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 2');
    $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 3');

    $connection->commit();
} catch (Exception $e) {
    $connection->rollback();
}

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

<?php

try {
    $connection->begin();

    $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 1');

    try {
        $connection->begin();

        $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 2');
        $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 3');

        $connection->commit();
    } catch (Exception $e) {
        $connection->rollback();
    }

    $connection->execute('DELETE `co_invoices` WHERE `inv_id` = 4');

    $connection->commit();
} catch (Exception $e) {
    // Произошло исключение откат транзакции
    $connection->rollback();
}

События

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

Имя событияТригирыМожно остановить
afterQuery После выполнения запроса Нет
beforeQuery Перед выполнением запроса Да
beginTransaction Прежде чем транзакция начинается Нет
createSavepoint Перед созданием точки сохранения Нет
commitTransaction Перед совершением транзакции Нет
releaseSavepoint Перед освобождением точки сохранения Нет
rollbackTransaction Прежде чем транзакция откатывается Нет
rollbackSavepoint Перед откатом точки сохранения Нет

Если вы свяжете Диспетчер событий с подключением к базе данных, все события с типом db будут включены и запущены для соответствующих слушателей.

<?php

use Phalcon\Events\Manager;
use Phalcon\Db\Adapter\Pdo\Mysql;

$manager = new Manager();

$manager->attach('db', $listener);

$connection = new Mysql(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'secret',
        'dbname'   => 'tutorial',
    ]
);

$connection->setEventsManager($manager);

Вы можете использовать силу этих событий, чтобы защитить ваше приложение от опасных операций SQL.

<?php

use Phalcon\Events\Event;

$manager->attach(
    'db:beforeQuery',
    function (Event $event, $connection) {
        $sql = $connection->getSQLStatement();

        if (true === preg_match('/DROP|ALTER/i', $sql)) {
            return false;
        }

        return true;
    }
);
<?php

use Phalcon\Events\Event;

$manager->attach(
    'db:beforeQuery',
    function (Event $event, $connection) {
        $sql = $connection->getSQLStatement();

        if (true === preg_match('/DROP|ALTER/i', $sql)) {
            return false;
        }

        return true;
    }
);

Профилирование

Адаптер включает компонент Phalcon\Db\Profiler, который используется для анализа производительности операций с базами данных с целью диагностики проблем производительности и обнаружения узких мест.

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Db\Profiler;

$manager  = new Manager();
$profiler = new Profiler();

$manager->attach(
    'db',
    function (Event $event, $connection) use ($profiler) {
        if ($event->getType() === 'beforeQuery') {
            $sql = $connection->getSQLStatement();
            $profiler->startProfile($sql);
        }

        if ($event->getType() === 'afterQuery') {
            $profiler->stopProfile();
        }
    }
);

$connection->setEventsManager($manager);

$sql = '
SELECT 
    inv_id,
    inv_title
FROM 
    co_invoices
';
$connection->query($sql);

$profile = $profiler->getLastProfile();

echo 'SQL Statement: ', $profile->getSQLStatement(), PHP_EOL,
     'Start Time: ', $profile->getInitialTime(), PHP_EOL,
     'Final Time: ', $profile->getFinalTime(), PHP_EOL,
     'Total Elapsed Time: ', $profile->getTotalElapsedSeconds(), PHP_EOL;

Вы также можете создать свой собственный класс профиля на основе класса Phalcon\Db\Profiler для записи статистики операторов в реальном времени, отправляемых в базу данных:

<?php

use Phalcon\Events\Manager;
use Phalcon\Db\Profiler;
use Phalcon\Db\Profiler\Item;

class DbProfiler extends Profiler
{
    public function beforeStartProfile(Item $profile)
    {
        echo $profile->getSQLStatement();
    }

    public function afterEndProfile(Item $profile)
    {
        echo $profile->getTotalElapsedSeconds();
    }
}

$manager  = new Manager();
$listener = new DbProfiler();

$manager->attach('db', $listener);

Регистрация

Использование высокоуровневых компонентов абстракции, таких как адаптеры Phalcon\Db для доступа к базе данных, затрудняет понимание того, какие операторы отправляются в систему базы данных. Компонент Phalcon\Logger взаимодействует с адаптерами Phalcon\Db, предлагая возможности ведения журнала на уровне абстракции базы данных.

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Logger;
use Phalcon\Logger\Adapter\Stream;

$adapter = new Stream('/storage/logs/queries.log');
$logger  = new Logger(
    'messages',
    [
        'main' => $adapter,
    ]
);

$manager = new Manager();

$manager->attach(
    'db:beforeQuery',
    function (Event $event, $connection) use ($logger) {
        $sql = $connection->getSQLStatement();

        $logger->info(
            sprintf(
                '%s - [%s]',
                $connection->getSQLStatement(),
                json_encode($connection->getSQLVariables())
            )
        );
    }
);

$connection->setEventsManager($manager);

$connection->insert(
    'products',
    [
        'Hot pepper',
        3.50,
    ],
    [
        'name',
        'price',
    ]
);
$connection->insert(
    'co_invoices',
    [
        1,
        'Invoice for ACME Inc.',
    ],
    [
        'inv_cst_id',
        'inv_title', 
    ]
);

Как и выше, файл /storage/logs/queries.log будет содержать что-то вроде этого:

[2019-12-25 01:02:03][INFO] INSERT INTO `co_invoices` 
    SET (`inv_cst_id`, `inv_title`) 
    VALUES (1, 'Invoice for ACME Inc.')

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

[2019-12-25 01:02:03][INFO] SELECT `co_customers`.`cst_id`, 
    ...,
    FROM `co_customers` 
    WHERE LOWER(`co_customers`.`cst_email`) = :cst_email 
    LIMIT :APL0 - [{"emp_email":"team@phalcon.ld","APL0":1}]

Таблицы

Описание

Адаптеры Phalcon\Db также предоставляют методы для получения подробной информации о таблицах и представлениях:

<?php

$tables = $connection->listTables('gonano');

Получить таблицы в базе данных gonano

<?php

$exists = $connection->tableExists('co_invoices');

Проверить, есть ли в базе данных таблица с именем co_invoices?

<?php

$fields = $connection->describeColumns('co_invoices');
foreach ($fields as $field) {
    echo 'Column Type: ', $field['Type'];
}

Печать имени и типов данных таблицы co_invoices

<?php

$indexes = $connection->describeIndexes('co_invoices');
foreach ($indexes as $index) {
    print_r(
        $index->getColumns()
    );
}

Печать индексов в таблице co_invoices

<?php

$references = $connection->describeReferences('co_invoices');
foreach ($references as $reference) {
    print_r(
        $reference->getReferencedColumns()
    );
}

Печать внешних ключей в таблице co_invoices

Описание таблицы очень похоже на команду MySQL DESCRIBE, она содержит следующую информацию:

FieldTypeKeyNull
Имя поля тип столбца Является ли столбец частью первичного ключа или индекса? Допускает ли столбец нулевые значения?

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

<?php

$tables = $connection->listViews('gonano');

Получить представление о базе данных gonano

<?php

$exists = $connection->viewExists('vw_invoices');

Check if there is a view vw_invoices in the database

Создавать

Различные системы баз данных (MySQL, Postgresql и др.) возможность создавать, изменять или удалять таблицы с помощью таких команд, как CREATE, ALTER или DROP. Синтаксис SQL отличается в зависимости от того, какая система баз данных используется. Phalcon\Db adapters предлагает унифицированный интерфейс для изменения таблиц, без необходимости дифференцировать синтаксис SQL на основе целевой системы хранения.

<?php

use \Phalcon\Db\Column as Column;

$connection->createTable(
    'co_invoices',
    null,
    [
       'columns' => [
            new Column(
                'inv_id',
                [
                    'type'          => Column::TYPE_INTEGER,
                    'size'          => 10,
                    'notNull'       => true,
                    'autoIncrement' => true,
                    'primary'       => true,
                ]
            ),
            new Column(
                'inv_cst_id',
                [
                    'type'    => Column::TYPE_INTEGER,
                    'size'    => 11,
                    'notNull' => true,
                ]
            ),
            new Column(
                'inv_title',
                [
                    'type'    => Column::TYPE_VARCHAR,
                    'size'    => 100,
                    'notNull' => true,
                ]
            ),
        ]
    ]
);

Метод createTable принимает ассоциативный массив, описывающий таблицу. Столбцы определяются с помощью класса Phalcon\Db\Column. В таблице ниже приведены параметры, доступные для определения столбца:

ВариантОписаниеНеобязательный
after Столбец должен быть размещен после указанного столбца Да
autoIncrement Укажите, будет ли этот столбец автоматически приращен базой данных. Только один столбец в таблице может иметь этот атрибут. Да
bind Одна из констант BIND_TYPE_ *, указывающая, как столбец должен быть привязан перед сохранением Да
default Значение по умолчанию (при использовании с 'notNull' => true). Да
first Столбец должен быть помещен в первую позицию порядка столбцов Да
notNull Столбец может хранить значения NULL Да
primary true Если столбец является частью первичного ключа таблицы Да
scale Столбцы DECIMAL или NUMBER могут иметь масштаб, указывающий, сколько десятичных знаков должно храниться Да
size Некоторые типы столбцов, такие как VARCHAR или INTEGER, могут иметь определенный размер Да
type Тип колонки. Должна быть константой Phalcon\Db\Column (список см. ниже) Нет
unsigned Столбцы INTEGER могут быть signed или unsigned. Этот параметр не применяется к столбцам других типов Да

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

  • Phalcon\Db\Column::TYPE_INTEGER
  • Phalcon\Db\Column::TYPE_DATE
  • Phalcon\Db\Column::TYPE_VARCHAR
  • Phalcon\Db\Column::TYPE_DECIMAL
  • Phalcon\Db\Column::TYPE_DATETIME
  • Phalcon\Db\Column::TYPE_CHAR
  • Phalcon\Db\Column::TYPE_TEXT

Ассоциативный массив, переданный в createTable (), может иметь следующие ключи:

ИндексОписаниеНеобязательный
columns Массив со столбцами, определенными с помощью Phalcon\Db\Column Нет
indexes Массив с индексами, определенными с помощью Phalcon\Db\Index Да
references Массив со ссылками (внешними ключами), определенный с помощью Phalcon\Db\Reference Да
options Массив с опциями создания. (Для системы базы данных) Да

Изменять

По мере роста приложения может потребоваться изменить базу данных в рамках рефакторинга или добавления новых функций. Не все системы баз данных позволяют изменять существующие столбцы или добавлять столбцы между двумя существующими. Phalcon\Db\Column ограничен этими ограничениями.

Ниже приведен пример создания таблицы:

<?php

use Phalcon\Db\Column as Column;

$connection->addColumn(
    'co_invoices',
    null,
    new Column(
        'inv_status_flag',
        [
            'type'    => Column::TYPE_INTEGER,
            'size'    => 1,
            'notNull' => true,
            'default' => 0,
            'after'   => 'inv_cst_id',
        ]
    )
);


$connection->modifyColumn(
    'co_invoices',
    null,
    new Column(
        'inv_status_flag',
        [
            'type'    => Column::TYPE_INTEGER,
            'size'    => 2,
            'notNull' => true,
        ]
    )
);

$connection->dropColumn(
    'co_invoices',
    null,
    'inv_status_flag'
);

Удаление

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

<?php

$connection->dropTable('co_invoices');

Удаление таблицы co_invoices из активной базы данных

<?php

$connection->dropTable('co_invoices', 'gonano');

Удалить таблицу co_invoices из базы данных gonano

Никаких мыслей по поводу “01 Уровень абстракции базы данных”