Doctrine 2 one-to-many relationship - doctrine-orm

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);
}
}
}

Related

Doctrine association persist

I have a problem with doctrine. I have two entities.
FriendRequest
class FriendRequest
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue **/
protected $id;
/**
* First person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="id", referencedColumnName="id")
*/
protected $from;
/**
* Second person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="id", referencedColumnName="id")
*/
protected $to;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getFrom()
{
return $this->from;
}
/**
* #param mixed $from
*/
public function setFrom($from)
{
$this->from = $from;
}
/**
* #return mixed
*/
public function getTo()
{
return $this->to;
}
/**
* #param mixed $to
*/
public function setTo($to)
{
$this->to = $to;
}
}
And User
/**
* #ORM\Entity #ORM\Table(name="users")
*/
class User
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue **/
protected $id;
/** #ORM\Column(type="string") **/
protected $email;
/** #ORM\Column(type="string") **/
protected $password;
/** #ORM\Column(type="string") **/
protected $name;
/** #ORM\Column(type="string") **/
protected $surname;
/** #ORM\Column(type="date") **/
protected $date;
/** #ORM\Column(type="string") **/
protected $sex;
/**
* #return mixed
*/
public function getSex()
{
return $this->sex;
}
/**
* #param mixed $sex
*/
public function setSex($sex)
{
$this->sex = $sex;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getEmail()
{
return $this->email;
}
/**
* #param mixed $email
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* #return mixed
*/
public function getPassword()
{
return $this->password;
}
/**
* #param mixed $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getSurname()
{
return $this->surname;
}
/**
* #param mixed $surname
*/
public function setSurname($surname)
{
$this->surname = $surname;
}
/**
* #return mixed
*/
public function getDate()
{
return $this->date;
}
/**
* #param mixed $date
*/
public function setDate($date)
{
$this->date = $date;
}
}
I tried to create the new friendship request.
$from = $this->entity_manager->getRepository(User::class)->findOneBy(
["id" => $my_id]
);
$to = $this->entity_manager->getRepository(User::class)->findOneBy(
["id" => $target_user_id]
);
/** #var FriendRequest $friend_request */
$friend_request = new FriendRequest();
$friend_request->setFrom($from);
$friend_request->setTo($to);
$this->entity_manager->persist($friend_request);
$this->entity_manager->flush();
But it does not work. Doctrine shows me error:
An exception occurred while executing 'INSERT INTO friendRequest (id) VALUES (?)' with params [186]:
SQLSTATE[HY000]: General error: 1364 Field 'from' doesn't have a default value.
I tried to print $from ad $to, but they are correct. Is there someone who know what does it mean? I spent a lot of time with it, but I dont know...
I think your issue comes from the declaration of the $from and $to attributes in the FriendRequest entity class, if you try to update your database model you are going to get an error like this:
[Doctrine\ORM\Mapping\MappingException]
Duplicate definition of column 'id' on entity 'FriendRequest' in a field or discriminator column mapping.
Since you have assigned the same name 'id' for two different attributes. Probably you have in your database two columns From and To, but they are not mapping with your model, that's why you get an error saying from doesn't have a default value. Since the column name in the database are not sync with the name of the attributes in your entity.
Assuming you already have a FriendRequest table and you are using 'from' and 'to' as the column names this should be the update of the FriendRequest entity class.
class FriendRequest
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue **/
protected $id;
/**
* First person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="from", referencedColumnName="id")
*/
protected $from;
/**
* Second person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="to", referencedColumnName="id")
*/
protected $to;
...
}

"Class is not a valid entity..." error for EntityManager#getClassMetadata(...)

I'm trying to write a test case for to post it on the Doctrine's GitHub page and have a problem with schema generating. The call
$this->_em->getClassMetadata(Server::class)
causes the exception
Class "Doctrine\Tests\Models\DDC6786\Server" is not a valid entity or mapped super class.
What am I doing wrong ? / How to get it working?
CODE
DDC6786Test
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\DDC6786\Endpoint;
use Doctrine\Tests\Models\DDC6786\EndpointServerConfig;
use Doctrine\Tests\Models\DDC6786\Server;
use Doctrine\Tests\OrmFunctionalTestCase;
class DDC6786Test extends OrmFunctionalTestCase
{
public function testIssue()
{
$this->assertTrue(true);
}
public function setUp()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(Server::class),
$this->_em->getClassMetadata(EndpointServerConfig::class),
$this->_em->getClassMetadata(Endpoint::class),
]
);
} catch(\Exception $e) {
$breakpoint = null;
}
}
}
Endpoint
namespace Doctrine\Tests\Models\DDC6786;
use Doctrine\ORM\Mapping as ORM;
use ReflectionClass;
/**
* Endpoint
*
* #ORM\Table(name="endpoint")
* #ORM\Entity
*/
class Endpoint
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="role", type="string", nullable=true)
*/
protected $role;
/**
* #var string
*
* #ORM\Column(name="server_place", type="string", nullable=true)
*
* #Groups({"export"})
*/
protected $serverPlace;
/**
* #var string
*
* #ORM\Column(name="contact_person", type="string", length=500, nullable=true)
*
* #Groups({"export"})
*/
protected $contactPerson;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime", nullable=false)
*/
protected $created;
/**
* #var \DateTime
*
* #ORM\Column(name="updated", type="datetime", nullable=true)
*/
protected $updated;
/**
* #var EndpointServerConfig
*
* #ORM\OneToOne(targetEntity="EndpointServerConfig", inversedBy="endpoint", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="endpoint_server_config_id", referencedColumnName="id")
* })
*
* #Groups({"export"})
*/
protected $endpointServerConfig;
/**
* #param integer $id
*
* #return Endpoint
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #param string $role
*
* #return Endpoint
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* #return string
*/
public function getRole()
{
return $this->role;
}
/**
* #param string $type
*
* #return Endpoint
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* #return string
*
* #Groups({"export"})
*/
public function getType()
{
return str_replace(
'Endpoint',
'',
(new ReflectionClass($this))->getShortName()
);
}
/**
* #param string $serverPlace
*
* #return Endpoint
*/
public function setServerPlace($serverPlace)
{
$this->serverPlace = $serverPlace;
return $this;
}
/**
* #return string
*/
public function getServerPlace()
{
return $this->serverPlace;
}
/**
* #param string $contactPerson
*
* #return Endpoint
*/
public function setContactPerson($contactPerson)
{
$this->contactPerson = $contactPerson;
return $this;
}
/**
* #return string
*/
public function getContactPerson()
{
return $this->contactPerson;
}
/**
* #param \DateTime $created
*
* #return Endpoint
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* #param \DateTime $updated
*
* #return Endpoint
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* #param EndpointServerConfig $endpointServerConfig
*
* #return Endpoint
*/
public function setEndpointServerConfig(EndpointServerConfig $endpointServerConfig = null)
{
$this->endpointServerConfig = $endpointServerConfig;
return $this;
}
/**
* #return EndpointServerConfig
*/
public function getEndpointServerConfig()
{
return $this->endpointServerConfig;
}
}
EndpointServerConfig
namespace Doctrine\Tests\Models\DDC6786;
use Doctrine\ORM\Mapping as ORM;
/**
* EndpointServerConfig
*
* #ORM\Table(name="endpoint_server_config", indexes={
* #ORM\Index(name="fk_endpoint_server_config_server_idx", columns={"server_name"})}
* )
* #ORM\Entity
*/
class EndpointServerConfig
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="dns_address", type="string", length=253, nullable=true)
*/
protected $dnsAddress;
/**
* #var Server
*
* #ORM\ManyToOne(targetEntity="Server")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="server_name", referencedColumnName="name")
* })
*/
protected $server;
/**
* #var Endpoint
*
* #ORM\OneToOne(targetEntity="Endpoint", mappedBy="endpointServerConfig")
*/
protected $endpoint;
/**
* #param integer $id
*
* #return EndpointServerConfig
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #param string $dnsAddress
*
* #return EndpointServerConfig
*/
public function setDnsAddress($dnsAddress)
{
$this->dnsAddress = $dnsAddress;
return $this;
}
/**
* #return string
*/
public function getDnsAddress()
{
return $this->dnsAddress;
}
/**
* #param Server $server
*
* #return EndpointServerConfig
*/
public function setServer(Server $server = null)
{
if(! $server || ! $server->getName()) {
$server = null;
}
$this->server = $server;
return $this;
}
/**
* #return Server
*/
public function getServer()
{
return $this->server;
}
/**
* #param Endpoint $endpoint
*
* #return EndpointServerConfig
*/
public function setEndpoint($endpoint)
{
$this->endpoint = $endpoint;
return $this;
}
/**
* #return Endpoint
*/
public function getEndpoint()
{
return $this->endpoint;
}
}
Server
namespace Doctrine\Tests\Models\DDC6786;
use Doctrine\ORM\Mapping as ORM;
/**
* Server
*
* #ORM\Table(name="server")
* #ORM\Entity
*
* #author automatix
*/
class Server
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=32, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
protected $name;
/**
* #var boolean
*
* #ORM\Column(name="active", type="boolean", nullable=true)
*/
protected $active;
/**
* #var \DateTime
*
* #ORM\Column(name="updated", type="datetime", nullable=true)
*/
protected $updated;
/**
* #var string
*
* #ORM\Column(name="node_name", type="string", length=50, nullable=true)
*/
protected $nodeName;
/**
* #var string
*
* #ORM\Column(name="virtual_node_name", type="string", length=50, nullable=true)
*/
protected $virtualNodeName;
/**
* Not relevant for ORM. Should become obsolete after and be removed after the migration to Doctrine.
*
* #var EndpointServerConfig[]
*/
protected $endpointServerConfigs;
/**
* #param string $name
*
* #return Server
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #param boolean $active
*
* #return Server
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* #return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* #param \DateTime $updated
*
* #return Server
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* #param string $nodeName
*
* #return Server
*/
public function setNodeName($nodeName)
{
$this->nodeName = $nodeName;
return $this;
}
/**
* #return string
*/
public function getNodeName()
{
return $this->nodeName;
}
/**
* #param string $virtualNodeName
*
* #return Server
*/
public function setVirtualNodeName($virtualNodeName)
{
$this->virtualNodeName = $virtualNodeName;
return $this;
}
/**
* #return string
*/
public function getVirtualNodeName()
{
return $this->virtualNodeName;
}
/**
* #param EndpointServerConfig[] $endpointServerConfigs
*
* #return Server
*/
public function setEndpointServerConfigs($endpointServerConfigs)
{
$this->endpointServerConfigs = $endpointServerConfigs;
return $this;
}
/**
* #return EndpointServerConfig[] $endpointServerConfigs
*/
public function getEndpointServerConfigs()
{
return $this->endpointServerConfigs;
}
}
The problem was caused by the annotations. use Doctrine\ORM\Mapping as ORM; & #ORM\Entity doesn't work, but just #ORM\Entity (and #ORM\Table etc.) does.

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);
}
}

Updating Doctrine Collection

I'm working on a survey project and I got 3 Entities, survey(umfrage), surveyQuestion(umfrageFrage) and surveyAnswer(umfrageAntwort).
Here are the entities(removed all unnecessary fields):
namespace Umfrage\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* Umfrage
*
* #ORM\Table(name="umfrage")
* #ORM\Entity
*/
class Umfrage
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Fragen
*
* #ORM\OneToMany(targetEntity="Umfrage\Entity\UmfrageFrage", mappedBy="umfrage", cascade={"persist","remove"})
*/
private $fragen;
public function __construct() {
$this->fragen = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set fragen
*
* #param \Umfrage\Entity\UmfrageFrage $fragen
*
* #return UmfrageFrage
*/
public function setFragen($fragen)
{
$this->fragen = $fragen;
return $this;
}
/** Get fragen
*
* #param \Umfrage\Entity\UmfrageFrage $fragen
*
* #return UmfrageFrage
*/
public function getFragen() {
return $this->fragen;
}
public function addFragen(Collection $fragen)
{
foreach ($fragen as $frage) {
$frage->setUmfrage($this);
$this->fragen->add($frage);
}
}
public function removeFragen(Collection $fragen)
{
foreach ($fragen as $frage) {
$frage->setUmfrage(null);
$this->fragen->removeElement($frage);
}
}
}
The Questions:
namespace Umfrage\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* UmfrageFrage
*
* #ORM\Table(name="umfrage_frage")
* #ORM\Entity
*/
class UmfrageFrage
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \Umfrage\Entity\Umfrage
*
* #ORM\ManyToOne(targetEntity="Umfrage\Entity\Umfrage", inversedBy="fragen")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="umfrage_id", referencedColumnName="id")
* })
*/
private $umfrage;
/**
* #var Antworten
*
* #ORM\OneToMany(targetEntity="Umfrage\Entity\UmfrageAntwort", mappedBy="umfrageFrage", cascade={"all"})
*/
private $antworten;
public function __construct() {
$this->antworten = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set umfrage
*
* #param \Umfrage\Entity\Umfrage $umfrage
*
* #return UmfrageFrage
*/
public function setUmfrage(\Umfrage\Entity\Umfrage $umfrage = null)
{
$this->umfrage = $umfrage;
return $this;
}
/**
* Get umfrage
*
* #return \Umfrage\Entity\Umfrage
*/
public function getUmfrage()
{
return $this->umfrage;
}
/**
* Set antworten
*
* #param \Umfrage\Entity\UmfrageAntwort $antworten
*
* #return UmfrageAntwort
*/
public function setAntworten($antworten)
{
$this->antworten = $antworten;
return $this;
}
/** Get antworten
*
* #param \Umfrage\Entity\UmfrageAntwort $antworten
*
* #return UmfrageAntwort
*/
public function getAntworten() {
return $this->antworten;
}
public function addAntworten(Collection $antworten)
{
foreach ($antworten as $antwort) {
$antwort->setUmfrageFrage($this);
$this->antworten->add($antwort);
}
}
public function removeAntworten(Collection $antworten)
{
foreach ($antworten as $antwort) {
$this->antworten->removeElement($antwort);
}
}
}
The Answers:
namespace Umfrage\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* UmfrageAntwort
*
* #ORM\Table(name="umfrage_antwort")
* #ORM\Entity
*/
class UmfrageAntwort
{
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \Umfrage\Entity\UmfrageFrage
*
* #ORM\ManyToOne(targetEntity="Umfrage\Entity\UmfrageFrage", inversedBy="antworten")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="umfrage_frage_id", referencedColumnName="id")
* })
*/
private $umfrageFrage;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set umfrageFrage
*
* #param \Umfrage\Entity\UmfrageFrage $umfrageFrage
*
* #return UmfrageFrage
*/
public function setUmfrageFrage($umfrageFrage)
{
$this->umfrageFrage = $umfrageFrage;
return $this;
}
/**
* Get umfrageFrage
*
* #return \Umfrage\Entity\UmfrageFrage
*/
public function getUmfrageFrage()
{
return $this->umfrageFrage;
}
}
The Controller action:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('umfrage', array('action'=>'add'));
}
$umfrage = $this->getEntityManager()->find('Umfrage\Entity\Umfrage', $id);
$form = new UmfrageForm($this->getEntityManager());
$form->setHydrator(new DoctrineEntity($this->getEntityManager(),'Umfrage\Entity\Umfrage'));
$form->bind($umfrage);
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getEntityManager()->persist($umfrage);
$this->getEntityManager()->flush();
// Redirect to overview
return $this->redirect()->toRoute('umfrage');
}
}
$this->layout('layout/umfrage_backend');
return new ViewModel(array(
'id' => $id,
'form' => $form
));
}
And the view:
<?php
// module/Umfrage/view/umfrage/umfrage/edit.phtml:
use Doctrine\Common\Util\Debug;
$title = 'Umfrage bearbeiten';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<?php
$form = $this->form;
$form->setAttribute('action', $this->url(
'umfrage',
array(
'action' => 'edit',
'id' => $this->id,
)
));
echo $this->ztbForm($form);
?>
Adding a Survey works fine, Deleting also, the Survey and its related Questions/Answers are removed from the DB. Only the Update actions doesn't work as expected. Survey and Questions are updated, but for the Answers I receive an Insert, instead of an Update, which results in duplicate entries in the DB. What's wrong with the Mapping(Code)?
Thanks in advance for your help!