Spec-Zone.ru › Phalcon 2

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

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

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

Это руководство не является полным описанием доступных методов и их аргументов. Для получения полной справки, пожалуйста, посетите API.

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

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

Имя Описание API
MySQL Самая используемая в мире реляционная система управления базами данных (СУБД), работающая как сервер, предоставляющий многопользовательский доступ к нескольким базам данных. Phalcon\Db\Adapter\Pdo\Mysql
PostgreSQL PostgreSQL — мощная, свободная реляционная система управления базами данных. Она имеет более чем 15 лет активного развития и проверенную архитектуру, что обеспечило ей сильную репутацию надежности, целостности данных и корректности. Phalcon\Db\Adapter\Pdo\Postgresql
SQLite SQLite — библиотека программного обеспечения, которая реализует автономный, бессерверный, безконфигурационный транзакционный движок SQL-базы данных. Phalcon\Db\Adapter\Pdo\Sqlite
Oracle Oracle — объектно-реляционная система управления базами данных, разработанная и продаваемая компанией Oracle Corporation. Phalcon\Db\Adapter\Pdo\Oracle

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

Для создания собственных адаптеров баз данных или расширения существующих необходимо реализовать интерфейс Phalcon\Db\AdapterInterface.

Диалекты баз данных

Phalcon инкапсулирует специфические детали каждого движка базы данных в диалектах. Они предоставляют общие функции и генератор SQL адаптерам.

Имя Описание API
MySQL Диалект SQL для системы баз данных MySQL. Phalcon\Db\Dialect\Mysql
PostgreSQL Диалект SQL для системы баз данных PostgreSQL. Phalcon\Db\Dialect\Postgresql
SQLite Диалект SQL для системы баз данных SQLite. Phalcon\Db\Dialect\Sqlite
Oracle Диалект SQL для системы баз данных Oracle. Phalcon\Db\Dialect\Oracle

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

Для создания собственных диалектов баз данных или расширения существующих необходимо реализовать интерфейс Phalcon\Db\DialectInterface.

Подключение к базам данных

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

// Required
$config = array(
    "host" => "127.0.0.1",
    "username" => "mike",
    "password" => "sigma",
    "dbname" => "test_db"
);

// Optional
$config["persistent"] = false;

// Create a connection
$connection = new \Phalcon\Db\Adapter\Pdo\Mysql($config);
// Required
$config = array(
    "host" => "localhost",
    "username" => "postgres",
    "password" => "secret1",
    "dbname" => "template"
);

// Optional
$config["schema"] = "public";

// Create a connection
$connection = new \Phalcon\Db\Adapter\Pdo\Postgresql($config);
// Required
$config = array(
    "dbname" => "/path/to/database.db"
);

// Create a connection
$connection = new \Phalcon\Db\Adapter\Pdo\Sqlite($config);
// Basic configuration
$config = array(
    'username' => 'scott',
    'password' => 'tiger',
    'dbname' => '192.168.10.145/orcl',
);

// Advanced configuration
$config = array(
    'dbname' => '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=xe)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=20)(DELAY=5))))',
    'username' => 'scott',
    'password' => 'tiger',
    'charset' => 'AL32UTF8',
);

// Create a connection
$connection = new \Phalcon\Db\Adapter\Pdo\Oracle($config);

Настройка дополнительных параметров PDO

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

// Create a connection with PDO options
$connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(
    "host" => "localhost",
    "username" => "root",
    "password" => "sigma",
    "dbname" => "test_db",
    "options" => array(
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES \'UTF8\'",
        PDO::ATTR_CASE => PDO::CASE_LOWER
    )
));

Поиск строк

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

$sql = "SELECT id, name FROM robots ORDER BY name";

// Send a SQL statement to the database system
$result = $connection->query($sql);

// Print each robot name
while ($robot = $result->fetch()) {
   echo $robot["name"];
}

// Get all rows in an array
$robots = $connection->fetchAll($sql);
foreach ($robots as $robot) {
   echo $robot["name"];
}

// Get only the first row
$robot = $connection->fetchOne($sql);

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

Константа Описание
Phalcon\Db::FETCH_NUM Возвращает массив с числовыми индексами
Phalcon\Db::FETCH_ASSOC Возвращает массив с ассоциативными индексами
Phalcon\Db::FETCH_BOTH Возвращает массив с ассоциативными и числовыми индексами
Phalcon\Db::FETCH_OBJ Возвращает объект вместо массива
$sql = "SELECT id, name FROM robots ORDER BY name";
$result = $connection->query($sql);

$result->setFetchMode(Phalcon\Db::FETCH_NUM);
while ($robot = $result->fetch()) {
   echo $robot[0];
}

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

$sql = "SELECT id, name FROM robots";
$result = $connection->query($sql);

// Traverse the resultset
while ($robot = $result->fetch()) {
   echo $robot["name"];
}

// Seek to the third row
$result->seek(2);
$robot = $result->fetch();

// Count the resultset
echo $result->numRows();

Связывание параметров

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

// Binding with numeric placeholders
$sql    = "SELECT * FROM robots WHERE name = ? ORDER BY name";
$result = $connection->query($sql, array("Wall-E"));

// Binding with named placeholders
$sql     = "INSERT INTO `robots`(name`, year) VALUES (:name, :year)";
$success = $connection->query($sql, array("name" => "Astro Boy", "year" => 1952));

Вставка/Обновление/Удаление строк

Для вставки, обновления или удаления строк можно использовать исходный SQL-запрос или использовать предопределённые функции класса:

// Inserting data with a raw SQL statement
$sql     = "INSERT INTO `robots`(`name`, `year`) VALUES ('Astro Boy', 1952)";
$success = $connection->execute($sql);

//With placeholders
$sql     = "INSERT INTO `robots`(`name`, `year`) VALUES (?, ?)";
$success = $connection->execute($sql, array('Astro Boy', 1952));

// Generating dynamically the necessary SQL
$success = $connection->insert(
   "robots",
   array("Astro Boy", 1952),
   array("name", "year")
);

// Updating data with a raw SQL statement
$sql     = "UPDATE `robots` SET `name` = 'Astro boy' WHERE `id` = 101";
$success = $connection->execute($sql);

//With placeholders
$sql     = "UPDATE `robots` SET `name` = ? WHERE `id` = ?";
$success = $connection->execute($sql, array('Astro Boy', 101));

// Generating dynamically the necessary SQL
$success = $connection->update(
   "robots",
   array("name"),
   array("New Astro Boy"),
   "id = 101"
);

// Deleting data with a raw SQL statement
$sql     = "DELETE `robots` WHERE `id` = 101";
$success = $connection->execute($sql);

//With placeholders
$sql     = "DELETE `robots` WHERE `id` = ?";
$success = $connection->execute($sql, array(101));

// Generating dynamically the necessary SQL
$success = $connection->delete("robots", "id = 101");

Транзакции и вложенные транзакции

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

try {

    //Start a transaction
    $connection->begin();

    //Execute some SQL statements
    $connection->execute("DELETE `robots` WHERE `id` = 101");
    $connection->execute("DELETE `robots` WHERE `id` = 102");
    $connection->execute("DELETE `robots` WHERE `id` = 103");

    //Commit if everything goes well
    $connection->commit();

} catch(Exception $e) {
    //An exception has occurred rollback the transaction
    $connection->rollback();
}

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

try {

    //Start a transaction
    $connection->begin();

    //Execute some SQL statements
    $connection->execute("DELETE `robots` WHERE `id` = 101");

    try {

        //Start a nested transaction
        $connection->begin();

        //Execute these SQL statements into the nested transaction
        $connection->execute("DELETE `robots` WHERE `id` = 102");
        $connection->execute("DELETE `robots` WHERE `id` = 103");

        //Create a save point
        $connection->commit();

    } catch(Exception $e) {
        //An error has occurred, release the nested transaction
        $connection->rollback();
    }

    //Continue, executing more SQL statements
    $connection->execute("DELETE `robots` WHERE `id` = 104");

    //Commit if everything goes well
    $connection->commit();

} catch(Exception $e) {
    //An exception has occurred rollback the transaction
    $connection->rollback();
}

События базы данных

Phalcon\Db может отправлять события в EventsManager, если он присутствует. Некоторые события, возвращающие false, могут остановить активную операцию. Поддерживаются следующие события:

Имя события Вызывается Может остановить операцию?
afterConnect После успешного подключения к системе баз данных Нет
beforeQuery Перед отправкой SQL-запроса в систему баз данных Да
afterQuery После отправки SQL-запроса в систему баз данных Нет
beforeDisconnect Перед закрытием временного подключения к базе данных Нет
beginTransaction Перед началом транзакции Нет
rollbackTransaction Перед откат транзакции Нет
commitTransaction Перед фиксацией транзакции | Нет

Привязка EventsManager к подключению проста, Phalcon\Db будет вызывать события с типом «db»:

use Phalcon\Events\Manager as EventsManager,
    \Phalcon\Db\Adapter\Pdo\Mysql as Connection;

$eventsManager = new EventsManager();

//Listen all the database events
$eventsManager->attach('db', $dbListener);

$connection = new Connection(array(
    "host" => "localhost",
    "username" => "root",
    "password" => "secret",
    "dbname" => "invo"
));

//Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);

Остановка SQL-операций очень полезна, если, например, требуется реализовать проверку инъекций SQL в качестве последнего средства:

$eventsManager->attach('db:beforeQuery', function($event, $connection) {

    //Check for malicious words in SQL statements
    if (preg_match('/DROP|ALTER/i', $connection->getSQLStatement())) {
        // DROP/ALTER operations aren't allowed in the application,
        // this must be a SQL injection!
        return false;
    }

    //It's ok
    return true;
});

Профилирование SQL-запросов

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

Профилирование баз данных очень просто с помощью Phalcon\Db\Profiler:

use Phalcon\Events\Manager as EventsManager,
    Phalcon\Db\Profiler as DbProfiler;

$eventsManager = new EventsManager();

$profiler = new DbProfiler();

//Listen all the database events
$eventsManager->attach('db', function($event, $connection) use ($profiler) {
    if ($event->getType() == 'beforeQuery') {
        //Start a profile with the active connection
        $profiler->startProfile($connection->getSQLStatement());
    }
    if ($event->getType() == 'afterQuery') {
        //Stop the active profile
        $profiler->stopProfile();
    }
});

//Assign the events manager to the connection
$connection->setEventsManager($eventsManager);

$sql = "SELECT buyer_name, quantity, product_name "
     . "FROM buyers "
     . "LEFT JOIN products ON buyers.pid = products.id";

// Execute a SQL statement
$connection->query($sql);

// Get the last profile in the profiler
$profile = $profiler->getLastProfile();

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

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

use Phalcon\Events\Manager as EventsManager,
    Phalcon\Db\Profiler as Profiler,
    Phalcon\Db\Profiler\Item as Item;

class DbProfiler extends Profiler
{

    /**
     * Executed before the SQL statement will sent to the db server
     */
    public function beforeStartProfile(Item $profile)
    {
        echo $profile->getSQLStatement();
    }

    /**
     * Executed after the SQL statement was sent to the db server
     */
    public function afterEndProfile(Item $profile)
    {
        echo $profile->getTotalElapsedSeconds();
    }

}

//Create an EventsManager
$eventsManager = new EventsManager();

//Create a listener
$dbProfiler = new DbProfiler();

//Attach the listener listening for all database events
$eventsManager->attach('db', $dbProfiler);

Ведение журнала SQL-запросов

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

use Phalcon\Logger,
    Phalcon\Events\Manager as EventsManager,
    Phalcon\Logger\Adapter\File as FileLogger;

$eventsManager = new EventsManager();

$logger = new FileLogger("app/logs/db.log");

//Listen all the database events
$eventsManager->attach('db', function($event, $connection) use ($logger) {
    if ($event->getType() == 'beforeQuery') {
        $logger->log($connection->getSQLStatement(), Logger::INFO);
    }
});

//Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);

//Execute some SQL statement
$connection->insert(
    "products",
    array("Hot pepper", 3.50),
    array("name", "price")
);

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

[Sun, 29 Apr 12 22:35:26 -0500][DEBUG][Resource Id #77] INSERT INTO products
(name, price) VALUES ('Hot pepper', 3.50)

Реализация собственного логгера

Вы можете реализовать собственный класс логирования для запросов к базе данных, создав класс, реализующий единственный метод с именем «log». Метод должен принимать строку в качестве первого аргумента. Затем вы можете передать свой объект логирования в Phalcon\Db::setLogger(), и с этого момента любой SQL-запрос, выполняемый в базе данных, будет вызывать этот метод для записи результатов.

Описание таблиц/видов

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

// Get tables on the test_db database
$tables = $connection->listTables("test_db");

// Is there a table 'robots' in the database?
$exists = $connection->tableExists("robots");

// Get name, data types and special features of 'robots' fields
$fields = $connection->describeColumns("robots");
foreach ($fields as $field) {
    echo "Column Type: ", $field["Type"];
}

// Get indexes on the 'robots' table
$indexes = $connection->describeIndexes("robots");
foreach ($indexes as $index) {
    print_r($index->getColumns());
}

// Get foreign keys on the 'robots' table
$references = $connection->describeReferences("robots");
foreach ($references as $reference) {
    // Print referenced columns
    print_r($reference->getReferencedColumns());
}

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

Индекс Описание
Поле Имя поля
Тип Тип столбца
Ключ Является ли столбец частью первичного ключа или индекса?
Null Разрешает ли столбец значения null?

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

// Get views on the test_db database
$tables = $connection->listViews("test_db");

// Is there a view 'robots' in the database?
$exists = $connection->viewExists("robots");

Создание/изменение/удаление таблиц

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

Создание таблиц

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

use \Phalcon\Db\Column as Column;

$connection->createTable(
    "robots",
    null,
    array(
       "columns" => array(
            new Column("id",
                array(
                    "type"          => Column::TYPE_INTEGER,
                    "size"          => 10,
                    "notNull"       => true,
                    "autoIncrement" => true,
                )
            ),
            new Column("name",
                array(
                    "type"    => Column::TYPE_VARCHAR,
                    "size"    => 70,
                    "notNull" => true,
                )
            ),
            new Column("year",
                array(
                    "type"    => Column::TYPE_INTEGER,
                    "size"    => 11,
                    "notNull" => true,
                )
            )
        )
    )
);

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

Параметр Описание Необязательно
“type” Тип столбца. Должен быть константой Phalcon\Db\Column (см. список ниже) Нет
“primary” True, если столбец является частью первичного ключа таблицы Да
“size” Для некоторых типов столбцов, таких как VARCHAR или INTEGER, может быть указан размер Да
“scale” Столбцы DECIMAL или NUMBER могут иметь масштаб, определяющий количество десятичных знаков Да
“unsigned” Столбцы INTEGER могут быть со знаком или без знака. Это свойство не применяется к другим типам столбцов Да
“notNull” Столбец может хранить значения null? Да
“autoIncrement” С этим атрибутом столбец будет автоматически заполняться целым числом с автоинкрементом. Только один столбец в таблице может иметь этот атрибут. Да
“bind” Одна из констант BIND_TYPE_*, указывающая, как столбец должен быть связан перед сохранением Да
“first” Столбец должен быть размещен на первом месте в порядке столбцов Да
“after” Столбец должен быть размещен после указанного столбца Да

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

  • 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

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

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

Изменение таблиц

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

use Phalcon\Db\Column as Column;

// Adding a new column
$connection->addColumn("robots", null,
    new Column("robot_type", array(
        "type"    => Column::TYPE_VARCHAR,
        "size"    => 32,
        "notNull" => true,
        "after"   => "name"
    ))
);

// Modifying an existing column
$connection->modifyColumn("robots", null, new Column("name", array(
    "type" => Column::TYPE_VARCHAR,
    "size" => 40,
    "notNull" => true,
)));

// Deleting the column "name"
$connection->deleteColumn("robots", null, "name");

Удаление таблиц

Примеры удаления таблиц:

// Drop table robot from active database
$connection->dropTable("robots");

//Drop table robot from database "machines"
$connection->dropTable("robots", "machines");

© 2011–2016 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/2.0.0/reference/db.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API