Класс xPDO
Класс xPDO преследует несколько целей, все из которых направлены на обеспечение базового набора возможностей для того, чтобы можно было быстро и безболезненно реализовать объектную модель и сделать это без ограничений в ее реализации. Далее подробнее рассматриваются три главные роли xPDO.
В качестве надстройки PDO
PDO - это новый стандарт доступа к базам данных в PHP, и его возможности служат ядром для всего xPDO. Экземпляр PDO по существу представляет собой соединение к базе данных, и в качестве надстройки, превращая его в «сервис-объект», xPDO может обеспечивать богатый буфер между вашей объектной моделью и сервисами, ответственными за управление всеми связями с базами данных.
И хотя xPDO не расширяет напрямую PDO (не является его классом-наследником), он предоставляет те же методы, что и PDO, что позволяет xPDO быть посредником между всеми вызовами базы данных. Это позволяет использовать кеширование результатов запросов и другие продвинутые техники оптимизации того, как ваши приложения взаимодействуют с базой данных (например, кешируя результаты запросов к БД в файлы или память, вы можете избежать соединений к БД, если все запрашиваемое уже есть в кеше).
Наконец, наследуя xPDO своими классами, вы можете добиться выполнения всех требуемых вами задач. Например, вы можете добавить специфичные для конкретной предметной области методы или расширить базовые методы в ваших наследниках и использовать экземпляры как центральные объекты предметной области для взаимодействия с вашей моделью. Так построена Система управления контентом MODX Revolution: центральный класс modX расширяет xPDO и добавляет методы, которые формируют предметную область приложения MODX.
Пример расширения класса xPDO: class myClass extends xPDO
и определения конструктора:
function __construct($options = array()) {
$options = array(
xPDO::OPT_CACHE_PATH => '/path/to/my/cache/dir',
xPDO::OPT_TABLE_PREFIX => 'myprefix_',
xPDO::OPT_HYDRATE_FIELDS => true,
xPDO::OPT_HYDRATE_RELATED_OBJECTS => true,
xPDO::OPT_HYDRATE_ADHOC_FIELDS => true,
xPDO::OPT_VALIDATE_ON_SAVE => true,
);
parent :: __construct(
'mysql:host=localhost;dbname=myxpdodb;charset=utf8',
'username',
'password',
$options,
array (
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_PERSISTENT => false,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
)
);
$this->setPackage('mypackage', 'path/to/my/model/');
}
Подробнее о конструкторе ниже.
В качестве сервисного слоя
В добавление к PDO, xPDO может обертывать другие объекты, с которыми хотите работать в своей модели.
Например, вы можете загрузить Smarty как объект, который можно вызывать напрямую из экземпляра xPDO:
if ($className= $xpdo->loadClass('Smarty','/path/to/smarty/smarty.class.php', false, true)) {
$xpdo->smarty= & new $className ($xpdo);
}
$xpdo->smarty->someFunc();
xPDO предоставляет также удобный метод сделать это в одну строчку:
if ($xpdo->getService('myService', 'myServiceClass', '/path/to/model/root/', array('param1' => $param1, 'param2' => $param2)) {
$xpdo->myService->doSomething();
}
При этом если сервисный экземпляр уже загружен в текущем запросе, он не будет загружен снова, а будет возвращена ссылка на него. Это создает простой способ обеспечивать повторно использование сервисных объектов для общих задач.
В качестве объектно-реляционного отображения
В качестве надстройки над PDO, xPDO может легко использовать свои PDO сервисы для взаимодействия с вашей реляционной моделью. Как только вы определили объектную модель и сгенерировали базовые классы и объектно-реляционные схемы, предоставляющие нужную xPDO информацию, вы можете использовать его методы для взаимодействия с вашими объектами множеством различных способов. Эти методы будут рассмотрены подробнее в разделе «Объектная модель».
Конструктор xPDO
По умолчанию xPDO конструктор вызывается так: $xpdo= new xPDO($dsn, $username, $password, $options, $driverOptions)
Параметры
В конструкторе доступно 5 параметров, но единственный необходимый это первый:
$dsn
Этот параметр запрашивает значение DSN соединения, которое задается в следующем формате: mysql:host=MYHOSTNAME;dbname=MYDBNAME;charset=MYCHARSET
Нужно просто поменять значение имен хоста, базы данных и кодировки. Больше информации доступно в документации PDO на PHP.net.
$username и $password
Это логин и пароль к базе данных. Установите их, если хотите использовать соединения к БД в xPDO.
$options
Позволяет передать в конструктор массив характерных для xPDO свойств.
Некоторые из этих свойств имеют предопределенные значения, например, следующие (но не ограничены ими):
Параметр | Описание |
---|---|
xPDO::OPT_AUTO_CREATE_TABLES | Если true, создает таблицы, соответствующие запрашиваемым классам, в случае если эти таблицы еще не существуют в базе данных |
xPDO::OPT_BASE_CLASSES | Массив имен классов, загружаемых во время создания экземпляра класса xPDO |
xPDO::OPT_BASE_PACKAGES | Строка имен пакетов и путей к ним, в формате "имя_пакета1:путь_до_пакета1,имя_пакета1:путь_до_пакета1,...", загружаемые при создании экземпляра класса xPDO |
xPDO::OPT_CACHE_COMPRESS | Если установлена, любой экземпляр класса xPDOCache, использующий провайдера, который поддерживает сжатие данных, будет использовать эту опцию по умолчанию (например, xPDOMemCache) |
xPDO::OPT_CACHE_DB | Если установлена, будет включено кеширование наборов данных запросов к БД |
xPDO::OPT_CACHE_DB_COLLECTIONS | Если установлена, кеширование наборов данных запросов к БД будет пытаться кешировать целые коллекции |
xPDO::OPT_CACHE_DB_OBJECTS_BY_PK | Если установлена, кеширование наборов данных запросов к БД будет создавать элементы кеша по первичному ключу в дополнение к используемой подписи запроса |
xPDO::OPT_CACHE_DB_EXPIRES | Если установлена, определяет число секунд, которые существует кеш наборов данных; 0 означает, что кеш не истекает |
xPDO::OPT_CACHE_DB_HANDLER | Если установлена, определяет наследника класса xPDOCache для управления кеширование наборов данных |
xPDO::OPT_CACHE_EXPIRES | Если установлена, определяет число секунд жизни кеша для любого провайдера по умолчанию; 0 означает, что кеш не истекает |
xPDO::OPT_CACHE_FORMAT | Если установлена, определяет формат файлов кеша, используемых в xPDOFileCache; по умолчанию PHP, но доступны JSON и сериализованный (начиная с версии xPDO 2.1) |
xPDO::OPT_CACHE_KEY | Если установлена, определяет ключ кеша по умолчанию; значение по умолчанию default |
xPDO::OPT_CACHE_PATH | Если установлена, определяет пользовательскую переменную класса cachePath для объекта xPDO, которая может использоваться при кешировании |
xPDO::OPT_CACHE_ATTEMPTS | Если установлена, определяет число попыток, которое xPDOFileCache будет блокировать на запись существующий элемент кеша; по умолчанию 1. (начиная с версии xPDO 2.1 |
xPDO::OPT_CACHE_ATTEMPT_DELAY | Если установлена, определяет число микросекунд задержки между попытками блокировки элементов кеша на запись; по умолчанию 10000 (начиная с версии xPDO 2.1) |
xPDO::OPT_CONNECTIONS | Дополнительно определяет набор соединений с БД при создании экземпляра класса xPDO (начиная с версии xPDO 2.2) |
xPDO::OPT_CONN_INIT | Определяет настройки, которые должны быть выбраны для соединения при его инициализации; применяется, если определены несколько соединений (начиная с версии xPDO 2.2) |
xPDO::OPT_CONN_MUTABLE | Определяет могут ли данные из соединения быть изменены, например, перезаписаны (начиная с версии xPDO 2.2) |
xPDO::OPT_HYDRATE_FIELDS | Если true, поля будут гидратированы |
xPDO::OPT_HYDRATE_RELATED_OBJECTS | Если true, связанные объекты будут гидратированы |
xPDO::OPT_HYDRATE_ADHOC_FIELDS | Если true, ad-hoc поля (не описанные в карте класса, создаваемые на лету) будут гидратированы |
xPDO::OPT_LOADER_CLASSES | Массив имен классов для загрузки во время создания экземпляра xPDO объекта. (устарело с версии 2.0.0-pl |
xPDO::OPT_ON_SET_STRIPSLASHES | Если установлена, stripslashes() применяется для значений, устанавливаемых методом xPDOObject::set() |
xPDO::OPT_TABLE_PREFIX | Если установлена, все классы будут ссылаться на таблицы, начинающиеся с данного префикса |
xPDO::OPT_VALIDATOR_CLASS | Если установлена, будет использоваться пользовательский класс валидации, производный от xPDOValidator (который используется по умолчанию) |
xPDO::OPT_VALIDATE_ON_SAVE | Если true, объекты xPDOObject будут проверяться своими Валидаторами перед сохранением |
$driverOptions
Необязательный массив настроек, специфичных для каждого PDO драйвера. Больше информации в справочнике PHP.
Соединения с базой данных и xPDO
Способность подключения к базе данных в xPDO задана в конструкторе. Объект xPDO одновременно может поддерживать только одно соединение, но вы можете создавать столько экземпляров xPDO, сколько вам потребуется. Синтаксис конструктора следующий:
xPDO::__construct($dsn, $username= '', $password= '', $options= array(), $driverOptions= null)
Итак предположим, что нам нужно соединиться с базой данной 'text' на localhost с портом 3306, в кодировке utf-8:
$dsn = 'mysql:host=localhost;dbname=test;port=3306;charset=utf-8';
$xpdo = new xPDO($dsn,'username','password');
И готово!
Опционально можно проверить соединение, просто добавив далее следующую строку:
echo $o=($xpdo->connect()) ? 'Соединено' : 'Не соединено';
xPDO создает объект PDO, и таким образом соединяется с базой данных, только когда вызывается метод PDO и требуется соединение. Эта особенность «соединение-по-требованию» позволяет xPDO получать данные из кеша без дополнительного соединения к базе данных (конечно, если данные в кеше уже сохранены).
Пример соединения
<?php
define('MODX_CORE_PATH', '/path/to/revo/core/');
define('MODX_CONFIG_KEY','config');
require_once MODX_CORE_PATH . 'model/modx/modx.class.php';
// Параметры базы данных
$host = 'localhost';
$username = 'your_username';
$password = 'your_password';
$dbname = 'your_database';
$port = 3306;
$charset = 'utf-8';
$dsn = "mysql:host=$host;dbname=$dbname;port=$port;charset=$charset";
$xpdo = new xPDO($dsn, $username, $password);
// Тестирование соединения
echo $o = ($xpdo->connect()) ? 'Connected' : 'Not Connected';
// Делаем запрос к базе данных и выводим количество результатов:
$results = $xpdo->query("SELECT id FROM some_table");
$recordCount = $results->rowCount();
print $recordCount;
Установка нескольких соединений (xPDO 2.2+)
xPDO 2.2 добавило возможность устанавливать несколько соединений и включает параметры конфигурации для определения неизменяемых атрибутов для каждого соединения. Это позволяет использовать xPDO с разного рода master/slave конфигурациями баз данных. Под этой особенностью понимается не соединение к конкретному узлу базы данных, а настройка master/slave конфигураций, где один (или более) узлов доступны только для чтения, и хотя бы один узел доступен для записи (т.е. mutable). В этом случае вы можете запрашивать исходное соединение только на чтение, и xPDO автоматически переключится на доступное для записи соединение, если над объектом базы данных производится операция записи.
xPDO::OPT_CONNECTIONS
Для определения дополнительных соединений для экземпляра xPDO, можно передать массив конфигураций соединений (конфигурации так же являются массивами) в параметр $options конструктора xPDO. Каждый массив соединения определяет такие же параметры, как и вызов конструктора xPDO. Пример вызова конструктора с несколькими соединениями только для чтения:
$xpdo = new xPDO('mysql:host=127.0.0.1:19570;dbname=xpdotest;charset=utf8', 'username', 'password' array(
xPDO::OPT_CONN_MUTABLE => true,
xPDO::OPT_CONN_INIT => array(xPDO::OPT_CONN_MUTABLE => false),
xPDO::OPT_CONNECTIONS => array(
array(
'dsn' => 'mysql:host=127.0.0.1:19571;dbname=xpdotest;charset=utf8',
'username' => 'username',
'password' => 'password',
'options' => array(
xPDO::OPT_CONN_MUTABLE => false,
),
'driverOptions' => array(),
),
array(
'dsn' => 'mysql:host=127.0.0.1:19572;dbname=xpdotest;charset=utf8',
'username' => 'username',
'password' => 'password',
'options' => array(
xPDO::OPT_CONN_MUTABLE => false,
),
'driverOptions' => array(),
),
),
));
xPDO::OPT_CONN_MUTABLE
Этот параметр определяет доступность соединения для записи (true) или только для чтения (false). Устанавливается в массиве $options конструктора, а так же в дополнительных соединениях.
xPDO::OPT_CONN_INIT
Этот параметр определяет условия, которым должно удовлетворять соединение, чтобы рассматриваться в качестве используемого для исходного соединения, создаваемого в xPDO. В конфигурациях master/slave обычное значение для этого параметра (которое устанавливается только раз в главных конфигурационных настройках) указывает использовать соединение, доступное только для чтения.
xPDO::OPT_CONN_INIT => array(xPDO::_OPT_CONN_MUTABLE => false)
Это обеспечивает, что xPDO выбирает соединение с параметром xPDO::_OPT_CONN_MUTABLE, установленным в значение false
. Если производится операция на запись при инициализированном соединении, доступном только для чтения, будет выбрано новое соединение, доступное для записи, и закешировано для последующего использования другими операциями записи в данном цикле выполнения.
Гидратирование полей
Что такое гидратирование?
Гидратирование (Hydration) это процесс, при котором поля и связанные объекты, представленные экземплярами класса xPDOObject, заполняются значениями. По умолчанию, эти поля доступны только с помощью методов get()
, getOne()
и getMany()
класса xPDOObject и должны быть определены подходящими метаданными в карте объекта. Тем не менее, существует несколько настроек, которые вы можете использовать для расширения процесса того, как xPDO гидратирует поля и связанные объекты.
Эти настройки применяются при передаче следующих параметров в параметр $config конструктора xPDO:
Параметр | Описание |
---|---|
xPDO::OPT_HYDRATE_FIELDS | Если true, поля будут гидратированы в качестве публичных переменных объекта. |
xPDO::OPT_HYDRATE_RELATED_OBJECTS | Если true, связанные объекты будут гидратированы в качестве публичных переменных объекта. |
xPDO::OPT_HYDRATE_ADHOC_FIELDS | Если true, ad-hoc поля (не описанные в карте класса, создаваемые на лету) будут разрешены и гидратированы в качестве публичных переменных объекта (при этом должна быть установлена настройка xPDO::OPT_HYDRATE_FIELDS). |
Гидратированные Поля
Если параметр xPDO::OPT_HYDRATE_FIELDS установлен в значении true, в дополнение к доступу к полям через метод xPDOObject::get()
все поля объекта становятся доступными через публичные переменные объекта. Пример:
$object->set('name',$name);
echo $object->name;
Этот код выведет значение поля 'name' объекта $object, при условии что поле 'name' определено в схеме объекта.
Замечание: Это "сырые" значения Доступ к полям объекта напрямую выводит только "сырые" значения, т.е. в таком виде, как они выгружены из базы данных, игнорируя метаданные, определенные для поля, и избегая любую логику, примененную в методе
get()
вашего класса, наследуемого от xPDOObject (а так же, всех его родительских классов). Рекомендуется всегда использовать методget()
для доступа к полям объектов, за исключением некоторых особых случаев, когда вам могут потребоваться сырые значения из базы данных, которые не должны быть изменены логикой методаget()
.
Гидратирование Ad Hoc Полей
Если параметр xPDO::OPT_HYDRATE_ADHOC_FIELDS установлен в значении true, для произвольных полей, не определенных в карте класса, так же будет проводиться гидратация. Теперь все поля, даже не указанные в схеме объекта будут заполняться. Например, мы хотим установить произвольное поле 'dollars' для объекта Person:
$object->set('name','Вася Пупкин');
$object->set('dollars',45);
echo $object->get('name') .' имеет '. $object->get('dollars') . ' долларов.';
Этот код вернет Вася Пупкин имеет 45 долларов.
, даже если поле 'dollars' не определено в схеме, конечно, только в том случае, если включены параметры xPDO::OPT_HYDRATE_ADHOC_FIELDS и xPDO::OPT_HYDRATE_FIELDS.
Гидратирование связанных объектов
Если xPDO::OPT_HYDRATE_RELATED_OBJECTS установлена в значение true, все связанные объекты так же будут доступны в качестве публичных переменных объекта. По умолчанию связанные объекты доступны только через методы getOne()
или getMany()
класса xPDOObject, но этот параметр (как xPDO::OPT_HYDRATE_FIELDS)
загружает все связанные объекты напрямую в переменные. Пример:
$user->getMany('UserSettings');
foreach ($user->UserSettings as $setting) {
echo $setting->get('key').' = ' . $setting->get('value') . '<br />';
}
Этот код вернет список ключей и значений пользовательских настроек, принадлежащих объекту $user, которые по умолчанию загружаются через getMany()
.
One против Many Объекты, загружаемые через
getOne()
доступны напрямую как объекты соответствующего класса, в то время как через методgetMany()
они доступны в качестве массива объектов класса.