mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-19 02:18:56 +00:00

Provided by sergey git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@347472 c90b9560-bf6c-de11-be94-00142212c4b1
942 lines
33 KiB
XML
942 lines
33 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- $Revision$ -->
|
||
|
||
<book xml:id="mongodb.architecture" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<titleabbrev>Driver Architecture and Internals</titleabbrev>
|
||
<title>Explains the driver architecture, and special features</title>
|
||
|
||
<article xml:id="mongodb.overview">
|
||
<titleabbrev>Architecture</titleabbrev>
|
||
<title>Architecture Overview</title>
|
||
|
||
<para>
|
||
This section explains how all the different parts of the driver fit
|
||
together. From the different language runtimes, through the extension and
|
||
to the PHP libraries on top. This new architecture has replaced the old
|
||
<link linkend="book.mongo">mongo</link> extension. We refer to the new one
|
||
as the <emphasis>mongodb</emphasis> extension.
|
||
</para>
|
||
|
||
<para>
|
||
<mediaobject>
|
||
<alt>Architecture Diagram</alt>
|
||
<imageobject>
|
||
<imagedata fileref="en/reference/mongodb/images/driver_arch.png"/>
|
||
</imageobject>
|
||
</mediaobject>
|
||
</para>
|
||
|
||
<para>
|
||
At the top of this stack sits a pure
|
||
<link xlink:href="&url.mongodb.library;">PHP library</link>, which we will
|
||
distribute as a Composer package. This library will provide an API similar
|
||
to what users have come to expect from the old mongo driver (e.g. CRUD methods,
|
||
database and collection objects, command helpers) and we expect it to be a
|
||
common dependency for most applications built with MongoDB. This library
|
||
will also implement common
|
||
<link xlink:href="&url.mongodb.specs;">specifications</link>, in the
|
||
interest of improving API consistency across all of the
|
||
<link xlink:href="&url.mongodb.drivers;">drivers</link> maintained by
|
||
MongoDB (and hopefully some community drivers, too).
|
||
</para>
|
||
|
||
<para>
|
||
Sitting below that library we have the lower level driver.
|
||
This extension will effectively form the glue between PHP and our
|
||
system libraries (<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> and
|
||
<link xlink:href="&url.mongodb.libbson;">libbson</link>). This extension
|
||
will expose an identical public API for the most essential and
|
||
performance-sensitive functionality:
|
||
|
||
<simplelist>
|
||
<member>Connection management</member>
|
||
<member>BSON encoding and decoding</member>
|
||
<member>Object document serialization (to support ODM libraries)</member>
|
||
<member>Executing commands and write operations</member>
|
||
<member>Handling queries and cursors</member>
|
||
</simplelist>
|
||
</para>
|
||
|
||
<para>
|
||
By decoupling the driver internals and a high-level API into an extension and
|
||
PHP libraries, respectively, we hope to reduce our maintainence burden and
|
||
allow for faster iteration on new features. As a welcome side effect, this
|
||
also makes it easier for anyone to contribute to the driver. Additionally,
|
||
an identical public API will make it that much easier to port an
|
||
application across PHP runtimes, whether the application uses the low-level
|
||
driver directly or a higher-level PHP library.
|
||
</para>
|
||
<para>
|
||
<link xlink:href="&url.mongodb.docs.gridfs;">GridFS</link> is a great example
|
||
of why we chose this direction.
|
||
Although we implemented GridFS in C for our old mongo driver, it is actually
|
||
quite a high-level specification. Its API is just an abstraction for
|
||
accessing two collections: files (i.e. metadata) and chunks (i.e. blocks of
|
||
data). Likewise, all of the syntactic sugar found in the old mongo driver,
|
||
such as processing uploaded files or exposing GridFS files as PHP streams,
|
||
can be implemented in pure PHP. Provided we have performant methods for
|
||
reading from and writing to GridFS' collections – and thanks to our low
|
||
level extensions, we will – shifting this API to PHP is win-win.
|
||
</para>
|
||
<para>
|
||
Earlier I mentioned that we expect the PHP library to be a common
|
||
dependency for <emphasis>most</emphasis> applications, but not
|
||
<emphasis>all</emphasis>. Some users may prefer to stick to the no-frills
|
||
API offered by the extensions, or create their own high-level abstraction
|
||
(akin to <link xlink:href="&url.mongodb.doctrine;">Doctrine MongoDB</link> for
|
||
the old mongo driver). Future libraries could include a PHP library geared
|
||
for MongoDB administration, which provides an API for various user
|
||
management and ops commands. The next major version of
|
||
<link xlink:href="&url.mongodb.doctrine-odm;">Doctrine MongoDB ODM</link> will
|
||
likely also sit directly atop the extensions.
|
||
</para>
|
||
<para>
|
||
While we will continue to maintain and support the old mongo driver and its
|
||
users for the foreseeable future, we invite everyone to use the
|
||
next-generation driver and consider it for any new projects going forward.
|
||
You can find all of the essential components across GitHub and JIRA:
|
||
|
||
<table>
|
||
<title>Driver Source Code and JIRA Locations</title>
|
||
<tgroup cols="3">
|
||
<thead>
|
||
<row>
|
||
<entry>Project</entry>
|
||
<entry>GitHub</entry>
|
||
<entry>JIRA</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>PHP Library</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 5 and PHP 7 Driver (phongo)</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>
|
||
|
||
<para>
|
||
The existing <link xlink:href="&url.mongodb.jira;">PHP</link> project in JIRA
|
||
will remain open for reporting bugs against the old mongo driver, but we
|
||
would ask that you use the new projects above for anything pertaining to
|
||
our next-generation drivers.
|
||
</para>
|
||
</article>
|
||
|
||
<article xml:id="mongodb.connection-handling">
|
||
<titleabbrev>Connections</titleabbrev>
|
||
<title>Connection handling and persistence</title>
|
||
|
||
&mongodb.note.forking;
|
||
|
||
<section>
|
||
<title>Connection and topology persistence (PHP version since 1.2.0)</title>
|
||
|
||
<para>
|
||
All versions of the driver since 1.2.0 persist the
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> client object in
|
||
the PHP worker process, which allows it to re-use database connections,
|
||
authentication states, <emphasis>and</emphasis> topology information across
|
||
multiple requests.
|
||
</para>
|
||
|
||
<para>
|
||
When <methodname>MongoDB\Driver\Manager::__construct</methodname> is
|
||
invoked, a hash is created from its arguments (i.e. URI string and array
|
||
options). The driver will attempt to find a previously persisted
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> client object for
|
||
that hash. If an existing client cannot be found for the hash, a new client
|
||
will be created (and persisted for future use).
|
||
</para>
|
||
|
||
<para>
|
||
Each client contains its own database connections and a view of the server
|
||
topology (e.g. standalone, replica set, shard cluster). By persisting the
|
||
client between PHP requests, the driver is able to re-use established
|
||
database connections and remove the need for
|
||
<link xlink:href="&url.mongodb.sdam;">discovering the server topology</link>
|
||
on each request.
|
||
</para>
|
||
|
||
<para>
|
||
Consider the following example:
|
||
</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>
|
||
The first two Manager objects will share the same
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> client since
|
||
their constructor arguments are identical. The third and fourth objects will
|
||
each use their own client. In total, three clients will be created and the
|
||
PHP worker executing this script will open two connections to
|
||
<literal>127.0.0.1</literal> and one connection to each of
|
||
<literal>rs1.example.com</literal> and <literal>rs2.example.com</literal>.
|
||
If the driver discovers additional members of the replica set after issuing
|
||
<literal>isMaster</literal> commands, it will open additional connections to
|
||
those servers as well.
|
||
</para>
|
||
|
||
<para>
|
||
If the same worker executes the script again in a second request, the three
|
||
clients will be re-used and no new connections should be made. Depending on
|
||
how long ago the previous request was served, the driver may need to issue
|
||
additional <literal>isMaster</literal> commands to update its view of the
|
||
topologies.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Socket persistence (PHP versions before 1.2.0)</title>
|
||
|
||
<para>
|
||
Versions of the PHP driver before 1.2.0 utilize PHP's Streams API for
|
||
database connections, using an API within
|
||
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> to designate
|
||
custom handlers for socket communication; however, a new libmongoc client is
|
||
created for each <classname>MongoDB\Driver\Manager</classname>. As a result,
|
||
the driver persists individual database connections but not authentication
|
||
state or topology information. This means that the driver needs to issue
|
||
commands at the start of each request to authenticate and
|
||
<link xlink:href="&url.mongodb.sdam;">discover the server topology</link>.
|
||
</para>
|
||
|
||
<para>
|
||
Database connections are persisted by a hash derived from the server's
|
||
host, port, and the URI string used to construct the
|
||
<classname>MongoDB\Driver\Manager</classname>. The constructor's array
|
||
options are not included in this hash.
|
||
</para>
|
||
|
||
<note>
|
||
<simpara>
|
||
Versions of the driver >= 1.1.8 and < 1.2.0 do not persist sockets
|
||
for SSL connections. See
|
||
<link xlink:href="&url.mongodb.jira.phpc;-720">PHPC-720</link> for
|
||
additional information.
|
||
</simpara>
|
||
</note>
|
||
|
||
<para>
|
||
Despite its shortcomings with persisting SSL connections when and topology
|
||
information, this version of the driver supports all
|
||
<link linkend="context.ssl">SSL context options</link> since it uses
|
||
PHP's Streams API.
|
||
</para>
|
||
</section>
|
||
</article>
|
||
|
||
<article xml:id="mongodb.persistence">
|
||
<titleabbrev>Persisting Data</titleabbrev>
|
||
<title>Serialization and deserialization of PHP variables into MongoDB</title>
|
||
|
||
<para>
|
||
This document discusses the methods how compound structures (documents,
|
||
arrays, objects) are persisted through the drivers. And how they are brought
|
||
back into PHP land.
|
||
</para>
|
||
|
||
<section xml:id="mongodb.persistence.serialization">
|
||
<title>Serialization to BSON</title>
|
||
|
||
<section>
|
||
<title>Arrays</title>
|
||
|
||
<para>
|
||
If an array is a <emphasis>packed array</emphasis> — i.e. the keys start
|
||
at 0 and are sequential without gaps: <emphasis>BSON array</emphasis>.
|
||
</para>
|
||
|
||
<para>
|
||
If the array is not packed — i.e. having associative (string) keys, the
|
||
keys don't start at 0, or when there are gaps:: <emphasis>BSON
|
||
object</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
A top-level (root) document, <emphasis>always</emphasis> serializes as a
|
||
BSON document.
|
||
</para>
|
||
|
||
<section>
|
||
<title>Examples</title>
|
||
|
||
<para>
|
||
These serialize as a BSON array:
|
||
</para>
|
||
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
[ 8, 5, 2, 3 ] => [ 8, 5, 2, 3 ]
|
||
[ 0 => 4, 1 => 9 ] => [ 4, 9 ]
|
||
]]>
|
||
</programlisting>
|
||
|
||
<para>
|
||
These serialize as a BSON document:
|
||
</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>
|
||
Note that the five examples are <emphasis>extracts</emphasis> of a full
|
||
document, and represent only <emphasis>one</emphasis> value inside a
|
||
document.
|
||
</para>
|
||
|
||
</section>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Objects</title>
|
||
|
||
<para>
|
||
If an object is of the <classname>stdClass</classname> class, serialize
|
||
as a <emphasis>BSON document</emphasis>.
|
||
</para>
|
||
|
||
<para>
|
||
If an object is a supported class that implements
|
||
<interfacename>MongoDB\BSON\Type</interfacename>, then use the BSON
|
||
serialization logic for that specific type.
|
||
<interfacename>MongoDB\BSON\Type</interfacename> instances (excluding
|
||
<interfacename>MongoDB\BSON\Serializable</interfacename> may only be
|
||
serialized as a document field value. Attempting to serialize such an
|
||
object as a root document will throw a
|
||
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>
|
||
</para>
|
||
|
||
<para>
|
||
If an object is of an unknown class implementing the
|
||
<interfacename>MongoDB\BSON\Type</interfacename> interface, then throw a
|
||
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>
|
||
</para>
|
||
|
||
<para>
|
||
If an object is of any other class, without implementing any special
|
||
interface, serialize as a <emphasis>BSON document</emphasis>. Keep only
|
||
<emphasis>public</emphasis> properties, and ignore
|
||
<emphasis>protected</emphasis> and <emphasis>private</emphasis>
|
||
properties.
|
||
</para>
|
||
|
||
<para>
|
||
If an object is of a class that implements the
|
||
<interfacename>MongoDB\BSON\Serializable</interfacename> interface, call
|
||
<methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname> and use
|
||
the returned array or <classname>stdClass</classname> to serialize as a
|
||
BSON document or array. The BSON type will be determined by the following:
|
||
</para>
|
||
|
||
<para>
|
||
<orderedlist>
|
||
<listitem>
|
||
<para>Root documents must be serialized as a BSON
|
||
document.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename> objects must be
|
||
serialized as a BSON document.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
If <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
returns a packed array, serialize as a BSON array.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
If <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
returns a non-packed array or <classname>stdClass</classname>,
|
||
serialize as a BSON document.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
If <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
did not return an array or <classname>stdClass</classname>, throw an
|
||
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>
|
||
exception.
|
||
</para>
|
||
</listitem>
|
||
</orderedlist>
|
||
</para>
|
||
|
||
<para>
|
||
If an object is of a class that implements the
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename> interface (which
|
||
implies <interfacename>MongoDB\BSON\Serializable</interfacename>), obtain
|
||
the properties in a similar way as in the previous paragraphs, but
|
||
<emphasis>also</emphasis> add an additional property
|
||
<property>__pclass</property> as a Binary value, with subtype
|
||
<literal>0x80</literal> and data bearing the fully qualified class name
|
||
of the object that is being serialized.
|
||
</para>
|
||
|
||
<para>
|
||
The <property>__pclass</property> property is added to the array or
|
||
object returned by
|
||
<methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>, which
|
||
means it will overwrite any <property>__pclass</property> key/property in
|
||
the <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
|
||
return value. If you want to avoid this behaviour and set your own
|
||
<property>__pclass</property> value, you must <emphasis>not</emphasis>
|
||
implement <interfacename>MongoDB\BSON\Persistable</interfacename> and
|
||
should instead implement
|
||
<interfacename>MongoDB\BSON\Serializable</interfacename> directly.
|
||
</para>
|
||
|
||
<section>
|
||
<title>Examples</title>
|
||
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class stdClass {
|
||
public $foo = 42;
|
||
} // => { "foo" : 42 }
|
||
|
||
class MyClass {
|
||
public $foo = 42;
|
||
protected $prot = "wine";
|
||
private $fpr = "cheese";
|
||
} // => { "foo" : 42 }
|
||
|
||
class AnotherClass1 implements MongoDB\BSON\Serializable {
|
||
public $foo = 42;
|
||
protected $prot = "wine";
|
||
private $fpr = "cheese";
|
||
function bsonSerialize() {
|
||
return [ 'foo' => $this->foo, 'prot' => $this->prot ];
|
||
}
|
||
} // => { "foo" : 42, "prot" : "wine" }
|
||
|
||
class AnotherClass2 implements MongoDB\BSON\Serializable {
|
||
public $foo = 42;
|
||
function bsonSerialize() {
|
||
return $this;
|
||
}
|
||
} // => MongoDB\Driver\Exception\UnexpectedValueException("bsonSerialize() did not return an array or stdClass")
|
||
|
||
class AnotherClass3 implements MongoDB\BSON\Serializable {
|
||
private $elements = [ 'foo', 'bar' ];
|
||
function bsonSerialize() {
|
||
return $this->elements;
|
||
}
|
||
} // => { "0" : "foo", "1" : "bar" }
|
||
|
||
class ContainerClass implements MongoDB\BSON\Serializable {
|
||
public $things = AnotherClass4 implements MongoDB\BSON\Serializable {
|
||
private $elements = [ 0 => 'foo', 2 => 'bar' ];
|
||
function bsonSerialize() {
|
||
return $this->elements;
|
||
}
|
||
}
|
||
function bsonSerialize() {
|
||
return [ 'things' => $this->things ];
|
||
}
|
||
} // => { "things" : { "0" : "foo", "2" : "bar" } }
|
||
|
||
class ContainerClass implements MongoDB\BSON\Serializable {
|
||
public $things = AnotherClass5 implements MongoDB\BSON\Serializable {
|
||
private $elements = [ 0 => 'foo', 2 => 'bar' ];
|
||
function bsonSerialize() {
|
||
return array_values($this->elements);
|
||
}
|
||
}
|
||
function bsonSerialize() {
|
||
return [ 'things' => $this->things ];
|
||
}
|
||
} // => { "things" : [ "foo", "bar" ] }
|
||
|
||
class ContainerClass implements MongoDB\BSON\Serializable {
|
||
public $things = AnotherClass6 implements MongoDB\BSON\Serializable {
|
||
private $elements = [ 'foo', 'bar' ];
|
||
function bsonSerialize() {
|
||
return (object) $this->elements;
|
||
}
|
||
}
|
||
function bsonSerialize() {
|
||
return [ 'things' => $this->things ];
|
||
}
|
||
} // => { "things" : { "0" : "foo", "1" : "bar" } }
|
||
|
||
class UpperClass implements MongoDB\BSON\Persistable {
|
||
public $foo = 42;
|
||
protected $prot = "wine";
|
||
private $fpr = "cheese";
|
||
function bsonSerialize() {
|
||
return [ 'foo' => $this->foo, 'prot' => $this->prot ];
|
||
}
|
||
} // => { "foo" : 42, "prot" : "wine", "__pclass" : { "$type" : "80", "$binary" : "VXBwZXJDbGFzcw==" } }
|
||
]]>
|
||
</programlisting>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
<section xml:id="mongodb.persistence.deserialization">
|
||
<title>Deserialization from BSON</title>
|
||
|
||
<para>
|
||
The legacy <link linkend="book.mongo">mongo</link> extension deserialized
|
||
both BSON documents and arrays as PHP arrays. While PHP arrays are
|
||
convenient to work with, this behavior was problematic because different
|
||
BSON types could deserialize to the same PHP value (e.g.
|
||
<literal>{"0": "foo"}</literal> and <literal>["foo"]</literal>) and make it
|
||
impossible to infer the original BSON type. By default, the current driver
|
||
addresses this concern by ensuring that BSON arrays and documents are
|
||
converted to PHP arrays and objects, respectively.
|
||
</para>
|
||
|
||
<para>
|
||
For compound types, there are three data types:
|
||
</para>
|
||
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>root</term>
|
||
<listitem>
|
||
<para>
|
||
refers to the top-level BSON document <emphasis>only</emphasis>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>document</term>
|
||
<listitem>
|
||
<para>
|
||
refers to embedded BSON documents <emphasis>only</emphasis>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>array</term>
|
||
<listitem>
|
||
<para>
|
||
refers to a BSON array
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
|
||
<para>
|
||
Besides the three collective types, it is also possible to configure
|
||
specific fields in your document to map to the data types mentioned below.
|
||
As an example, the following type map allows you to
|
||
map each embedded document within an <literal>"addresses"</literal> array to
|
||
an <classname>Address</classname> class <emphasis>and</emphasis> each
|
||
<literal>"city"</literal> field within those embedded address documents to
|
||
a <classname>City</classname> class:
|
||
|
||
<programlisting role="text">
|
||
<![CDATA[
|
||
[
|
||
'fieldPaths' => [
|
||
'addresses.$' => 'MyProject\Address',
|
||
'addresses.$.city' => 'MyProject\City',
|
||
],
|
||
]
|
||
]]>
|
||
</programlisting>
|
||
</para>
|
||
|
||
<para>
|
||
Each of those three data types, as well as the field specific mappings,
|
||
can be mapped against different PHP types. The possible mapping values
|
||
are:
|
||
</para>
|
||
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term><emphasis>not set</emphasis> or <type>NULL</type> (default)</term>
|
||
<listitem>
|
||
<para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>
|
||
A BSON array will be deserialized as a PHP <type>array</type>.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
A BSON document (root or embedded) without a
|
||
<property>__pclass</property> property
|
||
<footnote xml:id="mongodb.pclass">
|
||
<para>
|
||
A __pclass property is only deemed to exist if
|
||
there exists a property with that name, and it is a Binary value,
|
||
and the sub-type of the Binary value is 0x80. If any of these three
|
||
conditions is not met, the __pclass property does not exist and
|
||
should be treated as any other normal property.
|
||
</para>
|
||
</footnote>
|
||
becomes a PHP <classname>stdClass</classname> object, with each
|
||
BSON document key set as a public <classname>stdClass</classname>
|
||
property.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
A BSON document (root or embedded) with a
|
||
<property>__pclass</property> property <footnoteref linkend="mongodb.pclass"/> becomes a PHP object of
|
||
the class name as defined by the <property>__pclass</property>
|
||
property.
|
||
</para>
|
||
<para>
|
||
If the named class implements the
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename> interface,
|
||
then the properties of the BSON document, including the
|
||
<property>__pclass</property> property, are sent as an associative
|
||
array to the
|
||
<methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>
|
||
function to initialise the object's properties.
|
||
</para>
|
||
<para>
|
||
If the named class does not exist or does not implement the
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename> interface,
|
||
<classname>stdClass</classname> will be used and each BSON document
|
||
key (including <property>__pclass</property>) will be set as a
|
||
public <classname>stdClass</classname> property.
|
||
</para>
|
||
<para>
|
||
The <property>__pclass</property> functionality relies on the
|
||
property being part of a retrieved MongoDB document. If you use a
|
||
<link linkend="mongodb-driver-query.construct-queryOptions">projection</link>
|
||
when querying for documents, you need to include the
|
||
<property>__pclass</property> field in the projection for this
|
||
functionality to work.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term><literal>"array"</literal></term>
|
||
<listitem>
|
||
<para>
|
||
Turns a BSON array or BSON document into a PHP array. There will be no
|
||
special treatment of a <property>__pclass</property> property <footnoteref linkend="mongodb.pclass"/>,
|
||
but it may be set as an element in the returned array if it was
|
||
present in the BSON document.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term><literal>"object"</literal> or <literal>"stdClass"</literal></term>
|
||
<listitem>
|
||
<para>
|
||
Turns a BSON array or BSON document into a
|
||
<classname>stdClass</classname> object. There will be no special
|
||
treatment of a <property>__pclass</property> property <footnoteref linkend="mongodb.pclass"/>, but it may
|
||
be set as a public property in the returned object if it was present
|
||
in the BSON document.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry>
|
||
<term>any other string</term>
|
||
<listitem>
|
||
<para>
|
||
Defines the class name that the BSON array or BSON object should be
|
||
deserialized as. For BSON objects that include
|
||
<property>__pclass</property> properties, that class will take
|
||
priority.
|
||
</para>
|
||
|
||
<para>
|
||
If the named class does not exist, is not concrete (i.e. it is
|
||
abstract or an interface), or does not implement
|
||
<interfacename>MongoDB\BSON\Unserializable</interfacename> then an
|
||
<classname>MongoDB\Driver\Exception\InvalidArgumentException</classname>
|
||
exception is thrown.
|
||
</para>
|
||
|
||
<para>
|
||
If the BSON object has a <property>__pclass</property> property and
|
||
that class exists and implements
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename> it will
|
||
supersede the class provided in the type map.
|
||
</para>
|
||
|
||
<para>
|
||
The properties of the BSON document, <emphasis>including</emphasis>
|
||
the <property>__pclass</property> property if it exists, will be sent
|
||
as an associative array to the
|
||
<methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>
|
||
function to initialise the object's properties.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
|
||
<section xml:id="mongodb.persistence.typemaps">
|
||
<title>TypeMaps</title>
|
||
|
||
<para>
|
||
TypeMaps can be set through the
|
||
<methodname>MongoDB\Driver\Cursor::setTypeMap</methodname> method on a
|
||
<classname>MongoDB\Driver\Cursor</classname> object, or the
|
||
<literal>$typeMap</literal> argument of
|
||
<function>MongoDB\BSON\toPHP</function>. Each of the three
|
||
classes (<emphasis>root</emphasis>, <emphasis>document</emphasis>, and
|
||
<emphasis>array</emphasis>) can be individually set, in addition to the
|
||
field specific types.
|
||
</para>
|
||
|
||
<para>
|
||
If the value in the map is <type>NULL</type>, it means the same as the
|
||
<emphasis>default</emphasis> value for that item.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Examples</title>
|
||
|
||
<para>
|
||
These examples use the following classes:
|
||
</para>
|
||
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>MyClass</term>
|
||
<listitem>
|
||
<para>
|
||
which does <emphasis>not</emphasis> implement any interface
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>YourClass</term>
|
||
<listitem>
|
||
<para>
|
||
which implements
|
||
<interfacename>MongoDB\BSON\Unserializable</interfacename>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>OurClass</term>
|
||
<listitem>
|
||
<para>
|
||
which implements
|
||
<interfacename>MongoDB\BSON\Persistable</interfacename>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>TheirClass</term>
|
||
<listitem>
|
||
<para>
|
||
which extends OurClass
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
|
||
<para>
|
||
The <methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>
|
||
method of YourClass, OurClass, TheirClass iterate over the array and set
|
||
the properties without modifications. It <emphasis>also</emphasis> sets
|
||
the <literal>$unserialized</literal> property to <literal>true</literal>:
|
||
|
||
<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: [] (all defaults) */
|
||
{ "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>
|
||
|
||
</article>
|
||
</book>
|
||
|
||
<!-- 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
|
||
-->
|