Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/ /

Tipos de datos personalizados

Nota

Este tutorial explica cómo implementar tipos de datos personalizados mediante la MongoDB\BSON\Persistable interfaz encontrada en la extensión de MongoDB. Considera utilizar un códec en su lugar para desacoplar la lógica de persistencia de MongoDB de la lógica de negocio. Ver el Tutorial del códec para un ejemplo.

La extensión y librería de MongoDB PHP admiten clases personalizadas durante la serialización y deserialización. Un ejemplo de dónde esto puede ser útil es si deseas almacenar información de fecha y hora manteniendo la información sobre la zona horaria que almacena la clase DateTimeImmutable de PHP junto con un punto en el tiempo.

La extensión serializa variables PHP, incluidos objetos, en BSON cuando se comunica con el servidor, y deserializa BSON de nuevo a variables PHP cuando recibe datos del servidor.

Es posible influir en el comportamiento mediante la implementación de la interfaz de MongoDB\BSON\Persistable. Si una clase implementa esta interfaz, al momento de la serialización se llama al método bsonSerialize. Este método es responsable de devolver un arreglo o un objeto stdClass para convertirlo a BSON y almacenarlo en la base de datos. Estos datos se utilizarán posteriormente para reconstruir el objeto al leer desde la base de datos.

Como ejemplo, presentamos el LocalDateTime clase. Esta clase encapsula el MongoDB\BSON\UTCDateTime tipo de datos y una zona horaria.

<?php
/* Custom document class that stores a UTCDateTime and time zone and also
* implements the UTCDateTime interface for portability. */
class LocalDateTime implements \MongoDB\BSON\Persistable, \MongoDB\BSON\UTCDateTimeInterface
{
private $utc;
private $tz;
public function __construct($milliseconds = null, \DateTimeZone $timezone = null)
{
$this->utc = new \MongoDB\BSON\UTCDateTime($milliseconds);
if ($timezone === null) {
$timezone = new \DateTimeZone(date_default_timezone_get());
}
$this->tz = $timezone;
}
?>

Como implementa la interfaz MongoDB\BSON\Persistable, la clase debe implementar los métodos bsonSerialize y bsonUnserialize. En el método bsonSerialize, devolvemos un arreglo con los dos valores que necesitamos mantener: el punto en el tiempo en milisegundos desde la Unix Epoch, representado por un objeto MongoDB\BSON\UTCDateTime, y un string que contiene el identificador de zona horaria Olson:

<?php
public function bsonSerialize()
{
return [
'utc' => $this->utc,
'tz' => $this->tz->getName(),
];
}
?>

La extensión añadirá además un campo __pclass al documento y lo almacenará también en la base de datos. Este campo contiene el nombre de la clase PHP para que al deserializar la extensión sepa qué clase usar para recrear el objeto almacenado.

Cuando se lee el documento de la base de datos, la extensión detecta si existe un campo __pclass y luego ejecuta el método MongoDB\BSON\Persistable::bsonUnserialize que es responsable de restaurar el estado original del objeto.

En el código siguiente, nos aseguramos de que los datos en los campos utc y tz tienen el tipo de tiempo adecuado, y luego asignamos sus valores a las dos propiedades privadas.

<?php
public function bsonUnserialize(array $data)
{
if ( ! isset($data['utc']) || ! $data['utc'] instanceof \MongoDB\BSON\UTCDateTime) {
throw new Exception('Expected "utc" field to be a UTCDateTime');
}
if ( ! isset($data['tz']) || ! is_string($data['tz'])) {
throw new Exception('Expected "tz" field to be a string');
}
$this->utc = $data['utc'];
$this->tz = new \DateTimeZone($data['tz']);
}
?>

Puede que hayas notado que la clase también implementa la interfaz MongoDB\BSON\UTCDateTimeInterface. Esta interfaz define los dos métodos no constructores de la clase MongoDB\BSON\UTCDateTime.

Se recomienda que los contenedores de las clases BSON existentes implementen la interfaz correspondiente (es decir, MongoDB\BSON\UTCDateTimeInterface) para que los objetos contenedor puedan usarse en el mismo contexto que sus versiones originales sin envolver. También se recomienda que siempre se utilicen sugerencias de tipo para la interfaz (es decir, MongoDB\BSON\UTCDateTimeInterface) y nunca para la clase concreta (es decir, MongoDB\BSON\UTCDateTime), ya que esto impediría que los objetos envueltos sean aceptados en los métodos.

En nuestro nuevo método toDateTime, devolvemos un objeto DateTime con la zona horaria local establecida, en lugar del UTC que normalmente utiliza MongoDB\BSON\UTCDateTime en su valor de retorno.

<?php
public function toDateTime()
{
return $this->utc->toDateTime()->setTimezone($this->tz);
}
public function __toString()
{
return (string) $this->utc;
}
}
?>

Con la clase definida, ahora podemos usarla en nuestros documentos. El siguiente fragmento muestra el ida y vuelta desde el objeto LocalDateTime a BSON, y de regreso a LocalDateTime.

<?php
$bson = MongoDB\BSON\Document::fromPHP(['date' => new LocalDateTime]);
$document = $bson->toPHP();
var_dump($document);
var_dump($document->date->toDateTime());
?>

Que produce:

object(stdClass)#1 (1) {
["date"]=>
object(LocalDateTime)#2 (2) {
["utc":"LocalDateTime":private]=>
object(MongoDB\BSON\UTCDateTime)#3 (1) {
["milliseconds"]=>
string(13) "1533042443716"
}
["tz":"LocalDateTime":private]=>
object(DateTimeZone)#4 (2) {
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}
}
}
object(DateTime)#5 (3) {
["date"]=>
string(26) "2018-07-31 14:07:23.716000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}

Almacenar el identificador de zona horaria de Olson en un campo separado también funciona bien con el Marco de Agregación de MongoDB, que permite la manipulación de fechas, formateo y consultas dependiendo de una zona horaria específica.

Volver

Agregación