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

1

5

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

Somatoplasm answered 26/4, 2012 at 18:35 Comment(0)
C
7

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();
        }
    }
}
Crispas answered 26/4, 2012 at 22:56 Comment(2)
No problem. I've gone through the same pain as you when starting out with Doctrine. It's awesome once you get the hang of it though!Crispas
I think its really good so far. It makes building a service layer over the top much easier. One small point is I the Roles::hasUsers() should return !$this->users->isEmpty(); to invert the boolean. Thanks very much for your help and this works like a dream.Somatoplasm

© 2022 - 2024 — McMap. All rights reserved.