Skip to content

Instantly share code, notes, and snippets.

@jmikola

jmikola/out.txt Secret

Created August 14, 2017 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmikola/403554ac91927705ec179938d1262ad8 to your computer and use it in GitHub Desktop.
Save jmikola/403554ac91927705ec179938d1262ad8 to your computer and use it in GitHub Desktop.
UTCDateTime with timezone
object(stdClass)#1 (1) {
["date"]=>
object(LocalDateTime)#2 (2) {
["utc":"LocalDateTime":private]=>
object(MongoDB\BSON\UTCDateTime)#3 (1) {
["milliseconds"]=>
string(13) "1502739349546"
}
["tz":"LocalDateTime":private]=>
object(DateTimeZone)#4 (2) {
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "America/New_York"
}
}
}
object(DateTime)#5 (3) {
["date"]=>
string(26) "2017-08-14 15:35:49.546000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "America/New_York"
}
<?php
/* Custom document class that stores a UTCDateTime and timezone 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;
}
public function bsonSerialize()
{
return [
'utc' => $this->utc,
'tz' => $this->tz->getName(),
];
}
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']);
}
public function toDateTime()
{
return $this->utc->toDateTime()->setTimezone($this->tz);
}
public function __toString()
{
return (string) $this->utc;
}
}
$bson = MongoDB\BSON\fromPHP(['date' => new LocalDateTime]);
$document = MongoDB\BSON\toPHP($bson);
var_dump($document);
var_dump($document->date->toDateTime());
@jmikola
Copy link
Author

jmikola commented Aug 15, 2017

@alcaeus: I talked this over with @derickr and I think we're going to pull the TypeWrapper interface out of 1.3.0, but leave the various BSON type interfaces (e.g. BinaryInterface). As noted in my example above, they can be useful for abstraction purposes.

It occurred to me that both type wrapping (PHPC-640) and the field path syntax (PHPC-314) may be better handled by letting users provide a callable that receives the original BSON value and the field path as a string. That approach let's us reduce much of the complexity in the BSON-to-PHP decoding within bson.c and it allows users the most flexibility. For instance, PHPLIB could have its own callable that applies any logic we might want and then invokes another callable from the library user (akin to stacking autoloaders). Benchmarking would help us determine if this is feasible, but I think it may be comparable to how we're currently calling createFromBSONType() frequently (granted, the callable could be invoked many more times for large documents).

In concert with removing createFromBSONType() entirely, I'm also going to look at doing away with the TypeWrapper interface. @derickr and I don't recall the exact reasons that we originally decided not to use MongoDB\BSON\Serializable for this purpose, but I'd like to explore relaxing its restriction on the bsonSerialize() return type. Docs currently state that it must return an array or object, which limits it to producing BSON arrays and documents. If we instead let it return any PHP value (including a BSON type object or PHP primitive), it may be able to take the place of MongoDB\BSON\TypeWrapper::toBSONType(). Of course, we'd have a sanity check to ensure that any bsonSerialize() return value destined to become a root document is actually an array or object.

For MongoDB\BSON\Unserializable, I expect bsonUnserialize() stays the same, which is to say it's only used to convert BSON arrays and documents into new PHP objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment