Содержание


Adapter


Zend\Db\Adapter, Адаптер, Db, ДБ, База данных, работа, ЗФ2, Zend Framework 2, ZF2,




Объект Adapter является одним из самых важных компонентов, входящих в Zend\Db. Он отвечает за адаптацию написанного кода на/для Zend\Db к целевым расширениям PHP и БД. При этом, он создает уровень абстракции для расширений PHP, которая называется «Driver»  адаптера Zend\Db. Так же создается легкий слой абстракции для различных особенностей, присущих каждой платформе SQL/RDBMS (СУБД) реализации, называемых «Platform»(Платформа) адаптера.

Создание адаптера (быстрый старт)

 

Создание адаптера может быть сделано просто  путем создания экземпляра класса ZendDbAdapterAdapter. Самым простым способом использования является передача массива с необходимыми данными в адаптер.

$adapter = new ZendDbAdapterAdapter($driverArray);

Этот драйвер является абстракцией для требуемого уровня расширенных параметров. Описание параметров:

 

     Name                                 Required                                            Notes

1) driver                      required*    Mysqli, Sqlsrv, Pdo_Sqlite, Pdo_Mysql, Pdo=OtherPdoDriver

2) database                 generally required**              имяБД

3) username                generally required                  имяпользователяБД

4) password                generally required                  пароль

5) hostname                not generally required***      IP адресс для подключения к БД

6) port                         not generally required            портдляподключения

7) characterset              not generally required           требуемаякодировка (обычно UTF-8)

Сверсии 2.0.3 (charset)

 

* required – требуется обязательно

**generallyrequired – обычно необходимо

***notgenerallyrequired – не является обязательным

 

Другие имена также будут распознаны. Если в PHP руклведстве используются конкретные имена, то эти имена так же будут поддерживаться драйвером. Например, «dbname» в большинстве случаев также будет работать для «database». Еще как пример, в случае с «Sqlsrv», «UID» будет воспринято как «username». Вы сами решаете с каким форматом имен работать. В таблице выше были представлены официальные именования.

 

Пример подключения к MySqli:

 $adapter = new Zend\Db\Adapter\Adapter(array(
    'driver' => 'Mysqli',
    'database' => 'zend_db_example',
    'username' => 'developer',
    'password' => 'developer-password'
 ));

Пример подключения к Sqlite через PDO:

$adapter = new Zend\Db\Adapter\Adapter(array(
    'driver' => 'Pdo_Sqlite',
    'database' => 'path/to/sqlite.db'
 ));

Важно понимать, что при использовании такого стиля подключения адаптер будет пытаться создать зависимости, которые прямо не предусмотрены. Объект Driver будет создан из данных, которые были переданы в массиве $driver в конструктор. Объект Platform будет создан основываясь на типе созданного объекта Driver. И вконце будет создан и доступен для использования объект по-умолчанию ResultSet. Любой из этих объектов может быть инъекцирован. Более подробно дальше.

 

Список официально поддерживаемых драйверов:

 

1) Mysqli                    ext/mysqli драйвер

2) Pgsql                      ext/pgsql драйвер

3) Sqlsrv                     ext/sqlsrv драйвер (от Microsoft)

4) Pdo_Mysql             MySQL через расширение PDO

5) Pdo_Sqlite             SQLite через расширение PDO

6) Pdo_Pgsql              PostgreSQL через расширение PDO



Создание адаптера (путем введения зависимостей)

 

Более выразительным и красивым способом создания адаптера является ввод зависимостей. Zend\Db\Adapter\Adapter использует конструктор инъекций, и все необходимые зависимости создаются через конструктор, который использует следующий синтаксис:

use Zend\Db\Adapter\Platform\PlatformInterface;
use Zend\Db\ResultSet\ResultSet;
 
class Zend\Db\Adapter\Adapter {
    public function __construct($driver, PlatformInterface $platform = null, ResultSet $queryResultSetPrototype = null)
}

Что может быть инъекцировано:

1) $driver –массив параметров для соединения или экземпляр Zend\Db\Adapter\Driver\DriverInterface .

2) $platform - (опционально) экземпляр Zend\Db\Platform\PlatformInterface, по-умолчанию создается на основе драйвера.

3) $queryResultSetPrototype - (опционально) экземпляр Zend\Db\ResultSet\ResultSet. Для понимания роли этого объекта смотрите раздел ниже о запросах через адаптер.

 

Подготовка запроса с помощью  Zend\Db\Adapter\Adapter::query()

 

По умолчанию query() предпочитает использовать «preparation» (подготовку) в качестве средства для обработки SQL. Это означает, что Вы будете формировать запрос со значениями замещенными заполнителями (обычно знаки вопросов), а потом соответствующие параметры для этих заполнителей будет подставлены на свои места. Пример такого подхода:

$adapter->query('SELECT * FROM `artist` WHERE `id` = ?', array(5));

Предыдущий пример проходит через такие этапы:

 

1) создается новый объект Statement (Заявление)

2) подготовить массив в ParameterContainer при необходимости

3) инъкцировать(внедрить зависимость) ParameterContainer в объект Statement

4) исполнение объекта Statement, создавая объект Result.

5) проверка объекта Result, был ли переданный запрос действительно sql запросом (query) или результат устанавливает произведенное заявление.( or a result set producing statement)

6) если Result создал запрос, клонируется прототип ResultSet, инъекцируется ResultSet как источник данных и возвращает его.

7) иначе возвращает Result

 

Выполнение запросов напрямую через Zend\Db\Adapter\Adapter::query()

 

Иногда бывают ситуации, когда необходимо выполнять запросы напрямую. В большинстве случаев выполнение запросов напрямую вместо их подготовки и последующего выполнения возникает при использовании DDL заявлений(которое в большинстве платформ и расширений) не поддерживает предподготовку (preparable). Смотрим пример такой реализации:

$adapter->query('ALTER TABLE ADD INDEX(`foo_index`) ON (`foo_column`))', Adapter::QUERY_MODE_EXECUTE);
 

Главная особенность этого подхода в том, что вторым параметром необходимо передать Adapter::QUERY_MODE_EXECUTE (выполнение). 

Создание заявлений (операторов, Statements)

 

Пока query() является весьма полезным для разовых и быстрых запросов к БД через адаптер, имеет смысл создания заявлений (Statements) и взаимодействовать с ним напрямую. Таким образом Вы получаете максимальный контроль над процессом подготовки -  выполнения запроса. Для реализации выше сказанного, адаптер (Adapter) предоставляет Вам возможность вызова createStatement(), который позволяет создавать драйвер (Driver) для конкретного заявления (Statement), что в итоге позволяет контролировать процесс подгтовки-выполнения запроса. Пример ниже:

// with optional parameters to bind up-front
$statement = $adapter->createStatement($sql, $optionalParameters);
$result = $statement->execute();


Использование объекта Driver

 

Объект Driver является основным местом, где Zend\Db\Adapter\Adapter реализует уровень абстракции соединения, позволяющий использовать все интерфейсы Zend\Db

Через различные ext/mysqli, ext/sqlsrv, PDO и другие PHP драйверы. Поэтому каждый драйвер состоит из трех (3) объектов:

 

1) A connection: Zend\Db\Adapter\Driver\ConnectionInterface. Соединение.

2) A statement: Zend\DbAdapter\Driver\StatementInterface. Заявление.

3) A result: Zend\Db\Adapter\Driver\ResultInterface. Результат.

 

Каждый из встроенных драйверов поддерживает прототопирование (prytotyping), что означает создание объекта, когда новый экземпляр вызывается. Рабочий процесс выглядит следующим образом:

 

1) Адаптер создан с набором параметров соединения

2) Адаптер выбирает соответствующий драйвер для экземпляра. Например Zend\Db\Adapter\Driver\Mysqli.

3) Объект драйвера создан

4)  Если нет соединения (connection), заявление или объект результата инъекцируются. По умолчанию создаются экземпляры.

 

Следующий драйвер готов быть вызванным при запросе. Так выглядит Driver API :

 interface DriverInterface
 {
     const PARAMETERIZATION_POSITIONAL = 'positional';
     const PARAMETERIZATION_NAMED = 'named';
     const NAME_FORMAT_CAMELCASE = 'camelCase';
     const NAME_FORMAT_NATURAL = 'natural';
     public function getDatabasePlatformName($nameFormat = self::NAME_FORMAT_CAMELCASE);
     public function checkEnvironment();
     public function getConnection();
     public function createStatement($sqlOrResource = null);
     public function createResult($resource);
     public function getPrepareType();
     public function formatParameterName($name, $type = null); 
     public function getLastGeneratedValue();
 }

Этот DriverInterface предоставляет Вам следующие возможности:

 

1) Узнать поддерживаемое этим драйвером имя платформы (олезно для выбора надлежащего объекта платформы)

2) Убедиться, что окружающая среда может поддерживать этот драйвер

3) Вернуть объект Connnection

4) Создание объекта связи (оператора, Statement), которые необязательно будут родителями для SQL заявлений.(в таком случае будет клоном прототопированого объекта заяления)

5) Создать объект Result, который необязательно будет родителем для ресурса заявления. .(в таком случае будет клоном прототопированого объекта Result)

 

6) Формат параметра имен, является важным для определения разницы между различными способами именования между расширениями.

7) Получить последнее сгенерированное значение. Например значение auto-increment.

 

Объект заявления обычно выглядит так:

interface StatementInterface extends StatementContainerInterface
{
    public function getResource();
    public function prepare($sql = null);
    public function isPrepared();
    public function execute($parameters = null);
 
    /** Inherited from StatementContainerInterface */
    public function setSql($sql);
    public function getSql();
    public function setParameterContainer(ParameterContainer $parameterContainer);
    public function getParameterContainer();
}

Объект результата выглядит так:

interface ResultInterface extends Countable, Iterator
{
    public function buffer();
    public function isQueryResult();
    public function getAffectedRows();
    public function getGeneratedValue();
    public function getResource();
    public function getFieldCount();
}


Использование объекта Platform (платформы)

 

Объект Platform предоставляет API для упрощения создания SQL запросов учитывая особенности различных платформ. Например, заключение в кавычки различных идентификаторов и значений или обработка разделитель в идентификаторах. Объект Platform выглядит следующим образом:

interface Zend\Db\Adapter\Platform\PlatformInterface
{
    public function getName();
    public function getQuoteIdentifierSymbol();
    public function quoteIdentifier($identifier);
    public function quoteIdentifierChain($identiferChain)
    public function getQuoteValueSymbol();
    public function quoteValue($value);
    public function quoteValueList($valueList);
    public function getIdentifierSeparator();
    public function quoteIdentifierInFragment($identifier, array $additionalSafeWords = array());
}

Хотя существует возможность создавать свой собственный  объект Platform, намного проще получать его из заранее сконфигурированного адаптера.

$platform = $adapter->getPlatform();
// or
$platform = $adapter->platform; // magic property access

Несколько примеров использования Platform:

/** @var $adapter Zend\Db\Adapter\Adapter */
/** @var $platform Zend\Db\Adapter\Platform\Sql92 */
$platform = $adapter->getPlatform();
 
// "first_name"
echo $platform->quoteIdentifier('first_name');
 
// "
echo $platform->getQuoteIdentifierSymbol();
 
// "schema"."mytable"
echo $platform->quoteIdentifierChain(array('schema','mytable')));
 
// '
echo $platform->getQuoteValueSymbol();
 
// 'myvalue'
echo $platform->quoteValue('myvalue');
 
// 'value', 'Foo O'Bar'
echo $platform->quoteValueList(array('value',"Foo O'Bar")));
 
// .
echo $platform->getIdentifierSeparator();
 
// "foo" as "bar"
echo $platform->quoteIdentifierInFragment('foo as bar');
 
// additionally, with some safe words:
// ("foo"."bar" = "boo"."baz")
echo $platform->quoteIdentifierInFragment('(foo.bar = boo.baz)', array('(', ')', '='));

Использование контейнера параметров (Parameter Container)

 

Объект ParameterContainer представляет собой контейнер для различных параметров, которые должны быть переданы в объект Statement (Заявление) для выполнения всех параметризированных частей SQL заявления. Этот объект реализует интерфейс ArrayAccess. Ниже приведен API ParameterContainer:

class ParameterContainer implements \Iterator, \ArrayAccess, \Countable {
    public function __construct(array $data = array())
 
    /** methods to interact with values */
    public function offsetExists($name)
    public function offsetGet($name)
    public fu/span span style=nction offsetSetReference($name, $from)
    public function offsetSet($name, $value, $errata = null)
    public function offsetUnset($name)
 
    /** set values from array (will reset first) */
    public function setFromArray(Array $data)
 
    /** methods to interact with value errata */
    public function offsetSetErrata($name, $errata)
    public function offsetGetErrata($name)
    public function offsetHasErrata($name)
    public function offsetUnsetErrata($name)
 
    /** errata only iterator */
    public function getErrataIterator()
 
    /** get array with named keys */
    public function getNamedArray()
 
    /** get array with int keys, ordered by position */
    public function getPositionalArray()
 
    /** iterator: */
    public function count()
    public function current()
    public function next()
    public function key()
    public function valid()
    public function rewind()
 
    /** merge existing array of parameters with existing parameters */
    public function merge($parameters)
}

В дополнение к параметрам имен и значений, контейнер так же помогает в отслеживании типов параметров для SQL.

 

Например, может быть важным :

$container->offsetSet('limit', 5);

Быть целочисленным значением. Для этого передайте константу ParameterContainer::TYPE_INTEGER в третий параметр:

$container->offsetSet('limit', 5, $container::TYPE_INTEGER);

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

Примеры

 

Создание Driver, Vendor portable Query, Preparing, Iterating Result

$adapter = new Zend\Db\Adapter\Adapter($driverConfig);
 
$qi = function($name) use ($adapter) { return $adapter->platform->quoteIdentifier($name); };
$fp = function($name) use ($adapter) { return $adapter->driver->formatParameterName($name); };
 
$sql = 'UPDATE ' . $qi('artist')
    . ' SET ' . $qi('name') . ' = ' . $fp('name')
    . ' WHERE ' . $qi('id') . ' = ' . $fp('id');
 
/** @var $statement ZendDbAdapterDriverStatementInterface */
$statement = $adapter->query($sql);
 
$parameters = array(
    'name' => 'Updated Artist',
    'id' => 1
);
 
$statement->execute($parameters);
 
// DATA INSERTED, NOW CHECK
 
/* @var $statement ZendDbAdapterDriverStatementInterface */
$statement = $adapter->query('SELECT * FROM '
    . $qi('artist')
    . ' WHERE id = ' . $fp('id'));
 
/* @var $results ZendDbResultSetResultSet */
$results = $statement->execute(array('id' => 1));
 
$row = $results->current();
$name = $row['name'];

Автор статьи: DuB