Класс xPDO

21 августа 2017, 18:14
  • Конструктор xPDO
  • Соединения с базой данных и xPDO
  • Установка нескольких соединений (xPDO 2.2+)
  • Гидратирование полей
  • Класс 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() они доступны в качестве массива объектов класса.


    Следующий раздел
    Объектная модель