Skip to content

How can I hydrate a document class used with setTypeMap ? #612

@AsyncWizard

Description

@AsyncWizard

Hi,

I'm working on a lightweight "Entity" system that simplifies access to data between, for example, two collections.
In the code below, I would like my User class to allow me to retrieve informations from the user's group.

First, data in DB:

// One document in "group" collection:
{
  _id: 1234,
  name: 'My group'
}

// One document in "user" collection:
{
  _id: 1230,
  firstName: 'Joe',
  lastName: 'Robert',
  group: 1234
}

Now, PHP (pseudo)code:

use MongoDB\Model\BSONDocument;

class User extends BSONDocument
{
    /**
     * @return Database
     */
    protected function getDB(){
        /**
         * NEED TO IMPLEMENT THIS
         */
    }

    public function getGroup(){
        $groupId = $this[ 'group' ];
        return $this
            ->getDB()
            ->selectCollection('group')
            ->findOne([
                '_id' => $groupId
            ])
        ;
    }
}

// Usage example:
$usersCursor = $collection->find();

$usersCursor->setTypeMap([
    'root' => User::class,
    'document' => 'array',
    'array' => 'array',
]);

foreach($usersCursor as $user){
    $groupInformations = $user->getGroup();
    $username = $user['firstName'];
    
    // ...
}

In this example I need the Database, but in reality it relates to any data that can be used in the document.

For now, I investigated 2 methods:

1 - Static references

Something like:

class User extends BSONDocument
{
    private static $db;

    public static function setDB(Database $db){
        self::$db = $db;
    }

    /**
     * @return Database
     */
    protected function getDB(){
        return self::$db;
    }

    //...
}

I find that this implementation is not clean.
And above all, in this example, if I request users on two different databases, I will have conflicts, it seems chaotic.

2 - Extends / wrap EVERYTHING

Extending MongoDB\Collection, override all methods that return BSONDocument, intercept the return of a document to hydrate it.
When a method (for example ::find) returns a \MongoDB\Driver\Cursor, it will have to be wrapped in a custom cursor, because:

final class Cursor implements \Traversable

This could be a problem if a third-party library requires a \MongoDB\Driver\Cursor and nothing else.

Discussion

Why ::setTypeMap could not use a callback or a factory class that implements BSONDocumentFactory for example ?
The returned result would be just completed with a call to bsonUnserialize.

Maybe I forgot something?
In my example I need a Database, but, again, this might be needed with any kind of data.

For now I'm thinking about the implementation of the second solution, it's a big deal!
Otherwise, if someone has another solution or a library that provides that, I would be grateful.

Thank you for reading so far! :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions