I'm trying to set up my User entity to use roles, and following the documentation at http://symfony.com/doc/current/cookbook/security/entity_provider.html
Users work fine, and if I hardcode the $roles value everything works as expected, log in/out is good, etc. But, if I try and retrieve the roles through a many-to-many relationship as outlined in the documentation I get back null.
I should also mention that after creating the entities when I ran 'php app/console doctrine:schema:update --force' it created the role table, but not the 'user_role' table as it said it would. I went ahead and created it manually and entered a row for the user I was testing with, but that was my first clue something wasn't working. It's really frustrating because I followed the documentation and it looks like it should work.
The error I get back while trying to log-in is:
FatalErrorException: Error: Call to a member function toArray() on a non-object
Which points to return $this->roles->toArray() in the user entity.
My User Entity (the relevant bits):
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="ACME\MyBundle\Entity\UserRepository")
*
*/
class User implements UserInterface, \Serializable
{
...
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="users")
*
*/
private $roles;
...
/**
* Constructor
*/
public function __construct()
{
$this->roles = new ArrayCollection();
}
public function getRoles()
{
return $this->roles->toArray();
}
...
}
My Role Entity:
use Symfony\Component\Security\Core\Role\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="role")
* #ORM\Entity()
*/
class Role implements RoleInterface
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=30)
*/
private $name;
/**
* #ORM\Column(name="role", type="string", length=20, unique=true)
*/
private $role;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="roles")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
/**
* #see RoleInterface
*/
public function getRole()
{
return $this->role;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Role
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set role
*
* #param string $role
* #return Role
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
}
Does anybody see a problem in my code or have experience with this same issue? I'm stuck at the moment.
In your entity Role you have
* #ORM\Table(name="role")
change it to
* #ORM\Table(name="user_role")
because your table name is user_role not role
I had the same probleme and i removed the toArray methode
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="ACME\MyBundle\Entity\UserRepository")
*
*/
class User implements UserInterface, \Serializable
{
...
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="users")
*
*/
private $roles;
...
/**
* Constructor
*/
public function __construct()
{
$this->roles = new ArrayCollection();
}
public function getRoles()
{
return $this->roles;//return $this->roles->toArray();
}
...
}
Related
in my symfony app, i'm using embedded forms. In my case, an object "CompetenceGroupe" can have multiple objects "CompetenceItem", but an object "CompetenceItem" belongs to only one object "CompetenceGroupe", so the relation is manyToOne.
The form work perfectly, and I have two tables (one for each entity), and it's well saved in the database.
But when I select an CompetenceGroupe object with doctrine in my controller, I have all informations of the object, and he's got an empty "competenceItems" property, so I can't retrieve the childs object (CompetenceItem).
My "CompetenceGroupe" entity :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="competences_groupes")
*/
class CompetenceGroupe
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id_competence_groupe;
/**
* #var User $user
*
* #ORM\ManyToOne(targetEntity="User", cascade={"persist", "merge"})
* #ORM\JoinColumn(name="id_user", referencedColumnName="id_user", nullable=false)
*/
private $user;
/**
* #ORM\Column(type="string", length=60, nullable=true)
*/
protected $titre;
protected $competence_items;
public function __construct()
{
$this->competence_items = new ArrayCollection();
}
public function getCompetenceItems()
{
return $this->competence_items;
}
/**
* Get idCompetenceGroupe
*
* #return integer
*/
public function getIdCompetenceGroupe()
{
return $this->id_competence_groupe;
}
/**
* Set titre
*
* #param string $titre
*
* #return CompetenceGroupe
*/
public function setTitre($titre)
{
$this->titre = $titre;
return $this;
}
/**
* Get titre
*
* #return string
*/
public function getTitre()
{
return $this->titre;
}
/**
* Set user
*
* #param \AppBundle\Entity\User $user
*
* #return CompetenceGroupe
*/
public function setUser(\AppBundle\Entity\User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
public function addItem(CompetenceItem $item)
{
$this->competence_items->add($item);
}
public function removeItem(CompetenceItem $item)
{
// ...
}
/**
* Set competenceItems
*
* #param \AppBundle\Entity\CompetenceItem $competenceItems
*
* #return CompetenceGroupe
*/
public function setCompetenceItems(\AppBundle\Entity\CompetenceItem $competenceItems = null)
{
$this->competence_items = $competenceItems;
return $this;
}
}
And my "CompetenceItem" entity :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="competences_items")
*/
class CompetenceItem
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id_competence_item;
/**
* #ORM\Column(type="string", length=60, nullable=false)
*/
protected $libelle;
/**
* #var CompetenceNiveau $niveau
*
* #ORM\ManyToOne(targetEntity="CompetenceNiveau", cascade={"persist", "merge"})
* #ORM\JoinColumn(name="id_competence_niveau", referencedColumnName="id_competence_niveau", nullable=true)
*/
private $niveau;
/**
* #var CompetenceGroupe $competence_groupe
*
* #ORM\ManyToOne(targetEntity="CompetenceGroupe", cascade={"persist", "merge"})
* #ORM\JoinColumn(name="id_competence_groupe", referencedColumnName="id_competence_groupe", nullable=false)
*/
private $competence_groupe;
/**
* Get idCompetenceItem
*
* #return integer
*/
public function getIdCompetenceItem()
{
return $this->id_competence_item;
}
/**
* Set libelle
*
* #param string $libelle
*
* #return CompetenceItem
*/
public function setLibelle($libelle)
{
$this->libelle = $libelle;
return $this;
}
/**
* Get libelle
*
* #return string
*/
public function getLibelle()
{
return $this->libelle;
}
/**
* Set niveau
*
* #param \AppBundle\Entity\CompetenceNiveau $niveau
*
* #return CompetenceItem
*/
public function setNiveau(\AppBundle\Entity\CompetenceNiveau $niveau = null)
{
$this->niveau = $niveau;
return $this;
}
/**
* Get niveau
*
* #return \AppBundle\Entity\CompetenceNiveau
*/
public function getNiveau()
{
return $this->niveau;
}
/**
* Set competenceGroupe
*
* #param \AppBundle\Entity\CompetenceGroupe $competenceGroupe
*
* #return CompetenceItem
*/
public function setCompetenceGroupe(\AppBundle\Entity\CompetenceGroupe $competenceGroupe)
{
$this->competence_groupe = $competenceGroupe;
return $this;
}
/**
* Get competenceGroupe
*
* #return \AppBundle\Entity\CompetenceGroupe
*/
public function getCompetenceGroupe()
{
return $this->competence_groupe;
}
}
I think I have a missing annotation of the "competence_items" property in the CompetenceGroupe entity, but i'm really not sure ...
Thanks for your help !
A good practice may be to have a competence form, which would be call inside your competence group form
You may add a CollectionType as parrent and include query to search which competence already exist
There are some good example with post form type in symfony demo blog
Or you can use form events (onSubmit, preSubmit, etc...) to charge your entity with your required competence. This example show a message form which allow to choose friend from preset data, this is a good example.
You have tow choice , even to create a Many-To-One, Unidirectional , in this case , you need clean some code , take a look:
In CompetenceGroupe class :
class CompetenceGroupe
{
/**
* Many competence have One Group.
* #ManyToOne(targetEntity="CompetenceItem")
* #JoinColumn(name="id_competence_item", referencedColumnName="id_competence_item")
*/
protected $competence_items;
public function __construct()
{
// $this->competence_items = new ArrayCollection();
//delete that line
}
In CompetenceItem class :
class CompetenceItem
{
You need to delete private $competence_groupe; attribute with his annotation :
By this way, when you dump a CompetenceGroupe object you gonna find the competence items.
Also, you can do it with One-To-Many, Bidirectional ,if you want to get the data from the inverse side and from the owning side .
EDIT: If one competenceGroupe can have many competenceItems, then that is a OneToMany relationship; this is the inverse side of the relationship as defined by doctrine, but that is ok. Your question asked how to pull a competenceGroupe and retrieve all related competenceItems. You can do this by making the competenceItems an ArrayCollection in your CompetenceGroupe entity, just as you have done. You do have to define that further in the annotation, see (updated) code below.
For an ArrayCollection, you can remove your method setCompetenceItems and instead define a method addCompetenceItem in your CompetenceGroupe entity.
class CompetenceGroupe
{
/**
* #ORM\OneToMany(targetEntity="CompetenceItem", mappedBy="competence_groupe")
*/
protected $competenceItems;
public function __construct()
{
$this->competenceItems= new ArrayCollection();
}
/**
* Add competenceItem
*
* #param CompetenceItem $competenceItem
* #return CompetenceGroupe
*/
public function addCompetenceItem(CompetenceItem $competenceItem)
{
$this->competence_items->add($competenceItem);
return $this;
}
}
You'll also need to define the owning side to make all this work.
I'm trying to setup a one-to-many database, using Doctrine. One User, can have multiple Roles, and when I get the User, I want to get the associated Roles. I have a raw MySQL query that does that.
SELECT
u.*,
GROUP_CONCAT(r.role) as roles
FROM
users u
INNER JOIN user_roles ur ON ur.user_id = u.id
INNER JOIN roles r ON r.id = ur.role_id
GROUP BY id;
+----+----------+------------------------+--------------------------------------------------------------+-----------+----------------------+
| id | username | email | password | is_active | GROUP_CONCAT(r.role) |
+----+----------+------------------------+--------------------------------------------------------------+-----------+----------------------+
| 1 | admin | my#email.address | $2a$08$jHZj/wJfcVKlIwr5AvR78euJxYK7Ku5kURNhNx.7.CSIJ3Pq6LEPC | 1 | ROLE_USER,ROLE_ADMIN |
+----+----------+------------------------+--------------------------------------------------------------+-----------+----------------------+
Is this something I can actually automatically replicate in Doctrine? And if so, where abouts am I going wrong? Here are my current (broken) classes (apologies for the code dump).
The error this is currently logging is:
[2016-12-20 12:01:35] security.INFO: Authentication request failed. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\Auth
enticationServiceException(code: 0): Notice: Undefined index: user at /var/www/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authe
ntication/Provider/DaoAuthenticationProvider.php:94, Symfony\\Component\\Debug\\Exception\\ContextErrorException(code: 0): Notice: Undefined in
dex: user at /var/www/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:1768)"} []
User.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface, \Serializable
{
...
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="UserRoles", mappedBy="user", fetch="EAGER")
*/
private $roles;
public function __construct()
{
$this->isActive = true;
// may not be needed, see section on salt below
// $this->salt = md5(uniqid(null, true));
$this->roles = new ArrayCollection();
}
...
public function getRoles()
{
return $this->roles;
}
/**
* Add role
*
* #param \AppBundle\Entity\UserRoles $role
*
* #return User
*/
public function addRole(\AppBundle\Entity\UserRoles $role)
{
$this->roles[] = $role;
return $this;
}
/**
* Remove role
*
* #param \AppBundle\Entity\UserRoles $role
*/
public function removeRole(\AppBundle\Entity\UserRoles $role)
{
$this->roles->removeElement($role);
}
}
Role.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Role
*
* #ORM\Table(name="roles")
* #ORM\Entity(repositoryClass="AppBundle\Repository\RoleRepository")
*/
class Role
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="role", type="string", length=255, unique=true)
*/
private $role;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set role
*
* #param string $role
*
* #return Role
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* #return string
*/
public function getRole()
{
return $this->role;
}
}
UserRoles.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* UserRoles
*
* #ORM\Table(name="user_roles")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRolesRepository")
*/
class UserRoles
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="userroles")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $userId;
/**
* #var int
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Role")
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
*/
private $roleId;
/**
* Set userId
*
* #param integer $userId
*
* #return UserRoles
*/
public function setUserId($userId)
{
$this->userId = $userId;
return $this;
}
/**
* Get userId
*
* #return int
*/
public function getUserId()
{
return $this->userId;
}
/**
* Set roleId
*
* #param integer $roleId
*
* #return UserRoles
*/
public function setRoleId($roleId)
{
$this->roleId = $roleId;
return $this;
}
/**
* Get roleId
*
* #return int
*/
public function getRoleId()
{
return $this->roleId;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
In the $roles association inside your User entity you set the mappedBy attribute to user, but your UserRoles entity does not have such a field. Instead it has a field called userId.
Doctrine tries to find the association using your mapping. The user value from your #mappedBy attribute cannot be found in the database, hence the error message:
Undefined index...
Since you are mapping objects you should reconsider the naming convention inside your UserRoles entity. So don't use $userId and $roleId but simply use User and Role and also set dependency injection and return values inside your setters and getters to match User and Role classes.
Since UserRoles is an entity (and not a collection) I would also suggest renaming it to UserRole (singular). It will help you understand what you have.
Start with changing your UserRoles like this:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\User;
use AppBundle\Entity\Role;
/**
* UserRole
*
* #ORM\Table(name="user_roles")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRoleRepository")
*/
class UserRole
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var User
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="userRoles")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #var Role
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Role")
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
*/
private $role;
/**
* Set user
*
* #param User $user
* #return UserRole
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return User
*/
public function getUser()
{
return $this->user;
}
/**
* Set role
*
* #param Role $role
* #return UserRole
*/
public function setRole(Role $role)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* #return Role
*/
public function getRole()
{
return $this->role;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
And change your User entity to match these changes accordingly:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\UserRole;
use Serializable;
/**
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface, Serializable
{
...
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UserRole", mappedBy="user", fetch="EAGER")
*/
private $userRoles;
public function __construct()
{
$this->isActive = true;
// may not be needed, see section on salt below
// $this->salt = md5(uniqid(null, true));
$this->userRoles = new ArrayCollection();
}
...
/**
* #return Collection
*/
public function getUserRoles()
{
return $this->userRoles;
}
/**
* Add user role
*
* #param UserRole $userRole
*
* #return User
*/
public function addUserRole(UserRole $userRole)
{
$this->userRoles[] = $userRole;
return $this;
}
/**
* Remove role
*
* #param UserRole $userRole
*/
public function removeUserRole(UserRole $userRole)
{
$this->userRoles->removeElement($userRole);
}
}
Since your the repository for your User class is called UserRepository I also renamed UserRolesRepository to UserRoleRepository (singular).
Why my methid setUserId not work?
It's my Post entity:
<?php
// src/Acme/UserBundle/Entity/User.php
namespace Acme\PostBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="posts")
*/
class Post
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(type="integer", nullable=false)
*/
public $user_id;
/**
* #ORM\ManyToOne(targetEntity="Acme\PostBundle\Entity\User", inversedBy="posts")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank(message="Введите текст")
* )
*/
protected $text;
/**
* #ORM\Column(type="string", length=255)
*/
protected $address;
/**
*
* #ORM\Column(type="datetime")
*/
protected $date;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set user_id
*
* #param integer $userId
* #return Post
*/
public function setUserId($userId)
{
$this->user_id = $userId;
return $this;
}
/**
* Get user_id
*
* #return integer
*/
public function getUserId()
{
return $this->user_id;
}
public function getText()
{
return $this->text;
}
public function __construct() {
$this->date = new \DateTime();
}
//...
}
And my User entity:
<?php
// src/Acme/UserBundle/Entity/User.php
namespace Acme\PostBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(type="string")
*/
protected $path;
/**
*
* #ORM\Column(type="string")
*/
protected $username;
/**
* #ORM\OneToMany(targetEntity="Acme\PostBundle\Entity\Post", mappedBy="users")
*/
protected $posts;
public function __construct() {
$this->posts = new ArrayCollection();
}
}
I'm saving in the database via my controller:
public function createAction(Request $request)
{
$post = new Post();
$form = $this->createFormBuilder($post)
->add('text')
->add('address')
->getForm();
$post->setUserId($this->getUser()->getId());
$form->handleRequest($request);
if($form->isValid()){
$em = $this->getDoctrine()->getManager();
$em->persist($post);
$em->flush();
}
return $this->redirect($this->generateUrl('home'));
}
And i throw this error:
Integrity constraint violation: 1048 Column 'user_id' cannot be null
Why? My $this->getUser()->getId() is not null, i tried return new Response($this->getUser()->getId()) and get my id
You dont need user_id field because you have user relation on field:
/**
* #ORM\ManyToOne(targetEntity="Acme\PostBundle\Entity\User", inversedBy="posts")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
Look in you database, doctrine already created user_id for you.
As the others stated its not possible to set $userId on its own if you have also defined an $user property as entity using the same database column.
Instead change your setters and keep everything else as it is:
class Post
{
// ...
/**
* Set user_id
*
* #param integer $userId
* #throws \Exception
*/
public function setUserId($userId)
{
throw new \Exception('Post->userId can not be set directly');
}
/**
* Set user
*
* #param User $user
* #return Post
*/
public function setUser($user)
{
$this->user = $user;
$this->user_id = $user->getId();
return $this;
}
// ...
}
Now the $userId is automatically updated when you use setUser(...).
Throwing an exception in setUserId helps you preventing bugs in your code. Of course you could also just delete the setter, but it then would be recreated everytime you run another doctrine:generate:entities for your post entity.
I have a big understanding problem with OneToMany Relationship - i searched a lot but that didnt help, maybe someone can help me with this.
I have a Event Entity with OneToMany Relation
<?php
namespace #\#\#;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Turmforum\BookingBundle\Entity\Contact;
/**
* Event
*
* #ORM\Table(name="events")
* #ORM\Entity
*/
class Event
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Contact", mappedBy="event")
*/
protected $event_contacts;
/**
*
*/
public function __construct() {
$this->contacts = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function getContacts() {
return $this->contacts;
}
public function addContact(Contact $contact) {
$this->contacts[] = $contact;
return $this;
}
And have a Contact Entity with ManyToOne Relation
<?php
namespace #\#\#;
use Doctrine\ORM\Mapping as ORM;
use Turmforum\BookingBundle\Entity\Event;
/**
* Contact
*
* #ORM\Table(name="contacts")
* #ORM\Entity
*/
class Contact
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Event", inversedBy="event_contacts")
* #ORM\JoinColumn(name="event_id", referencedColumnName="id")
*/
protected $event;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getEvent() {
return $this->event;
}
When i try to save my event details over a form i get the error:
Neither the property "event_id" nor one of the methods "getEventId()",
"eventId()", "isEventId()", "hasEventId()", "__get()" exist and have
public access in class "Turmforum\BookingBundle\Entity\Event".
What am i missing?
First of all: the error I'm getting is: Entities passed to the choice field must be managed
I have these entities:
- user (belongs to one or many teams)
- team (has one or 2 users)
- challenge (has 2 teams)
I'd like to build a ChallengeType form where a user can fill in the two users for the two teams and create the challenge. I think I need an embedded form here.
I've made a TeamType Form class: (I would expect to get a select box from this, where all users are listed)
<?php
namespace Tennisconnect\DashboardBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class TeamType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('players', 'entity', array(
'class' => 'TennisconnectUserBundle:User',
'multiple' => true
));
}
public function getName()
{
return 'team';
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'Tennisconnect\DashboardBundle\Entity\Team');
}
}
This is the ChallengeType form class:
<?php
namespace Tennisconnect\DashboardBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ChallengeType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('teams', 'collection', array('type' => new TeamType()));
}
public function getName()
{
return 'challenge';
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'Tennisconnect\DashboardBundle\Entity\Challenge');
}
}
Challenge entity:
namespace Tennisconnect\DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Tennisconnect\DashboardBundle\Entity\Team;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="challenge")
*/
class Challenge
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Team", mappedBy="teams")
*/
protected $teams;
public function __construct()
{
$this->teams = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add teams
*
* #param Tennisconnect\DashboardBundle\Entity\Team $teams
*/
public function addTeam(Team $teams)
{
$this->teams[] = $teams;
}
/**
* Get teams
*
* #return Doctrine\Common\Collections\Collection
*/
public function getTeams()
{
return $this->teams;
}
}
Team entity:
namespace Tennisconnect\DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Tennisconnect\UserBundle\Entity\User;
use Tennisconnect\DashboardBundle\Entity\Challenge;
use Tennisconnect\DashboardBundle\Entity\Match;
/**
* #ORM\Entity
* #ORM\Table(name="team")
*/
class Team
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Tennisconnect\UserBundle\Entity\User", mappedBy="teams")
*/
protected $players;
/**
* #ORM\ManyToMany(targetEntity="challenge", inversedBy="teams", cascade= {"persist"})
*/
protected $challenges;
/**
* #ORM\ManyToMany(targetEntity="Match", inversedBy="teams")
*/
protected $matches;
public function __construct()
{
$this->players = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add players
*
* #param Tennisconnect\UserBundle\Entity\User $players
*/
public function addUser(User $players)
{
$this->players[] = $players;
}
/**
* Get players
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPlayers()
{
return $this->players;
}
/**
* Add matches
*
* #param Tennisconnect\DashboardBundle\Entity\Match $matches
*/
public function addMatch(Match $matches)
{
$this->matches[] = $matches;
}
/**
* Get matches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMatches()
{
return $this->matches;
}
/**
* Add challenges
*
* #param Tennisconnect\DashboardBundle\Entity\challenge $challenges
*/
public function addchallenge(challenge $challenges)
{
$this->challenges[] = $challenges;
}
/**
* Get challenges
*
* #return Doctrine\Common\Collections\Collection
*/
public function getChallenges()
{
return $this->challenges;
}
}
Challenge controller:
class ChallengeController extends Controller
{
public function newAction()
{
$challenge = new Challenge();
$form = $this->createForm(new ChallengeType(), $challenge);
return $this->render('TennisconnectDashboardBundle:Challenge:new.html.twig', array('form' => $form->createView()));
}
}
You've created forms that are displaying a ManyToMany collection; set the multiple option in your formbuilder for those widgets to true (it defaults false, which fundamentally conflicts with a ToMany relationship).
If you have the error Entities passed to the choice field must be managed. Maybe persist them in the entity manager? with a ManyToMany relationship between 2 entities, when using a form type, it may come from your entity constructor :
If your form is "TeamType", try to remove the ArrayCollection initialization of your "Team" entity.
Your Team class become :
namespace Tennisconnect\DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Tennisconnect\UserBundle\Entity\User;
use Tennisconnect\DashboardBundle\Entity\Challenge;
use Tennisconnect\DashboardBundle\Entity\Match;
/**
* #ORM\Entity
* #ORM\Table(name="team")
*/
class Team
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Tennisconnect\UserBundle\Entity\User", mappedBy="teams")
*/
protected $players;
/**
* #ORM\ManyToMany(targetEntity="challenge", inversedBy="teams", cascade= {"persist"})
*/
protected $challenges;
/**
* #ORM\ManyToMany(targetEntity="Match", inversedBy="teams")
*/
protected $matches;
public function __construct()
{
// REMOVE $this->players = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add players
*
* #param Tennisconnect\UserBundle\Entity\User $players
*/
public function addUser(User $players)
{
$this->players[] = $players;
}
/**
* Get players
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPlayers()
{
return $this->players;
}
/**
* Add matches
*
* #param Tennisconnect\DashboardBundle\Entity\Match $matches
*/
public function addMatch(Match $matches)
{
$this->matches[] = $matches;
}
/**
* Get matches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMatches()
{
return $this->matches;
}
/**
* Add challenges
*
* #param Tennisconnect\DashboardBundle\Entity\challenge $challenges
*/
public function addchallenge(challenge $challenges)
{
$this->challenges[] = $challenges;
}
/**
* Get challenges
*
* #return Doctrine\Common\Collections\Collection
*/
public function getChallenges()
{
return $this->challenges;
}
}
The problem is solved.
I had to add the "allow_add" option to my collection in the ChallengeType class.
The challenge controller class needed some editing too. I added 2 teams to the Challenge object before passing it through to the form.