mirror of
https://github.com/php/doc-ru.git
synced 2025-07-22 18:26:31 +00:00
985 lines
42 KiB
XML
985 lines
42 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: e8ac70bf549a723cb36465667a6109d9933b8619 Maintainer: sergey Status: ready -->
|
||
<!-- Reviewed: no -->
|
||
<chapter xml:id="mongodb.architecture" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<titleabbrev>Архитектура и внутреннее устройство драйвера</titleabbrev>
|
||
<title>Обзор архитектуры драйвера и её особенностей</title>
|
||
|
||
<section xml:id="mongodb.overview">
|
||
<titleabbrev>Архитектура</titleabbrev>
|
||
<title>Обзор архитектуры</title>
|
||
|
||
<para>
|
||
Раздел объясняет, как разные части PHP-драйвера сочетаются
|
||
друг с другом, от базовых системных библиотек, через PHP-модули и до
|
||
PHP-библиотек на самом верху.
|
||
</para>
|
||
|
||
<para>
|
||
<mediaobject>
|
||
<alt>
|
||
Схема архитектуры PHP-драйвера MongoDB.
|
||
Самый низкий уровень драйвера — системные модули: libmongoc, libbson и libmongocrypt.
|
||
Средний уровень — PHP-модуль MongoDB.
|
||
Верхний уровень — пользовательское PHP-окружение,
|
||
которое включает PHP-модуль MongoDB и пакеты более высокого уровня наподобие фреймворков и приложений.
|
||
</alt>
|
||
<imageobject>
|
||
<imagedata fileref="en/reference/mongodb/images/driver_arch.svg" width="625" depth="450" format="SVG" />
|
||
</imageobject>
|
||
</mediaobject>
|
||
</para>
|
||
|
||
<para>
|
||
Наверху стека расположена
|
||
<link xlink:href="&url.mongodb.library;">библиотека PHP</link>, которая распространяется
|
||
в виде <link xlink:href="&url.packagist.package;/mongodb/mongodb">пакета Composer</link>.
|
||
Эта библиотека предоставит API, согласованный с другими
|
||
<link xlink:href="&url.mongodb.drivers;">драйверами</link> MongoDB,
|
||
и реализует междрайверные
|
||
<link xlink:href="&url.mongodb.specs;">спецификации</link>.
|
||
Хотя модуль можно использовать напрямую, библиотека даёт минимальные накладные расходы
|
||
и должна быть общей зависимостью для большей части приложений, построенных с MongoDB.
|
||
</para>
|
||
|
||
<para>
|
||
На уровень ниже библиотеки располагается PHP-модуль, который распространяется
|
||
через репозиторий <link xlink:href="&url.pecl.package;mongodb">PECL</link>.
|
||
Модуль образует связующую прослойку между PHP и системными библиотеками
|
||
(<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>,
|
||
<link xlink:href="&url.mongodb.libbson;">libbson</link>
|
||
и <link xlink:href="&url.mongodb.libmongocrypt;">libmongocrypt</link>).
|
||
Этот публичный API предлагает только самую базовую функциональность:
|
||
|
||
<simplelist>
|
||
<member>Управление соединением</member>
|
||
<member>BSON кодирование и декодирование</member>
|
||
<member>Сериализация документа объекта (для поддержки библиотек ODM)</member>
|
||
<member>Выполнение команд, запросы и запись операций</member>
|
||
<member>Обработка курсоров для команд и результатов запроса</member>
|
||
</simplelist>
|
||
</para>
|
||
|
||
<para>
|
||
<table>
|
||
<title>Исходный код драйвера и проекты JIRA</title>
|
||
<tgroup cols="3">
|
||
<thead>
|
||
<row>
|
||
<entry>Проект</entry>
|
||
<entry>GitHub</entry>
|
||
<entry>JIRA</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>PHP библиотека</entry>
|
||
<entry><link xlink:href="&url.mongodb.github.phplib;">mongodb/mongo-php-library</link></entry>
|
||
<entry><link xlink:href="&url.mongodb.jira.phplib;">PHPLIB</link></entry>
|
||
</row>
|
||
<row>
|
||
<entry>PHP-модуль</entry>
|
||
<entry><link xlink:href="&url.mongodb.github.phpc;">mongodb/mongo-php-driver</link></entry>
|
||
<entry><link xlink:href="&url.mongodb.jira.phpc;">PHPC</link></entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mongodb.connection-handling">
|
||
<titleabbrev>Соединения</titleabbrev>
|
||
<title>Обработка и сохранение соединения</title>
|
||
|
||
&mongodb.note.forking;
|
||
|
||
<section>
|
||
<title>Сохранение соединения и топологии (версия PHP начиная с 1.2.0)</title>
|
||
|
||
<para>
|
||
Каждая версия модуля начиная с 1.2.0 сохраняет клиентский объект
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>
|
||
в рабочем процессе PHP, что позволяет ему повторно использовать соединения с базой данных,
|
||
состояния аутентификации <emphasis>и</emphasis> информацию о топологии в
|
||
нескольких запросах.
|
||
</para>
|
||
|
||
<para>
|
||
Когда вызывается метод <methodname>MongoDB\Driver\Manager::__construct</methodname>,
|
||
из его аргументов создаётся хеш (т. е. строка URI и параметры
|
||
массива). Модуль попытается найти ранее сохранённый клиентский объект
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> для
|
||
этого хеша. Если существующий клиент не может быть найден для хеша, будет создан
|
||
новый клиент и сохранён для будущего использования. Это поведение можно выключить
|
||
через параметр драйвера <literal>"disableClientPersistence"</literal>.
|
||
</para>
|
||
|
||
<para>
|
||
Каждый клиент содержит свои собственные подключения к базе данных и представление
|
||
топологии сервера (например, автономный, набор реплик, кластер сегментов). Сохраняя
|
||
клиент между PHP-запросами, модуль может переиспользовать установленные
|
||
подключения к базе данных и устранять необходимость
|
||
<link xlink:href="&url.mongodb.sdam;">обнаружения топологии сервера</link>
|
||
при каждом запросе.
|
||
</para>
|
||
|
||
<para>
|
||
Рассмотрим следующий пример:
|
||
</para>
|
||
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$managers = [
|
||
new MongoDB\Driver\Manager('mongodb://127.0.0.1'),
|
||
new MongoDB\Driver\Manager('mongodb://127.0.0.1'),
|
||
new MongoDB\Driver\Manager('mongodb://127.0.0.1:27017'),
|
||
new MongoDB\Driver\Manager('mongodb://rs1.example.com,rs2.example.com/', ['replicaSet' => 'myReplicaSet']),
|
||
];
|
||
|
||
foreach ($managers as $manager) {
|
||
$manager->executeCommand('test', new MongoDB\Driver\Command(['ping' => 1]));
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
|
||
<para>
|
||
Первые два объекта Manager будут использовать один и тот же
|
||
клиент <link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>, поскольку
|
||
их аргументы конструктора идентичны. Третий и четвёртый объекты будут
|
||
использовать каждый свой клиент. Всего будет создано три клиента, и
|
||
процесс PHP, выполняющий этот скрипт, откроет два соединения с
|
||
адресом <literal>127.0.0.1</literal> и одно соединение с каждым из
|
||
адресов: <literal>rs1.example.com</literal> и <literal>rs2.example.com</literal>.
|
||
Если драйвер обнаруживает дополнительных членов набора реплик после выполнения команд
|
||
<literal>hello</literal>, он также открывает дополнительные подключения
|
||
к этим серверам.
|
||
</para>
|
||
|
||
<para>
|
||
Если этот же процесс снова выполнит сценарий во втором запросе, эти три
|
||
клиента будут использованы повторно, а новых подключений установлено не будет. В зависимости
|
||
от того, как давно был обработан предыдущий запрос, модулю может потребоваться выполнить
|
||
дополнительные команды <literal>hello</literal> для обновления своего представления
|
||
топологий.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Сохранение сокетов (версии PHP до 1.2.0)</title>
|
||
|
||
<para>
|
||
Версии модуля до 1.2.0 используют API-интерфейс PHP-потоков
|
||
для подключений к базам данных через внутренний API-интерфейс библиотеки
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>, чтобы назначить пользовательские
|
||
обработчики для связи с сокетами; однако новый клиент libmongoc
|
||
создаётся для каждого менеджера <classname>MongoDB\Driver\Manager</classname>. В результате
|
||
модуль сохраняет отдельные соединения с базой данных, но не информацию о состоянии аутентификации
|
||
или топологии. Поэтому модулю приходится выдавать
|
||
команды в начале каждого запроса, чтобы проверить подлинность
|
||
и <link xlink:href="&url.mongodb.sdam;">обнаружить топологию сервера</link>.
|
||
</para>
|
||
|
||
<para>
|
||
Соединения с базой данных сохраняются как хеш хоста,
|
||
порта и строки URI-идентификатора сервера, которую передавали в конструктор
|
||
менеджера <classname>MongoDB\Driver\Manager</classname>. Параметры массива конструктора
|
||
не включаются в этот хеш.
|
||
</para>
|
||
|
||
<note>
|
||
<simpara>
|
||
Версии модуля >= 1.1.8 and < 1.2.0 не сохраняют сокеты
|
||
для SSL-соединений. Смотрите
|
||
<link xlink:href="&url.mongodb.jira.phpc;-720">PHPC-720</link> для получения
|
||
дополнительной информации.
|
||
</simpara>
|
||
</note>
|
||
|
||
<para>
|
||
Несмотря на недостатки, которые связаны с сохранением SSL-соединений и информацией о топологии,
|
||
эта версия модуля поддерживает все
|
||
<link linkend="context.ssl">параметры SSL-контекста</link>, поскольку использует
|
||
API-интерфейс потоков PHP.
|
||
</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section xml:id="mongodb.persistence">
|
||
<titleabbrev>Сохранение данных</titleabbrev>
|
||
<title>Сериализация и десериализация PHP-переменных в модуле MongoDB</title>
|
||
|
||
<para>
|
||
В документе обсуждается, как составные структуры наподобие документов, массивов
|
||
и объектов преобразовываются между значениями формата BSON и PHP-значениями.
|
||
</para>
|
||
|
||
<section xml:id="mongodb.persistence.serialization">
|
||
<title>Сериализация в BSON</title>
|
||
|
||
<section>
|
||
<title>Массивы</title>
|
||
|
||
<para>
|
||
Если массив представляет собой <emphasis>упакованный массив</emphasis> —
|
||
то есть пустой массив или ключи начинаются
|
||
с 0 и идут последовательно без пробелов: <emphasis>BSON-массив</emphasis>.
|
||
</para>
|
||
|
||
<para>
|
||
Если массив не упакован — то есть содержит ассоциативные (строковые) ключи,
|
||
ключи не начинаются с 0 или содержат пробелы: <emphasis>BSON-объект</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
Документ верхнего уровня (корневой) <emphasis>всегда</emphasis> сериализуется
|
||
как BSON-документ.
|
||
</para>
|
||
|
||
<section>
|
||
<title>Примеры</title>
|
||
|
||
<para>
|
||
Эти PHP-массивы сериализуются как BSON-массив:
|
||
</para>
|
||
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
[8, 5, 2, 3] => [8, 5, 2, 3]
|
||
[0 => 4, 1 => 9] => [4, 9]
|
||
]]>
|
||
</programlisting>
|
||
|
||
<para>
|
||
Эти PHP-массивы сериализуются как BSON-документ:
|
||
</para>
|
||
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
[0 => 1, 2 => 8, 3 => 12] => {"0": 1, "2": 8, "3": 12}
|
||
["foo" => 42] => {"foo": 42}
|
||
[1 => 9, 0 => 10] => {"1": 9, "0": 10}
|
||
]]>
|
||
</programlisting>
|
||
|
||
<para>
|
||
Обратите внимание, что пять приведённых примеров — <emphasis>выдержки</emphasis> из полного
|
||
документа и представляют только <emphasis>одно</emphasis> значение внутри
|
||
документа.
|
||
</para>
|
||
|
||
</section>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Объекты</title>
|
||
|
||
<para>
|
||
Если объект принадлежит типу <classname>stdClass</classname>, он сериализуется
|
||
как <emphasis>BSON-документ</emphasis>.
|
||
</para>
|
||
|
||
<para>
|
||
Если объект — поддерживаемый класс, который реализует
|
||
интерфейс <interfacename>MongoDB\BSON\Type</interfacename>, используется
|
||
логика сериализации BSON для этого конкретного типа.
|
||
Экземпляры с типом <interfacename>MongoDB\BSON\Type</interfacename> (исключая
|
||
тип <interfacename>MongoDB\BSON\Serializable</interfacename>) можно
|
||
сериализовать только как значение поля документа. Попытка сериализовать такой объект
|
||
как корневой документ выбросит исключение
|
||
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>.
|
||
</para>
|
||
|
||
<para>
|
||
Если объект принадлежит неизвестному классу, который реализует интерфейс
|
||
<interfacename>MongoDB\BSON\Type</interfacename>, выбрасывается исключение
|
||
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>.
|
||
</para>
|
||
|
||
<para>
|
||
Если объект принадлежит какому-либо другому классу без реализации какого-либо специального
|
||
интерфейса, он сериализуется как <emphasis>BSON-документ</emphasis>. Остаются только
|
||
открытые (<emphasis>public</emphasis>) свойства, а защищённые (<emphasis>protected</emphasis>)
|
||
и закрытые (<emphasis>private</emphasis>) свойства игнорируются.
|
||
</para>
|
||
|
||
<para>
|
||
Если объект принадлежит к классу, который реализует интерфейс
|
||
<interfacename>MongoDB\BSON\Serializable</interfacename>, вызывают
|
||
метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
и сериализуют массив или <classname>stdClass</classname>, которые возвращает метод,
|
||
как BSON-документ или как BSON-массив. Тип BSON определят следующие условия:
|
||
</para>
|
||
|
||
<para>
|
||
<orderedlist>
|
||
<listitem>
|
||
<para>Корневые документы требуется сериализовать
|
||
как BSON-документ.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
Объекты с типом <interfacename>MongoDB\BSON\Persistable</interfacename> требуется
|
||
сериализовать как BSON-документы.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
Если метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
возвращает упакованный массив, его сериализуют как BSON-массив.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
Если метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
возвращает неупакованный массив или объект <classname>stdClass</classname>,
|
||
его сериализуют как BSON-документ.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
Если метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
не вернул массив или объект <classname>stdClass</classname>, выбрасывается исключение
|
||
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>.
|
||
</para>
|
||
</listitem>
|
||
</orderedlist>
|
||
</para>
|
||
|
||
<para>
|
||
Если объект принадлежит классу, который реализует интерфейс
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename> (что
|
||
подразумевает реализацию метода <interfacename>MongoDB\BSON\Serializable</interfacename>),
|
||
свойства остаются по аналогии с предыдущими абзацами,
|
||
но <emphasis>также</emphasis> добавляется дополнительное свойство
|
||
<property>__pclass</property> в виде Binary-значения с подтипом
|
||
<literal>0x80</literal> и данными, которые содержат полное имя класса объекта,
|
||
который сериализуется.
|
||
</para>
|
||
|
||
<para>
|
||
Свойство <property>__pclass</property> добавляется в массив или
|
||
объект, который возвращает метод
|
||
<methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>,
|
||
что означает, что оно перезапишет любой ключ или свойство <property>__pclass</property>
|
||
в значении, которое возвращает метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>.
|
||
Если требуется избежать такого поведения и установить собственное значение
|
||
<property>__pclass</property>, <emphasis>вместо</emphasis>
|
||
реализации интерфейса <interfacename>MongoDB\BSON\Persistable</interfacename>
|
||
следует напрямую реализовать интерфейс
|
||
<interfacename>MongoDB\BSON\Serializable</interfacename>.
|
||
</para>
|
||
|
||
<section>
|
||
<title>Примеры</title>
|
||
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class stdClass
|
||
{
|
||
public $foo = 42;
|
||
} // => {"foo": 42}
|
||
|
||
class MyClass
|
||
{
|
||
public $foo = 42;
|
||
protected $prot = 'вино';
|
||
private $fpr = 'сыр';
|
||
} // => {"foo": 42}
|
||
|
||
class AnotherClass1 implements MongoDB\BSON\Serializable
|
||
{
|
||
public $foo = 42;
|
||
protected $prot = 'вино';
|
||
private $fpr = 'сыр';
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return ['foo' => $this->foo, 'prot' => $this->prot];
|
||
}
|
||
} // => {"foo": 42, "prot": "вино"}
|
||
|
||
class AnotherClass2 implements MongoDB\BSON\Serializable
|
||
{
|
||
public $foo = 42;
|
||
|
||
public function bsonSerialize(): self
|
||
{
|
||
return $this;
|
||
}
|
||
} // => MongoDB\Driver\Exception\UnexpectedValueException("bsonSerialize() did not return an array or stdClass")
|
||
|
||
class AnotherClass3 implements MongoDB\BSON\Serializable
|
||
{
|
||
private $elements = ['foo', 'bar'];
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return $this->elements;
|
||
}
|
||
} // => {"0": "foo", "1": "bar"}
|
||
|
||
/**
|
||
* Вложенные сериализуемые классы
|
||
*/
|
||
|
||
class AnotherClass4 implements MongoDB\BSON\Serializable
|
||
{
|
||
private $elements = [0 => 'foo', 2 => 'bar'];
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return $this->elements;
|
||
}
|
||
} // => {"0": "foo", "2": "bar"}
|
||
|
||
class ContainerClass1 implements MongoDB\BSON\Serializable
|
||
{
|
||
public $things;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->things = new AnotherClass4();
|
||
}
|
||
|
||
function bsonSerialize(): array
|
||
{
|
||
return ['things' => $this->things];
|
||
}
|
||
} // => {"things": {"0": "foo", "2": "bar"}}
|
||
|
||
|
||
class AnotherClass5 implements MongoDB\BSON\Serializable
|
||
{
|
||
private $elements = [0 => 'foo', 2 => 'bar'];
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return array_values($this->elements);
|
||
}
|
||
} // => {"0": "foo", "1": "bar"} as a root class
|
||
// ["foo", "bar"] as a nested value
|
||
|
||
class ContainerClass2 implements MongoDB\BSON\Serializable
|
||
{
|
||
public $things;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->things = new AnotherClass5();
|
||
}
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return ['things' => $this->things];
|
||
}
|
||
} // => {"things": ["foo", "bar"]}
|
||
|
||
|
||
class AnotherClass6 implements MongoDB\BSON\Serializable
|
||
{
|
||
private $elements = ['foo', 'bar'];
|
||
|
||
function bsonSerialize(): object
|
||
{
|
||
return (object) $this->elements;
|
||
}
|
||
} // => {"0": "foo", "1": "bar"}
|
||
|
||
class ContainerClass3 implements MongoDB\BSON\Serializable
|
||
{
|
||
public $things;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->things = new AnotherClass6();
|
||
}
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return ['things' => $this->things];
|
||
}
|
||
} // => {"things": {"0": "foo", "1": "bar"}}
|
||
|
||
class UpperClass implements MongoDB\BSON\Persistable
|
||
{
|
||
public $foo = 42;
|
||
protected $prot = 'вино';
|
||
private $fpr = 'сыр';
|
||
|
||
private $data;
|
||
|
||
public function bsonUnserialize(array $data): void
|
||
{
|
||
$this->data = $data;
|
||
}
|
||
|
||
public function bsonSerialize(): array
|
||
{
|
||
return ['foo' => $this->foo, 'prot' => $this->prot];
|
||
}
|
||
} // => {"foo": 42, "prot": "вино", "__pclass": {"$type": "80", "$binary": "VXBwZXJDbGFzcw=="}}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
<section xml:id="mongodb.persistence.deserialization">
|
||
<title>Десериализация из BSON</title>
|
||
|
||
&mongodb.warning.duplicate-keys;
|
||
|
||
<para>
|
||
Устаревший модуль <code>mongo</code> десериализовывал
|
||
BSON-документы и BSON-массивы в PHP-массивы. Хотя с PHP-массивами
|
||
удобно работать, такое поведение было проблематичным, поскольку разные
|
||
BSON-типы могли десериализоваться до одного и того же PHP-значения (например,
|
||
<literal>{"0": "foo"}</literal> и <literal>["foo"]</literal>), что делало
|
||
невозможным определение оригинального BSON-типа. По умолчанию модуль <code>mongodb</code>
|
||
решает эту проблему и гарантирует, что BSON-массивы преобразуются в PHP-массивы, а BSON-документы
|
||
в PHP-объекты.
|
||
</para>
|
||
|
||
<para>
|
||
Для составных типов существует три типа данных:
|
||
</para>
|
||
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>root</term>
|
||
<listitem>
|
||
<para>
|
||
относится <emphasis>только</emphasis> к BSON-документу верхнего уровня
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>document</term>
|
||
<listitem>
|
||
<para>
|
||
относится <emphasis>только</emphasis> к встроенным BSON-документам
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>array</term>
|
||
<listitem>
|
||
<para>
|
||
относится к BSON-массивам
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
|
||
<para>
|
||
Помимо трёх групповых типов, также можно настроить
|
||
определённые поля в документе для сопоставления с типами данных, как указывает следующий фрагмент кода.
|
||
В качестве примера, следующая карта типов позволяет
|
||
сопоставить каждый встроенный документ в массиве <literal>«addresses»</literal>
|
||
с классом <classname>Address</classname>, <emphasis>а</emphasis> каждое
|
||
поле <literal>«city»</literal> в этих документах с встроенным адресом
|
||
с классом <classname>City</classname>:
|
||
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
[
|
||
'fieldPaths' => [
|
||
'addresses.$' => 'MyProject\Address',
|
||
'addresses.$.city' => 'MyProject\City',
|
||
],
|
||
]
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
Каждый из этих трёх типов данных, а также сопоставления конкретных полей
|
||
можно сопоставить с различными типами PHP. Возможные значения сопоставления:
|
||
</para>
|
||
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term><emphasis>не указано</emphasis> или <type>NULL</type> (по умолчанию)</term>
|
||
<listitem>
|
||
<para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>
|
||
BSON-массив будет десериализован как PHP-массив (<type>array</type>).
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
BSON-документ (корневой или встроенный) без свойства
|
||
<property>__pclass</property>
|
||
<footnote xml:id="mongodb.pclass">
|
||
<para>
|
||
Свойство __pclass считается существующим, только
|
||
если существует свойство с таким именем, и оно представляет собой Binary-значение,
|
||
а подтип Binary значения равен 0x80. Если какое-либо из этих трёх
|
||
условий не выполняется, свойство __pclass не существует
|
||
и должно рассматриваться как любое другое обычное свойство.
|
||
</para>
|
||
</footnote>
|
||
становится PHP-объектом <classname>stdClass</classname>, причём каждый
|
||
ключ BSON-документа устанавливается как открытое
|
||
свойство объекта <classname>stdClass</classname>.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
BSON-документ (корневой или встроенный) со свойством
|
||
<property>__pclass</property> <footnoteref linkend="mongodb.pclass"/> становится PHP-объектом
|
||
имени класса, как это определяет свойство <property>__pclass</property>.
|
||
</para>
|
||
<para>
|
||
Если именованный класс реализует интерфейс
|
||
M<interfacename>MongoDB\BSON\Persistable</interfacename>,
|
||
то свойства BSON-документа, включая свойство
|
||
<property>__pclass</property>, отправляются как ассоциативный
|
||
массив в метод
|
||
<methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>,
|
||
чтобы инициализировать свойства объекта.
|
||
</para>
|
||
<para>
|
||
Если именованный класс не существует или не реализует интерфейс
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename>,
|
||
будет использоваться объект <classname>stdClass</classname>, и каждый ключ BSON-документа
|
||
(включая свойство <property>__pclass</property>) будет установлен
|
||
как открытое свойство объекта <classname>stdClass</classname>.
|
||
</para>
|
||
<para>
|
||
Функциональность свойства <property>__pclass</property> зависит от того, представляет ли
|
||
собой свойство часть извлечённого документа БД MongoDB. Если при запросе документов
|
||
используется <link linkend="mongodb-driver-query.construct-queryOptions">проекция</link>,
|
||
необходимо включить в проекцию поле <property>__pclass</property>,
|
||
чтобы эта функциональность работала.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term><literal>«array»</literal></term>
|
||
<listitem>
|
||
<para>
|
||
Превращает BSON-массив или BSON-документ в PHP-массив. Специальной обработки
|
||
свойства <property>__pclass</property> <footnoteref linkend="mongodb.pclass"/> не будет,
|
||
но его можно установить как элемент в возвращаемом массиве, если он
|
||
содержался в BSON-документе.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term><literal>«object»</literal> или <literal>«stdClass»</literal></term>
|
||
<listitem>
|
||
<para>
|
||
Превращает BSON-массив или BSON-документ в объект
|
||
<classname>stdClass</classname>. Специальной
|
||
обработки свойства <property>__pclass</property> <footnoteref linkend="mongodb.pclass"/> не будет,
|
||
но его можно установить как открытое свойство в возвращаемом объекте, если оно присутствовало
|
||
в BSON-документе.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term><literal>«bson»</literal></term>
|
||
<listitem>
|
||
<para>
|
||
Превращает BSON-массив в объект <classname>MongoDB\BSON\PackedArray</classname>,
|
||
а BSON-документ в объект <classname>MongoDB\BSON\Document</classname>,
|
||
независимо от того, есть ли у BSON-документа свойство <property>__pclass</property>
|
||
<footnoteref linkend="mongodb.pclass"/>.
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Значение <literal>bson</literal> доступно только для трёх корневых типов,
|
||
но не в отображениях для конкретных полей.
|
||
</simpara>
|
||
</note>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term>любая другая строка</term>
|
||
<listitem>
|
||
<para>
|
||
Определяет имя класса, который должен десериализовать BSON-массив
|
||
или BSON-объект. Для BSON-объектов, которые содержат свойства
|
||
<property>__pclass</property>, этот класс будет приоритетным.
|
||
</para>
|
||
|
||
<para>
|
||
Если именованный класс не существует, не представляет собой конкретный класс (то есть это
|
||
абстрактный класс или интерфейс) или не реализует
|
||
интерфейс <interfacename>MongoDB\BSON\Unserializable</interfacename>, выбрасывается исключение
|
||
<classname>MongoDB\Driver\Exception\InvalidArgumentException</classname>.
|
||
</para>
|
||
|
||
<para>
|
||
Если BSON-объект содержит свойство <property>__pclass</property> и
|
||
этот класс существует и реализует
|
||
интерфейс <interfacename>MongoDB\BSON\Persistable</interfacename>,
|
||
он заменит класс, представленный в карте типов.
|
||
</para>
|
||
|
||
<para>
|
||
Свойства BSON-документа, <emphasis>включая</emphasis>
|
||
свойство <property>__pclass</property>, если оно существует, отправляются
|
||
как ассоциативный массив в метод
|
||
<methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>,
|
||
чтобы инициализировать свойства объекта.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
|
||
<section xml:id="mongodb.persistence.typemaps">
|
||
<title>TypeMaps</title>
|
||
|
||
<para>
|
||
Функции настройки TypeMaps можно установить методом
|
||
<methodname>MongoDB\Driver\Cursor::setTypeMap</methodname> для объекта
|
||
<classname>MongoDB\Driver\Cursor</classname> или аргумента
|
||
<literal>$typeMap</literal>
|
||
в методах <function>MongoDB\BSON\toPHP</function>,
|
||
<methodname>MongoDB\BSON\Document::toPHP</methodname>
|
||
и <methodname>MongoDB\BSON\PackedArray::toPHP</methodname>. Каждый из трёх
|
||
классов (<emphasis>root</emphasis>, <emphasis>document</emphasis>, и
|
||
<emphasis>array</emphasis>) можно задать индивидуально, в дополнение
|
||
к типам полей.
|
||
</para>
|
||
|
||
<para>
|
||
Если значение на карте равно <type>NULL</type>, это означает то же,
|
||
что и значение <emphasis>по умолчанию</emphasis> для этого элемента.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Примеры</title>
|
||
|
||
<para>
|
||
В этих примерах используются следующие классы:
|
||
</para>
|
||
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>MyClass</term>
|
||
<listitem>
|
||
<para>
|
||
<emphasis>не</emphasis> реализует интерфейсы
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>YourClass</term>
|
||
<listitem>
|
||
<para>
|
||
реализует интерфейс
|
||
<interfacename>MongoDB\BSON\Unserializable</interfacename>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>OurClass</term>
|
||
<listitem>
|
||
<para>
|
||
реализует интерфейс
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>TheirClass</term>
|
||
<listitem>
|
||
<para>
|
||
расширяет класс OurClass
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
|
||
<para>
|
||
Метод <methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>
|
||
классов YourClass, OurClass, OurClass выполняет итерацию по массиву и устанавливает
|
||
свойства без изменений. Метод <emphasis>также</emphasis> устанавливает для свойства
|
||
<literal>$unserialized</literal> значение &true;:
|
||
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function bsonUnserialize(array $map)
|
||
{
|
||
foreach ($map as $k => $value) {
|
||
$this->$k = $value;
|
||
}
|
||
$this->unserialized = true;
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
/* typemap: [] (все значения по умолчанию) */
|
||
{"foo": "yes", "bar" : false}
|
||
-> stdClass {$foo => 'yes', $bar => false}
|
||
|
||
{"foo": "no", "array" : [5, 6]}
|
||
-> stdClass {$foo => 'no', $array => [5, 6]}
|
||
|
||
{"foo": "no", "obj" : {"embedded" : 3.14}}
|
||
-> stdClass {$foo => 'no', $obj => stdClass {$embedded => 3.14}}
|
||
|
||
{"foo": "yes", "__pclass": "MyClass"}
|
||
-> stdClass {$foo => 'yes', $__pclass => 'MyClass'}
|
||
|
||
{"foo": "yes", "__pclass": {"$type" : "80", "$binary" : "MyClass"}}
|
||
-> stdClass {$foo => 'yes', $__pclass => Binary(0x80, 'MyClass')}
|
||
|
||
{"foo": "yes", "__pclass": {"$type" : "80", "$binary" : "YourClass")}
|
||
-> stdClass {$foo => 'yes', $__pclass => Binary(0x80, 'YourClass')}
|
||
|
||
{"foo": "yes", "__pclass": {"$type" : "80", "$binary" : "OurClass")}
|
||
-> OurClass {$foo => 'yes', $__pclass => Binary(0x80, 'OurClass'), $unserialized => true}
|
||
|
||
{"foo": "yes", "__pclass": {"$type" : "44", "$binary" : "YourClass")}
|
||
-> stdClass {$foo => 'yes', $__pclass => Binary(0x44, 'YourClass')}
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
/* typemap: ["root" => "MissingClass"] */
|
||
{"foo": "yes"}
|
||
-> MongoDB\Driver\Exception\InvalidArgumentException("MissingClass does not exist")
|
||
|
||
/* typemap: ["root" => "MyClass"] */
|
||
{"foo": "yes", "__pclass" : {"$type": "80", "$binary": "MyClass"}}
|
||
-> MongoDB\Driver\Exception\InvalidArgumentException("MyClass does not implement Unserializable interface")
|
||
|
||
/* typemap: ["root" => "MongoDB\BSON\Unserializable"] */
|
||
{"foo": "yes"}
|
||
-> MongoDB\Driver\Exception\InvalidArgumentException("Unserializable is not a concrete class")
|
||
|
||
/* typemap: ["root" => "YourClass"] */
|
||
{"foo": "yes", "__pclass" : {"$type": "80", "$binary": "MongoDB\BSON\Unserializable"}}
|
||
-> YourClass {$foo => "yes", $__pclass => Binary(0x80, "MongoDB\BSON\Unserializable"), $unserialized => true}
|
||
|
||
/* typemap: ["root" => "YourClass"] */
|
||
{"foo": "yes", "__pclass" : {"$type": "80", "$binary": "MyClass"}}
|
||
-> YourClass {$foo => "yes", $__pclass => Binary(0x80, "MyClass"), $unserialized => true}
|
||
|
||
/* typemap: ["root" => "YourClass"] */
|
||
{"foo": "yes", "__pclass" : {"$type": "80", "$binary": "OurClass"}}
|
||
-> OurClass {$foo => "yes", $__pclass => Binary(0x80, "OurClass"), $unserialized => true}
|
||
|
||
/* typemap: ["root" => "YourClass"] */
|
||
{"foo": "yes", "__pclass" : {"$type": "80", "$binary": "TheirClass"}}
|
||
-> TheirClass {$foo => "yes", $__pclass => Binary(0x80, "TheirClass"), $unserialized => true}
|
||
|
||
/* typemap: ["root" => "OurClass"] */
|
||
{ foo: "yes", "__pclass" : {"$type": "80", "$binary": "TheirClass"}}
|
||
-> TheirClass {$foo => "yes", $__pclass => Binary(0x80, "TheirClass"), $unserialized => true}
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
/* typemap: ['root' => 'YourClass'] */
|
||
{foo: "yes", "__pclass": {"$type": "80", "$binary": "YourClass"}}
|
||
-> YourClass {$foo => 'yes', $__pclass => Binary(0x80, 'YourClass'), $unserialized => true}
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
/* typemap: ['root' => 'array', 'document' => 'array'] */
|
||
{"foo": "yes", "bar": false}
|
||
-> ["foo" => "yes", "bar" => false]
|
||
|
||
{"foo": "no", "array": [5, 6]}
|
||
-> ["foo" => "no", "array" => [5, 6]]
|
||
|
||
{"foo": "no", "obj": {"embedded": 3.14}}
|
||
-> ["foo" => "no", "obj" => ["embedded => 3.14]]
|
||
|
||
{"foo": "yes", "__pclass": "MyClass"}
|
||
-> ["foo" => "yes", "__pclass" => "MyClass"]
|
||
|
||
{"foo": "yes", "__pclass": {"$type": "80", "$binary": "MyClass"}}
|
||
-> ["foo" => "yes", "__pclass" => Binary(0x80, "MyClass")]
|
||
|
||
{"foo": "yes", "__pclass": {"$type": "80", "$binary": "OurClass"}}
|
||
-> ["foo" => "yes", "__pclass" => Binary(0x80, "OurClass")]
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
/* typemap: ['root' => 'object', 'document' => 'object'] */
|
||
{"foo": "yes", "__pclass": {"$type": "80", "$binary": "MyClass"}}
|
||
-> stdClass {$foo => "yes", "__pclass" => Binary(0x80, "MyClass")}
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
</section>
|
||
</section>
|
||
|
||
</section>
|
||
</chapter>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|