Overriding discriminator mapping on join table - doctrine-orm

The project works with multiple user logins (plumber, builder), the relevant information for each entity is saved in their respective tables. The structure for them is supplied below.
We've been storing the information for suppliers and have now gathered a few hundred entries. Suppliers are now requiring a login to access the system.
The current flow with the discriminator map is it creates an entry in the Users table and then saves in the respective user type table with the id being that of the user.id.
User.id = 5 => plumber.id = 5
User.id = 6 => builder.id = 6
User.id = 7 => plumber.id = 7
Suppliers have had their own table with their own incrementing ids which would cause clashes with the DiscriminatorMap(). Is there a way to have suppliers be unique and connect on a supplier.user_id instead of supplier.id, like the other tables?
<?php
namespace Project\Entities;
abstract class BaseEntity
{
public static $idCol = 'id';
public static $joins = [];
public static $orderBy = [];
}
?>
<?php
namespace Project\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping AS ORM;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
/**
* #ORM\Entity(repositoryClass="Project\Repositories\User\UserRepository")
* #ORM\Table(name="user")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"user"="User", "plumber"="Plumber", "builder"="Builder"})
* #ORM\HasLifecycleCallbacks()
*/
class User extends BaseEntity implements Authenticatable
{
use \LaravelDoctrine\ORM\Auth\Authenticatable;
use \Project\Entities\Traits\HasContactDetails;
const TYPE_USER = "user";
const TYPE_PLUMBER = "plumber";
const TYPE_BUILDER = "builder";
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #var int
*/
protected $id;
/**
* #ORM\Column(type="string", unique=true, nullable=false)
* #var string
*/
protected $login;
/**
* #ORM\Column(type="text")
* #var string
*/
protected $password;
/**
* #return int
*/
public function getId() {
return $this->id;
}
/**
* #return string
*/
public function getLogin() {
return $this->login;
}
/**
* #param string $login
*/
public function setLogin($login) {
$this->login = $login;
}
public function getAuthPassword() {
return $this->password;
}
/**
* Encrypt password when inserting
* #ORM\PrePersist
*/
public function onPrePersist() {
$this->encryptPassword();
}
/**
* Encrypt password when updating
* #ORM\PreUpdate
*/
public function onPreUpdate(\Doctrine\ORM\Event\PreUpdateEventArgs $event) {
if ($event->hasChangedField('password')) {
$this->encryptPassword();
}
}
/**
*
* #return string
*/
public function getType() {
if ($this instanceof \Project\Entities\Plumber) {
return self::TYPE_PLUMBER;
}
if ($this instanceof \Project\Entities\Builder) {
return self::TYPE_BUILDER;
}
return self::TYPE_USER;
}
public function getAuthIdentifierName() {
return "login";
}
.....
}
?>
User roles extending
<?php
namespace Project\Entities;
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity(repositoryClass="Project\Repositories\Plumber\PlumberRepository")
* #ORM\Table(name="plumber")
*/
class Plumber extends User
{
.....
}
?>
<?php
namespace Project\Entities;
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity(repositoryClass="Project\Repositories\Builder\BuilderRepository")
* #ORM\Table(name="builder")
*/
class Builder extends User
{
.....
}
?>
The current supplier entity.
<?php
namespace Project\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity(repositoryClass="Project\Repositories\Supplier\SupplierRepository")
* #ORM\Table(name="supplier")
*/
class Supplier extends BaseEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #var int
*/
protected $id;
/**
* #ORM\Column(type="string")
* #var string
*/
protected $name;
/**
* #ORM\ManyToOne(targetEntity="Region")
* #var Region
*/
protected $region;
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
public function getRegion() {
return $this->region;
}
public function setId($id) {
$this->id = $id;
}
public function setName($name) {
$this->name = $name;
}
/**
* #param Region $region
*/
public function setRegion($region) {
$this->region = $region;
}
.....
}
?>

Related

ManyToMany does not work with inheritance

I'm building an app that deals with givers and companies, that own givers. Both inherit a super-class called "Organization".
I want to add an unidirectional ManyToMany relationship between them, but when I ask doctrine to implement the database, and hydrate it with fixtures, I can't retrieve the givers owned by a company.
Doctrine hasn't even created a giver_company table whatsoever which could contain the relationship information as it is supposed to do.
Here is my code:
Organization
<?php
// src/Entity/Chain/Organization.php
namespace App\Entity\Chain;
use App\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"association" = "Association", "super_association" = "SuperAssociation", "company" = "Company", "giver" = "Giver"})
*/
abstract class Organization
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank()
*/
private $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $address;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $city;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $zipcode;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $SIREN;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $phone;
/**
* #ORM\OneToOne(targetEntity="App\Entity\Photo")
*/
private $photo;
/**
* #ORM\OneToMany(targetEntity="App\Entity\User", mappedBy="memberOf")
*/
private $members ;
/**
* Organization constructor.
*/
public function __construct()
{
$this->members = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name): void
{
$this->name = $name;
}
public function getAddress()
{
return $this->address;
}
/**
* #param mixed $address
*/
public function setAddress($address): void
{
$this->address = $address;
}
public function getCity()
{
return $this->city;
}
/**
* #param mixed $city
*/
public function setCity($city): void
{
$this->city = $city;
}
public function getZipcode()
{
return $this->zipcode;
}
/**
* #param mixed $zipcode
*/
public function setZipcode($zipcode): void
{
$this->zipcode = $zipcode;
}
public function getSIREN()
{
return $this->SIREN;
}
/**
* #param mixed $SIREN
*/
public function setSIREN($SIREN): void
{
$this->SIREN = $SIREN;
}
public function getPhone()
{
return $this->phone;
}
/**
* #param mixed $phone
*/
public function setPhone($phone): void
{
$this->phone = $phone;
}
public function getPhoto()
{
return $this->photo;
}
/**
* #param mixed $photo
*/
public function setPhoto($photo): void
{
$this->photo = $photo;
}
public function getMembers()
{
return $this->members;
}
public function addMember(User $member)
{
if (!$this->members->contains($member)) {
$this->members->add($member);
}
}
public function removeMember(User $member){
$this->members->remove($member);
}
}
Giver
<?php
// src/Entity/Chain/Giver.php
namespace App\Entity\Chain;
use App\Entity\Photo;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class Giver extends Organization
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $status ;
/**
* Giver constructor.
*/
public function __construct()
{
parent::__construct();
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getStatus()
{
return $this->status;
}
/**
* #param mixed $status
*/
public function setStatus($status): void
{
$this->status = $status;
}
}
Company
<?php
// src/Entity/Chain/Company.php
namespace App\Entity\Chain;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class Company extends Organization
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, name="company_type")
*/
private $type ;
/*
* #ORM\ManyToMany(targetEntity="App\Entity\Chain\Giver")
*/
private $givers ;
/**
* Company constructor.
*/
public function __construct()
{
parent::__construct();
$this->givers = new ArrayCollection();
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getType()
{
return $this->type;
}
/**
* #param mixed $type
*/
public function setType($type): void
{
$this->type = $type;
}
public function getGivers()
{
return $this->givers;
}
public function addGiver(Giver $opening)
{
if (!$this->givers->contains($opening)) {
$this->givers->add($opening);
}
}
public function removeGiver(Giver $opening){
$this->givers->remove($opening);
}
}
Your DocBlock for givers in Company is missing an "*" at the beginning. PHPDoc
Change:
/*
* #ORM\ManyToMany(targetEntity="App\Entity\Chain\Giver")
*/
private $givers ;
to
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Chain\Giver")
*/
private $givers ;

Constraints like #Assert\NotBlank() annotation for entities does not work in unit test which gives semantical or auto loaded error

When I run the Unit test it gives the following error for the constraints
[Semantical Error] The annotation "#Symfony\Component\Validator\Constraints\NotBlank" in property AppBundle\Entity\User::$username does not exist, or could not be auto-loaded.
Here is my entity
User.class
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
/**
* Class User
* #package AppBundle\Entity
*
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #ORM\Table(name="user")
* #ORM\HasLifecycleCallbacks()
*
*/
class User implements AdvancedUserInterface, \Serializable
{
/** #var double
* #ORM\Column(type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=60, unique=true)
* #Assert\NotBlank()
* #Assert\Email()
*/
private $username;
/**
* #ORM\Column(type="string", length=64)
*/
private $password;
/**
* #Assert\NotBlank()
* #Assert\Length(max=4096)
*/
private $plainPassword;
/**
* #var string
* #ORM\Column(name="fullname", type="string", length=100, nullable=false)
* #Assert\NotBlank()
*/
protected $fullname;
/**
* #var \DateTime
* #ORM\Column(name="createdat", type="datetime", nullable=true)
*/
protected $createdat;
/**
* #var \DateTime
* #ORM\Column(name="modifiedat", type="datetime", nullable=true)
*/
protected $modifiedat;
/**
* #ORM\Column(type="boolean", options={"default" = 1}, nullable=false)
*/
private $isactive = true;
public function __construct()
{
$this->updatedTimestamps();
}
/**
* Now we tell doctrine that before we persist or update we call the updatedTimestamps() function.
*
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updatedTimestamps()
{
$this->setModifiedat(new \DateTime(date('Y-m-d H:i:s')));
if($this->getCreatedat() == null)
{
$this->setCreatedat(new \DateTime(date('Y-m-d H:i:s')));
}
}
public function getUsername()
{
return $this->username;
}
public function getSalt()
{
// you *may* need a real salt depending on your encoder
// see section on salt below
return '';
}
public function getPassword()
{
return $this->password;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function eraseCredentials()
{
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return $this->isactive;
}
/** #see \Serializable::serialize() */
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
$this->isactive
));
}
/** #see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
$this->isactive
) = unserialize($serialized);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
*
* #return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set password
*
* #param string $password
*
* #return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Set isactive
*
* #param boolean $isactive
*
* #return User
*/
public function setIsactive($isactive)
{
$this->isactive = $isactive;
return $this;
}
/**
* Get isactive
*
* #return boolean
*/
public function getIsactive()
{
return $this->isactive;
}
/**
* #return mixed
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* #param mixed $plainPassword
*/
public function setPlainPassword($plainPassword)
{
$this->plainPassword = $plainPassword;
}
/**
* Set fullname
*
* #param string $fullname
*
* #return User
*/
public function setFullname($fullname)
{
$this->fullname = $fullname;
return $this;
}
/**
* Get fullname
*
* #return string
*/
public function getFullname()
{
return $this->fullname;
}
/**
* Set createdat
*
* #param \DateTime $createdat
*
* #return User
*/
public function setCreatedat($createdat)
{
$this->createdat = $createdat;
return $this;
}
/**
* Get createdat
*
* #return \DateTime
*/
public function getCreatedat()
{
return $this->createdat;
}
/**
* Set modifiedat
*
* #param \DateTime $modifiedat
*
* #return User
*/
public function setModifiedat($modifiedat)
{
$this->modifiedat = $modifiedat;
return $this;
}
/**
* Get modifiedat
*
* #return \DateTime
*/
public function getModifiedat()
{
return $this->modifiedat;
}
/**
* The __toString method allows a class to decide how it will react when it is converted to a string.
*
* #return string
* #link http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring
*/
function __toString()
{
return "id: ". $this->id ." email: ". $this->username . " fullname: ". $this->fullname . " isactive: ". $this->isactive .
" createdat: ". $this->createdat->format('Y-m-d H:i:s') ." updatedat: ". $this->modifiedat->format('Y-m-d H:i:s');
}
}
This is my Unit Test classes:
TestBase.class
namespace tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\DependencyInjection\Container;
use Doctrine\Common\Annotations\AnnotationRegistry;
use AppKernel;
AnnotationRegistry::registerFile("../../../vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
require_once __DIR__ . "/../../../vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php";
class TestBase extends \PHPUnit_Framework_TestCase
{
/**
* #var Application
*/
protected $application;
/**
* #var \Doctrine\ORM\EntityManager
*/
protected $entityManager;
/**
* #var \AppKernel
*/
protected $kernel;
/**
* #var Container
*/
protected $container;
protected function setUp()
{
$this->kernel = new AppKernel("test", true);
$this->kernel->boot();
$this->application = new Application($this->kernel);
$this->application->setAutoExit(false);
// Store the container and the entity manager in test case properties
$this->container = $this->kernel->getContainer();
$this->entityManager = $this->container->get("doctrine")->getManager();
if(is_null($this->entityManager)){
print("upssss entitiy manager is null :(");
}
parent::setUp();
}
public function tearDown()
{
// Shutdown the kernel.
$this->kernel->shutdown();
parent::tearDown();
}
}
And here I test my User class just printing the database..
UserTest.class
namespace tests\AppBundle\Controller;
require_once ("TestBase.php");
class UserTest extends TestBase
{
protected function setUp()
{
parent::setUp();
}
public function tearDown()
{
parent::tearDown();
}
//generic method to list the users
public function listUsers($users ){
echo EOL, EOL;
foreach($users as $user){
echo $user, EOL;
}
echo EOL, EOL;
}
public function testListUsers(){
$users = $this->entityManager->getRepository('AppBundle:User')->findAll();
$this->assertGreaterThan(1, count($users));
$this->listUsers($users);
}
}
By the way it works when I don't use #Assert\NotBlank()
So from code-wise there is no problem at all... I guess it is just about autoloading when unit testing..
I really got stuck for 2 weeks with that..
Ok I found the answer..
When I changed test to dev in AppKernel it worked
old one was this:
$this->kernel = new AppKernel("test", true);
solution
$this->kernel = new AppKernel("dev", true);
I didn't change my AppKernel.php though
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
define('EOL',(PHP_SAPI == 'cli') ? PHP_EOL : '<br />');
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
new Liuggio\ExcelBundle\LiuggioExcelBundle(),
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new AppBundle\AppBundle(),
];
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
}
return $bundles;
}
public function getRootDir()
{
return __DIR__;
}
public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
}
public function getLogDir()
{
return dirname(__DIR__).'/var/logs';
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
}
}

Doctrine: one to many relationship and cascade persistance

I mean I have these two classes (one to many relationship). As you can appreciate in both I have included cascade={"persist"}.
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="task")
*/
class Task
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, name="description", nullable=true)
*/
protected $description;
/**
* #ORM\OneToMany(targetEntity="Tag", mappedBy="task", cascade={"persist"})
**/
protected $tags;
/*************************************/
public function __toString()
{
return $this->description;
}
/**
* Constructor
*/
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set description
*
* #param string $description
* #return Task
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Add tags
*
* #param \Project\FrontendBundle\Entity\Tag $tags
* #return Task
*/
public function addTag(\Project\FrontendBundle\Entity\Tag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \Project\FrontendBundle\Entity\Tag $tags
*/
public function removeTag(\Project\FrontendBundle\Entity\Tag $tags)
{
$this->tags->removeElement($tags);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="tag")
*/
class Tag
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, name="name", nullable=true)
*/
protected $name;
/**
* #ORM\ManyToOne(targetEntity="Task", inversedBy="tags", cascade={"persist"})
* #ORM\JoinColumn(name="task_id", referencedColumnName="id")
**/
private $task;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set task
*
* #param \Project\FrontendBundle\Entity\Task $task
* #return Tag
*/
public function setTask(\Project\FrontendBundle\Entity\Task $task = null)
{
$this->task = $task;
return $this;
}
/**
* Get task
*
* #return \Project\FrontendBundle\Entity\Task
*/
public function getTask()
{
return $this->task;
}
}
In my controller I have this:
$task = new Task();
$tag = new Tag();
$task->addTag($tag);
$em = $this->getDoctrine()->getManager();
$em->persist($item);
$em->flush();
but the foreign key is always NULL, why?
I think in the Task class, the addTag and removeTag should look like this:
public function addTag($tag)
{
$tag->setTask($this);
$this->tags->add($tag);
}
public function removeTag($tag)
{
$tag->setTask(null);
$this->tags->removeElement($tag);
}
Or if you want to add and remove many tags in one function call use these:
public function addTags(Collection $tags)
{
foreach ($tags as $tag) {
$tag->setTask($this);
$this->tags->add($tag);
}
}
public function removeTags(Collection $tags)
{
foreach ($tags as $tag) {
$tag->setTask(null);
$this->tags->removeElement($tag);
}
}

Doctrine 2 one-to-many relationship

I have the following:
User have one group, group can have many users
User
<?php namespace Application\Model;
use Doctrine\Common\Collections;
use Doctrine\ORM\Mapping as ORM;
/**
* User model
* Read-only entity
* #ORM\Table(name="VLOGGER_WEBCALENDAR_USR")
* #ORM\Entity
* #package Application\Model
*/
class User
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="USR_ID", type="integer")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="USR_LOGIN", type="string")
*/
protected $login;
/**
* #var string
* #ORM\Column(name="USR_CODE", type="string")
*/
protected $code;
/**
* #var int
* #ORM\Column(name="GRP_ID", type="integer")
*/
protected $groupId;
/**
* #var string
* #ORM\Column(name="GRP_CODE", type="string")
*/
protected $groupCode;
/**
* #var User\Group
* #ORM\ManyToOne(targetEntity="Application\Model\User\Group",fetch="EAGER")
* #ORM\JoinColumn(name="GRP_ID", referencedColumnName="GRP_ID")
*/
protected $group;
/**
* #var Event
* #ORM\OneToMany(targetEntity="Application\Model\Event", mappedBy="user")
* #ORM\JoinColumn(name="USR_ID", referencedColumnName="USR_ID")
*/
protected $events;
/**
* Constructor
*/
public function __construct()
{
$this->events = new Collections\ArrayCollection();
}
/**
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* #param string $code
* #return User
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* #return Event
*/
public function getEvents()
{
return $this->events;
}
/**
* #param Event $events
* #return User
*/
public function setEvents($events)
{
$this->events = $events;
return $this;
}
/**
* #return User\Group
*/
public function getGroup()
{
return $this->group;
}
/**
* #param User\Group $group
* #return User
*/
public function setGroup($group)
{
$this->group = $group;
return $this;
}
/**
* #return string
*/
public function getGroupCode()
{
return $this->groupCode;
}
/**
* #param string $groupCode
* #return User
*/
public function setGroupCode($groupCode)
{
$this->groupCode = $groupCode;
return $this;
}
/**
* #return int
*/
public function getGroupId()
{
return $this->groupId;
}
/**
* #param int $groupId
* #return User
*/
public function setGroupId($groupId)
{
$this->groupId = $groupId;
return $this;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
* #return User
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return string
*/
public function getLogin()
{
return $this->login;
}
/**
* #param string $login
* #return User
*/
public function setLogin($login)
{
$this->login = $login;
return $this;
}
}
Group
<?php namespace Application\Model\User;
use Application\Model;
use Doctrine\Common\Collections;
use Doctrine\ORM\Mapping as ORM;
/**
* User group model
* Read-only entity
* #ORM\Table(name="VLOGGER_WEBCALENDAR_GRP")
* #ORM\Entity
* #package Application\Model
*/
class Group
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="GRP_ID", type="integer")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="GRP_CODE", type="string")
*/
protected $code;
/**
* #var Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="Application\Model\User", mappedBy="group")
* #ORM\JoinColumn(name="GRP_ID", referencedColumnName="GRP_ID")
*/
protected $users;
/**
* Constructor
*/
public function __construct()
{
$this->users = new Collections\ArrayCollection();
}
/**
* #return mixed
*/
public function getCode()
{
return $this->code;
}
/**
* #param mixed $code
* #return Group
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param int $id
* #return Group
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return mixed
*/
public function getUsers()
{
return $this->users;
}
/**
* #param mixed $users
* #return Group
*/
public function setUsers($users)
{
$this->users = $users;
return $this;
}
}
When I try to retrieve the relation from the groups, it works great, but when I slect the users and try to get their group, Doctrine create some proxy objects and the result is an empty object with only the relationship key filled.
Can someone point me to the good direction ?
Here my code:
$query = $em->createQueryBuilder()
->select('u')
->from('Application\Model\User', 'u');
$data = $query->getQuery()->getResult();
$data = reset($data);
var_dump($data->getGroup()); // proxy
###########################
$query = $em->createQueryBuilder()
->select('g')
->from('Application\Model\User\Group', 'g');
$data = $query->getQuery()->getResult();
$data = reset($data);
var_dump($data->getUsers()); // ok
you don't need the $GRP_ID in the User Entity - it's already mapped with the $group relation. Doctrine handles the IDs automatically.
Also your naming-convention looks a bit weird. Normally you should use lowe-camel-case (to save you from strange errors)
Example:
$USR_CODE should be $usrCode -> to match your getter/setter: setUsrCode(), getUsrCode().
just noticed: you don't have any setters. You have to define setters for your attributes, with the naming-convention (look at my example above)
Edit:
you can map the column with the doctrine orm notation:
/**
*
* #ORM\Column(name="USR_CODE", type="string")
*/
private $usrCode;
And yes, you need setters otherwise doctrine won't be able to set the values.
You also need addUser() and removeUser() functions (since user is a Collection):
public function addUsers(Collection $users)
{
foreach($users as $user)
{
if( ! $this->users->contains($user))
{
$this->users->add($user);
$user->setGroup($this);
}
}
}
public function removeUsers(Collection $users)
{
foreach($users as $user)
{
if($this->users->contains($user)){
$this->users->remove($user);
$user->setGroup(null);
}
}
}

How remove registry from Many To Many relationship - Doctrine 2

I'm trying remove a registry from my database using doctrine 2, but I'm getting the follow error:
Catchable fatal error: Argument 1 passed to Doctrine\ORM\Mapping\DefaultQuoteStrategy::getJoinTableName() must be an array, null given, called in /home/triangulum/www/pedal/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php on line 1020 and defined in /home/triangulum/www/pedal/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php on line 86
I have 3 tables:
grupo = id, name
permissao = id, name
grupo_permissao = grupo_id, permissao_id
My entitys:
Grupo:
<?php
namespace User\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="grupo")
* #ORM\Entity(repositoryClass="User\Entity\GrupoRepository")
*/
class Grupo {
public function __construct($options=null) {
Configurator::configure($this, $options);
$this->permissoes = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var int
*/
protected $id;
/**
* #ORM\Column(type="text")
* #var string
*/
protected $nome;
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Permissao", mappedBy="grupo", cascade={"remove"})
*/
protected $permissoes;
public function getPermissoes()
{
return $this->permissoes;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getNome() {
return $this->nome;
}
public function setNome($nome) {
$this->nome = $nome;
}
public function toArray()
{
return array
(
'id' => $this->getId(),
'nome' => $this->getNome()
);
}
}
?>
Permissao:
<?php
namespace User\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="permissao")
* #ORM\Entity(repositoryClass="User\Entity\PermissaoRepository")
*/
class Permissao {
public function __construct($options=null) {
Configurator::configure($this, $options);
$this->grupos = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var int
*/
protected $id;
/**
* #ORM\Column(type="text")
* #var string
*/
protected $nome;
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Grupo", inversedBy="permissao", cascade={"persist", "remove"})
* #ORM\JoinTable(name="grupo_permissao",
* joinColumns={#ORM\JoinColumn(name="permissao_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="grupo_id", referencedColumnName="id")}
* )
*/
protected $grupos;
public function getGrupos() {
return $this->grupos;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getNome() {
return $this->nome;
}
public function setNome($nome) {
$this->nome = $nome;
}
public function toArray()
{
return array
(
'id' => $this->getId(),
'nome' => $this->getNome()
);
}
}
?>
remove:
public function delete($id)
{
$entity = $this->entityManager->find('User\Entity\Grupo', $id);
if($entity)
{
$this->entityManager->remove($entity);
$this->entityManager->flush();
return $id;
}
}
What am I doing wrong?
I think you have a problem with your mappedBy and inversedBy attributes in the manyToMany annotations. They should match the other entities property name, grupos and permissoes. Try this:
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Permissao", mappedBy="grupos", cascade={"remove"})
*/
protected $permissoes;
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Grupo", inversedBy="permissoes", cascade={"persist", "remove"})
* #ORM\JoinTable(name="grupo_permissao",
* joinColumns={#ORM\JoinColumn(name="permissao_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="grupo_id", referencedColumnName="id")}
* )
*/
protected $grupos;