1

I spent 2 days on this and still I can't find solution why It's not working. I used this tutorial to implement Doctrine in Zend Framework 3. On this site is implementation of ManyToMany relationship in entities. I used it 1:1 in my project (User-Role) but it not working. Every time when I want to get all roles for user ($user->getRoles()) i'm getting NULL

User entity

<?php

namespace User\Entity;

use Doctrine\ORM\Mapping as ORM;
use Development\Entity\AbstractEntity;
use Development\Entity\Traits\EntityId;
use Development\Exception\EntityException;
use Doctrine\Common\Collections\ArrayCollection;
use Utils\StringUtils;

/**
 * @ORM\Entity(repositoryClass="User\Repository\UserRepository")
 * @ORM\Table(name="user")
 */
class User extends AbstractEntity
{
use EntityId;

/**
 * @ORM\Column(name="name")
 */
protected $name;

/**
 * @ORM\Column(name="surname")
 */
protected $surname;

/**
 * @ORM\Column(name="position")
 */
protected $position;

/**
 * @ORM\Column(name="phone")
 */
protected $phone;

/**
 * @ORM\Column(name="login")
 */
protected $login;

/**
 * @ORM\Column(name="password")
 */
protected $password;

/**
 * @ORM\ManyToMany(targetEntity="User\Entity\Role")
 * @ORM\JoinTable(name="user_role",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
 *      )
 */
private $roles;

public function __construct()
{
    $this->roles = new ArrayCollection();
}

public function __toString()
{
    return $this->getFullName();
}

public function addRole($role)
{
    $this->roles[] = $role;
}

public function getRoles()
{
    return $this->roles;
}

public function removeRole($role)
{
    $this->roles->removeElement($role);
}

/**
 * @param integer $mbCase
 *
 * @return string
 *
 */
public function getFullName($mbCase = MB_CASE_TITLE)
{
    if (!StringUtils::isEmpty($this->surname)) {
        $fullName = mb_convert_case($this->name . ' ' . $this->surname, $mbCase, "UTF-8");
    } else {
        $fullName = mb_convert_case($this->name, $mbCase, "UTF-8");
    }

    return trim($fullName);
}

/**
 * @return string
 *
 */
public function getLogin()
{
    return $this->login;
}

/**
 * @return string
 *
 */
public function getPassword()
{
    return $this->password;
}

/**
 * @param mixed $login
 */
public function setLogin($login)
{
    $this->login = StringUtils::toLower($login);
}
}

Role entity

<?php

namespace User\Entity;

use Development\Entity\AbstractEntity;
use Development\Entity\Traits\EntityId;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * This class represents a role.
 * @ORM\Entity()
 * @ORM\Table(name="role")
 */
class Role extends AbstractEntity
{
use EntityId;

/**
 * @ORM\Column(name="name")
 */
protected $name;

/**
 * @ORM\Column(name="description")
 */
protected $description;

/**
 * @ORM\Column(name="date_created")
 */
protected $dateCreated;

/**
 * @var Role[]
 *
 * @ORM\ManyToMany(targetEntity="User\Entity\Role")
 * @ORM\JoinTable(name="role_hierarchy",
 *      joinColumns={@ORM\JoinColumn(name="child_role_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="parent_role_id", referencedColumnName="id")}
 *      )
 */
private $parentRoles;

/**
 * @var Role[]
 *
 * @ORM\ManyToMany(targetEntity="User\Entity\Role")
 * @ORM\JoinTable(name="role_hierarchy",
 *      joinColumns={@ORM\JoinColumn(name="parent_role_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="child_role_id", referencedColumnName="id")}
 *      )
 */
protected $childRoles;

/**
 * @var Permission[]
 *
 * @ORM\ManyToMany(targetEntity="User\Entity\Permission")
 * @ORM\JoinTable(name="role_permission",
 *      joinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="permission_id", referencedColumnName="id")}
 *      )
 */
private $permissions;

/**
 * Constructor.
 */
public function __construct()
{
    $this->parentRoles = new ArrayCollection();
    $this->childRoles = new ArrayCollection();
    $this->permissions = new ArrayCollection();
}

public function getName()
{
    return $this->name;
}

public function setName($name)
{
    $this->name = $name;
}

public function getDescription()
{
    return $this->description;
}

public function setDescription($description)
{
    $this->description = $description;
}

public function getDateCreated()
{
    return $this->dateCreated;
}

public function setDateCreated($dateCreated)
{
    $this->dateCreated = $dateCreated;
}

public function getParentRoles()
{
    return $this->parentRoles;
}

public function getChildRoles()
{
    return $this->childRoles;
}

public function getPermissions()
{
    return $this->permissions;
}
}

I'm using latest Doctrine ORM Module and Zend3. Do you know where I should search for solution? I will add code in next 8 hours if it will be needed. What is important in this kind of relationship for doctrine? Other relations works fine.

Matthew
  • 63
  • 10

3 Answers3

0

Are you sure that roles are being saved against the user in the database? I would check that first.

This might help: Symfony2-Doctrine: ManyToMany relation is not saved to database

NJ247
  • 1
0

I tried your example and it worked for me. Couple things you have to consider. In Doctrine, associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time it's accessed. So in order for your roles to get populated, you have to do something like this:

    foreach ($user->getRoles() as $role) {
        echo $role->getName();
    }

Alternatively you can use fetch="EAGER" in you association annotation:

/**
 * @ORM\ManyToMany(targetEntity="User\Entity\Role", fetch="EAGER")
 * @ORM\JoinTable(name="user_role",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
 *      )
 */
private $roles;

Check out this question to see the difference between fetch="EAGER" and fetch="LAZY"

zstate
  • 1,995
  • 1
  • 18
  • 20
  • Hey! Thank you for the response! I checked it twice again and other configuration (doctrine config, class factories, etc.) and I found some errors, wchich can make this situation for me. Now it works perfectly! Maybe I was tired yesterday, when I doing this... PS. Could you look [here](https://stackoverflow.com/questions/49458695/using-doctrine-onetoone-relation-with-condition-in-zf3) in free time? :) – Matthew Mar 23 '18 at 21:51
0

Are you sure the Role entity is correct: When I use:

./vendor/bin/doctrine-module orm:validate-schema

I get following error

Mapping
-------
[OK] The mapping files are correct.                                                                                    

Database
--------
In SchemaException.php line 112:
The table with name 'bmv5.role_hierarchy' already exists.

Same when I try to orm:schema-tool:update --force

cwhisperer
  • 1,478
  • 1
  • 32
  • 63