Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine ODM MongoDB - Replicate a simple One to Many Reference with Constraint

I'm new to Doctrine, mongo and the ODM setup and while playing with this setup in ZF1 I'm trying to replicate a simple one to many reference with a constraint. Here is the situation and would like some advise on how to achieve this.

This is a simple user->role mapping, so in a sql situation I would have tables as follows:

Users
 - id
 - name
 - role_id

Roles
 - id
 - name

Then a foreign key constraint would be set on the users role_id to map to the role id. And upon deleting a role a foreign key constraint would be triggered stopping the operation.

How could I achieve the same goal in Doctrines MongoDB ODM?

So far I have played with different types of annotations on the User entity including @ReferenceOne @ReferenceMany with different cascade options...

The choice left to me now is to implement @PreUpdate, @PreRemove lifecycle events on the 'role' entity and then check that no users are using the role, if they are then on update change the reference to match or on remove throw an exception.

Am I right here or lost ?

Thank you,

Si

like image 688
Si Griffiths Avatar asked Apr 26 '12 18:04

Si Griffiths


1 Answers

For something like that I wouldn't have two separate 'tables' like you would in SQL. You would just have the role type as a property of the user. And then if you wanted to remove a role type you can just manipulate the role field of all users with that role.

But to answer your question, I would do it's like so.

<?php
class User {
    /** @MongoDB\Id */
    protected $id;
    /** @MongoDB\String */
    protected $name;
    /** @MongoDB\ReferenceOne(targetDocument="Role", mappedBy="user") */
    protected $role;

    //Getters/Setters
}

class Role {
    /** @MongoDB\Id */
    protected $id;
    /** @MongoDB\String */
    protected $name;
    /** @MongoDB\ReferenceMany(targetDocument="User", inversedBy="role") */
    protected $users;

    public function _construct() {
        $this->users = new Doctrine\Common\Collections\ArrayCollection;
    }
    // Getters/Setters

    public function hasUsers() {
        return !$this->users->isEmpty();
    }
}

Then I would create a service class for working with my document manager.

class RoleService {
    public function deleteRole(Role $role) {
        if (!$role->hasUsers()) {
            // Setup the documentManager either in a base class or the init method. Or if your über fancy and have php 5.4, a trait.
            $this->documentManager->remove($role);
            // I wouldn't always do this in the service classes as you can't chain
            // calls without a performance hit.
            $this->documentManager->flush();
        }
    }
}
like image 107
Jamie Sutherland Avatar answered Nov 05 '22 17:11

Jamie Sutherland