I'm learning SF2 - really impressed with the job done, faced my first real issue I can't solve myself.
I have two entities: Post and Tag. Shortened code below:
class Tag
{
/**
* #ORM\ManyToMany(targetEntity="Post", mappedBy="tags", cascade={"persist"})
*/
private $posts;
public function __construct()
{
$this->posts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #param \My\AppBundle\Entity\Snippet $posts
* #return Tag
*/
public function addSnippet(\My\AppBundle\Entity\Post $posts)
{
$this->posts[] = $posts;
return $this;
}
/**
* #param \My\AppBundle\Entity\Snippet $snippets
*/
public function removeSnippet(\My\AppBundle\Entity\Post $posts)
{
$this->posts->removeElement($posts);
}
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getSnippets()
{
return $this->posts;
}
}
class Post
{
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="posts", cascade={"persist"})
* #ORM\JoinTable(name="posts_tags",
* joinColumns={#ORM\JoinColumn(name="post_id", referencedColumnName="id", unique=true, onDelete="cascade")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id", unique=true, onDelete="cascade")}
* )
*/
private $tags;
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #param \My\AppBundle\Entity\Tag $tags
* #return Snippet
*/
public function addTag(\My\AppBundle\Entity\Tag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* #param \My\AppBundle\Entity\Tag $tags
*/
public function removeTag(\My\AppBundle\Entity\Tag $tags)
{
$this->tags->removeElement($tags);
}
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
As you can see I have M:M relation between two entities.
I have also a form to add Post with embedded Tag collection:
$builder
->add('title')
->add('tags', 'collection', array(
'type' => new \My\AppBundle\Form\TagType(),
'allow_add' => true,
'by_reference' => false,
'prototype' => true
))
;
TagType form class:
$builder->add('name');
Everything works as expected. Except one thing: if there's a Tag object with the following name, I'm getting SQLSTATE[23000]: Integrity constraint violation MySQL error which is obvious. If I apply unique validation constraint I can add a tag to post (if it already exists in database).
It's obvious I need to check if following tag does exist in database and add it only if does not, but... how to do it Symfony way?
Any suggestions appreciated!
You can use UniqueEntity to handle this. I can't see your annotations on your tags class, or your declaration of 'name' but if you add something like the below it should give you a unique validation constraint based on name with an optional message to throw back.
/**
* #ORM\Entity
* #UniqueEntity(fields="name", message="This tag name already exists")
*/
class Tag...
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
protected $name;
Related
I have interesting problem for forms in Symfony 3.2.14.
Have two bundles AppBundle and UserBundle.
In AppBundle have entity, with appropriate repository, and working formType.
If I create a form which has EntityType::class, field and I'm in AppBundle - form works (generated in controller on action etc.) but If I'm trying to use Entity located in AppBundle in formType created in UserBundle and creating a field in
$builder ->add ('columnName',
EntityType::class, [
'label' => 'Country',
'class' => ProdCountry::class,
'choice_value' => 'id',
'choice_label' => 'name',
'expanded' => false,
'multiple' => false,
])]
- when upgrading or inserting data - have error: AppBundle\Entity\EntityName.php - cannot be converted to INT
in form type - datasource is entity in current UserBundle, and one of fields that I'm trying to fill is just an id from other entity (int in database)
yes, INT not STRING
Post data from form is correct and entity field passes number like 2, or 5 or any different id from db as it is configured in choice_value
and as I have said - EntityType field works fine if it is created in formType in same bundle as entity come from.
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class ProdCountry
* #package AppBundle\Entity
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProdCountryRepository")
* #ORM\Table(name="prod_country")
*/
class ProdCountry
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", options={"comment":"nazwa kraju po polsku", "default":"NULL"})
* #Assert\Valid()
* #Assert\NotBlank()
* #Assert\NotNull()
*/
private $polishCountryName;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $iso3166code;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $internetDomain;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $carCode;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $airplaneCode;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $phoneCode;
/**
* #ORM\Column(type="integer", nullable=false)
* #Assert\Valid()
* #Assert\NotNull()
* #Assert\NotBlank()
*/
private $orderField;
/**
* #ORM\Column(type="string", options={"comment":"nazwa kraju w języku oryginalnym", "default":"NULL"})
*/
private $nativeCountryName;
/**
* #ORM\Column(type="string", options={"comment":"nazwa kraju w języku angielskim", "default":"NULL"})
*/
private $englishCountryName;
/**
* #return mixed
*/
public function __toString()
{
return (string)$this->id;
}
/**
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getPolishCountryName()
{
return $this->polishCountryName;
}
/**
* #return mixed
*/
public function getIso3166code()
{
return $this->iso3166code;
}
/**
* #return mixed
*/
public function getInternetDomain()
{
return $this->internetDomain;
}
/**
* #return mixed
*/
public function getCarCode()
{
return $this->carCode;
}
/**
* #return mixed
*/
public function getAirplaneCode()
{
return $this->airplaneCode;
}
/**
* #return mixed
*/
public function getPhoneCode()
{
return $this->phoneCode;
}
/**
* #param mixed $polishCountryName
*/
public function setPolishCountryName($polishCountryName)
{
$this->polishCountryName = $polishCountryName;
}
/**
* #param mixed $iso3166code
*/
public function setIso3166code($iso3166code)
{
$this->iso3166code = $iso3166code;
}
/**
* #param mixed $internetDomain
*/
public function setInternetDomain($internetDomain)
{
$this->internetDomain = $internetDomain;
}
/**
* #param mixed $carCode
*/
public function setCarCode($carCode)
{
$this->carCode = $carCode;
}
/**
* #param mixed $airplaneCode
*/
public function setAirplaneCode($airplaneCode)
{
$this->airplaneCode = $airplaneCode;
}
/**
* #param mixed $phoneCode
*/
public function setPhoneCode($phoneCode)
{
$this->phoneCode = $phoneCode;
}
/**
* #return mixed
*/
public function getOrderField()
{
return $this->orderField;
}
/**
* #param mixed $orderField
*/
public function setOrderField($orderField)
{
$this->orderField = $orderField;
}
/**
* #return mixed
*/
public function getNativeCountryName()
{
return $this->nativeCountryName;
}
/**
* #param mixed $nativeCountryName
*/
public function setNativeCountryName($nativeCountryName)
{
$this->nativeCountryName = $nativeCountryName;
}
/**
* #return mixed
*/
public function getEnglishCountryName()
{
return $this->englishCountryName;
}
/**
* #param mixed $englishCountryName
*/
public function setEnglishCountryName($englishCountryName)
{
$this->englishCountryName = $englishCountryName;
}
}
Finally I have found the solution.
No Relation is defined in Entities User and Country
It depends on type of field in form - exactly - EntityType
EntityType::class,
[
'label' => 'userCountry',
'class' => ProdCountry::class,
'choice_value' => 'id', //not needed
'choice_label' => 'yourEntityProdCountryAttribute',
'expanded' => false,
'multiple' => false,
])
When both - Entity and FormType for that entity are in the same bundle - field in the database can be vchar or int and this will work fine.
When Entity is for example in AppBundle, but FormType is in OtherBundle processing the form will cause an error described above.
Solution is to change field in Entity you writing data to as vchar
or change EntityType field in form to ChoiceType
Solution is just to give different names for forms in src/Forms/YourNameFormType.php
by setting
public function getBlockPrefix()
{
return 'your_form_name_ver';
}
it will make any form unique
and then just ask for a proper form in the controler and view
I'm trying to setup selectable Tags to display/bring up Blogs that are linked to the tags.
What am I doing wrong? Is the problem with the doctrine query or how it's been setup on the entity side?
I'm getting the following error:
ContextErrorException: Notice: Undefined index: joinColumns in /.../vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1665
This is the current query I am using:
public function tagAction($tag)
{
$em = $this->getDoctrine()->getManager();
$tags = $em->getRepository('AcmeBundle:Blog')
->findByTags($tag);
$blogs = $tags->getBlogs();
return array(
'blogs' => $blogs,
);
}
And my entity setup: (Setup as ManyToMany/ManyToMany)
Tag:
/**
* #ORM\ManyToMany(targetEntity="Blog", mappedBy="tags")
*/
protected $blogs;
public function __construct()
{
$this->blogs = new ArrayCollection();
}
/**
* Add blogs
*
* #param \AcmeBundle\Entity\Blog $blogs
* #return Tag
*/
public function addBlog(\AcmeBundle\Entity\Blog $blogs)
{
$this->blogs[] = $blogs;
return $this;
}
/**
* Remove blogs
*
* #param \AcmeBundle\Entity\Blog $blogs
*/
public function removeBlog(\AcmeBundle\Entity\Blog $blogs)
{
$this->blogs->removeElement($blogs);
}
/**
* Get blogs
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getBlogs()
{
return $this->blogs;
}
Blog:
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="blogs")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id")
*/
protected $tags;
public function __construct()
{
$this->tags = new ArrayCollection();
}
/**
* Add tags
*
* #param \AcmeBundle\Entity\Tag $tags
* #return Blog
*/
public function addTag(\AcmeBundle\Entity\Tag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \AcmeBundle\Entity\Tag $tags
*/
public function removeTag(\AcmeBundle\Entity\Tag $tags)
{
$this->tags->removeElement($tags);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
Instead of querying for blog use tag.
$em = $this->getDoctrine()->getManager();
$tags = $em->getRepository('AcmeBundle:Tag')
->findOneByTag($tag);
$blogs = $tags->getBlogs();
return array(
'blogs' => $blogs,
);
I think this error happens because you have the wrong annotation for ManyToMany associations in:
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="blogs")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id")
*/
protected $tags;
For ManyToMany associations I use code as below:
/**
* #ManyToMany(targetEntity="Tag")
* #JoinTable(name="blogs_tags",
* joinColumns={#JoinColumn(name="blog_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
protected $tags;
This is the code as in the official documentation of Doctrine as you can see in http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html
I'm trying to perform a ManyToMany self referencing association in my Symfony 2.1 project by following the Doctrine docs: http://docs.doctrine-project.org/en/latest/reference/association-mapping.html#many-to-many-self-referencing
My use-case is that I'm working on a CMS and I'm adding the ability to have related items of content. For example: I could have a sidebar on a website which would say that this piece of content X is related to Y and Z. Similarly on pages where content Y appears it says that it is related to content item X.
In my tests using this to add a new relation between content items fails because it reaches PHP's maximum nesting level of 100 because it is running toArray() on the current content item and then again on the related content item and so on and so on.
I've seen many similar questions on SO about Many-to-Many Self referential Doctrine associations but none with enough complete code to be able to see how others have managed this. Can anybody help?
My Content entity:
/**
* #ORM\MappedSuperclass
* #ORM\Table(name="content")
* #ORM\Entity(repositoryClass="CMS\Bundle\Common\ContentBundle\Entity\ContentRepository")
* #ORM\InheritanceType("JOINED")
*/
abstract class content implements ContentInterface
{
/**
* #var int $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string", length=255)
* #Assert\NotBlank()
*/
private $title;
// Other class properties
/**
* #var array
*
* #ORM\ManyToMany(targetEntity="Content", cascade={"persist"})
* #ORM\JoinTable(name="content_relation",
* joinColumns={#ORM\JoinColumn(name="relation_id", referencedColumnName="id")},
* inverseJoinColumns={
* #ORM\JoinColumn(name="related_content_id", referencedColumnName="id")
* })
**/
private $related;
public function __construct()
{
$this->related = new ArrayCollection();
}
// Other getters & setters for class properties
/**
* #return array
*/
public function getRelated()
{
return $this->related;
}
/**
* #param Content $relation
*/
public function addRelation(Content $relation)
{
$this->related->add($relation);
$this->related->add($this);
}
/**
* #return array
*/
public function toArray()
{
$related = array();
foreach($this->getRelated() as $relatedItem) {
$related[] = $relatedItem->toArray();
}
return array(
'type' => static::getType(),
'id' => $this->id,
'title' => $this->title,
....
'related' => $related
);
}
In my RelationsController for managing the related content data I use it like this:
/**
* Creates a new relation to a content item
*
* #Route("{_locale}/content/{id}/related", name="relation_add")
* #Method("POST")
*/
public function addAction(Request $request, $id)
{
// Validation and error checking
// $entity is loaded by the repository manager doing a find on the passed $id
$entity->addRelation($relation);
$em = $this->getEntityManager();
$em->persist($entity);
$em->persist($relation);
$em->flush();
$response = $relation->toArray();
return new JsonResponse($response, 201);
}
The fix for this was to use the JMSSerializerBundle to encode the entity to JSON instead of using a toArray method and change the addRelation function to:
/**
* #param Content $relation
*/
public function addRelation(Content $relation)
{
$this->related[] = $relation;
if (! $relation->getRelated()->contains($this)) {
$relation->addRelation($this);
}
}
I'm using Symfony 2.1 and Doctrine 2.
I'm dealing with 2 main entities : Place and Feature, with a ManyToMany relationship between them.
There's many features in the database, and to group them by theme the Feature is also related to a FeatureCategory entity with a ManyToOne relationship.
Here's the code of the different entities :
The Place entity
namespace Mv\PlaceBundle\Entity;
…
/**
* Mv\PlaceBundle\Entity\Place
*
* #ORM\Table(name="place")
* #ORM\Entity(repositoryClass="Mv\PlaceBundle\Entity\Repository\PlaceRepository")
* #ORM\HasLifecycleCallbacks
*/
class Place
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
* #Assert\NotBlank
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="\Mv\MainBundle\Entity\Feature")
* #ORM\JoinTable(name="places_features",
* joinColumns={#ORM\JoinColumn(name="place_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="feature_id", referencedColumnName="id")}
* )
*/
private $features;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Place
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add features
*
* #param \Mv\MainBundle\Entity\Feature $features
* #return Place
*/
public function addFeature(\Mv\MainBundle\Entity\Feature $features)
{
$this->features[] = $features;
echo 'Add "'.$features.'" - Total '.count($this->features).'<br />';
return $this;
}
/**
* Remove features
*
* #param \Mv\MainBundle\Entity\Feature $features
*/
public function removeFeature(\Mv\MainBundle\Entity\Feature $features)
{
$this->features->removeElement($features);
}
/**
* Get features
*
* #return Doctrine\Common\Collections\Collection
*/
public function getFeatures()
{
return $this->features;
}
public function __construct()
{
$this->features = new \Doctrine\Common\Collections\ArrayCollection();
}
The Feature Entity :
namespace Mv\MainBundle\Entity;
…
/**
* #ORM\Entity
* #ORM\Table(name="feature")
* #ORM\HasLifecycleCallbacks
*/
class Feature
{
use KrToolsTraits\PictureTrait;
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="label", type="string", length=255)
* #Assert\NotBlank()
*/
protected $label;
/**
* #ORM\ManyToOne(targetEntity="\Mv\MainBundle\Entity\FeatureCategory", inversedBy="features", cascade={"persist"})
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set label
*
* #param string $label
* #return Feature
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Get label
*
* #return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Set category
*
* #param Mv\MainBundle\Entity\FeatureCategory $category
* #return Feature
*/
public function setCategory(\Mv\MainBundle\Entity\FeatureCategory $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return Mv\MainBundle\Entity\FeatureCategory
*/
public function getCategory()
{
return $this->category;
}
}
The FeatureCategory entity :
namespace Mv\MainBundle\Entity;
...
/**
* #ORM\Entity
* #ORM\Table(name="feature_category")
*/
class FeatureCategory
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="code", type="string", length=255)
* #Assert\NotBlank()
*/
protected $code;
/**
* #ORM\Column(name="label", type="string", length=255)
* #Assert\NotBlank()
*/
protected $label;
/**
* #ORM\OneToMany(targetEntity="\Mv\MainBundle\Entity\Feature", mappedBy="category", cascade={"persist", "remove"}, orphanRemoval=true)
* #Assert\Valid()
*/
private $features;
public function __construct()
{
$this->features = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set code
*
* #param string $code
* #return Feature
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set label
*
* #param string $label
* #return Feature
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Get label
*
* #return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Add features
*
* #param \Mv\MainBundle\Entity\Feature $features
*/
public function addFeatures(\Mv\MainBundle\Entity\Feature $features){
$features->setCategory($this);
$this->features[] = $features;
}
/**
* Get features
*
* #return Doctrine\Common\Collections\Collection
*/
public function getFeatures()
{
return $this->features;
}
/*
* Set features
*/
public function setFeatures(\Doctrine\Common\Collections\Collection $features)
{
foreach ($features as $feature)
{
$feature->setCategory($this);
}
$this->features = $features;
}
/**
* Remove features
*
* #param Mv\MainBundle\Entity\Feature $features
*/
public function removeFeature(\Mv\MainBundle\Entity\Feature $features)
{
$this->features->removeElement($features);
}
/**
* Add features
*
* #param Mv\MainBundle\Entity\Feature $features
* #return FeatureCategory
*/
public function addFeature(\Mv\MainBundle\Entity\Feature $features)
{
$features->setCategory($this);
$this->features[] = $features;
}
}
Feature table is already populated, and users won't be able to add features but only to select them in a form collection to link them to the Place.
(The Feature entity is for the moment only linked to Places but will be later related to others entities from my application, and will contain all the features available for all entities)
In the Place form I need to display checkboxes of the features available for a Place, but I need to display them grouped by category.
Example :
Visits (FeatureCategory - code VIS) :
Free (Feature)
Paying (Feature)
Languages spoken (FeatureCategory - code LAN) :
English (Feature)
French (Feature)
Spanish (Feature)
My idea
Use virtual forms in my PlaceType form, like this :
$builder
->add('name')
->add('visit', new FeatureType('VIS'), array(
'data_class' => 'Mv\PlaceBundle\Entity\Place'
))
->add('language', new FeatureType('LAN'), array(
'data_class' => 'Mv\PlaceBundle\Entity\Place'
));
And create a FeatureType virtual form, like this :
class FeatureType extends AbstractType
{
protected $codeCat;
public function __construct($codeCat)
{
$this->codeCat = $codeCat;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('features', 'entity', array(
'class' => 'MvMainBundle:Feature',
'query_builder' => function(EntityRepository $er)
{
return $er->createQueryBuilder('f')
->leftJoin('f.category', 'c')
->andWhere('c.code = :codeCat')
->setParameter('codeCat', $this->codeCat)
->orderBy('f.position', 'ASC');
},
'expanded' => true,
'multiple' => true
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'virtual' => true
));
}
public function getName()
{
return 'features';
}
}
With this solution I get what I want but the bind process doesn't persist all the features. Instead of grouping them, it only keeps me and persist the last group "language", and erases all the previouses features datas. To see it in action, if I check the 5 checkboxes, it gets well into the Place->addFeature() function 5 times, but the length of the features arrayCollection is successively : 1, 2, 1, 2, 3.
Any idea on how to do it another way ? If I need to change the model I'm still able to do it.
What is the best way, reusable on my future other entities also related to Feature, to handle this ?
Thank you guys.
I think your original need is only about templating.
So you should not tweak the form and entity persistence logic to get the desired autogenerated form.
You should go back to a basic form
$builder
->add('name')
->add('features', 'entity', array(
'class' => 'MvMainBundle:Feature',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('f')
//order by category.xxx, f.position
},
'expanded' => true,
'multiple' => true
));
And tweak your form.html.twig
I am stuck and frustrated with the bellow error message:
Catchable Fatal Error: Argument 1 passed to Medicine\UserBundle\Entity\User
::setUsertype() must be an instance of Medicine\UserBundle\Entity\Usertype,
instance of Doctrine\Common\Collections\ArrayCollection given, called in
/opt/lampp/htdocs/drugs/vendor/symfony/src/Symfony/Component/Form/Util
/PropertyPath.php on line 347 and defined in /opt/lampp/htdocs/drugs/src/
Medicine/UserBundle/Entity/User.php line 224
What I think this error is due to use of manytoone field in my entity, I even tried with keeping onetomany in another entity.
I have a user entity and a usertype entity, the usertype_id is a manytoone field in user table. here is the code for both the entities:-
User
namespace Medicine\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="Medicine\UserBundle\Repository\UserRepository")
* #ORM\Table(name="user")
* #ORM\HasLifecycleCallbacks()
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\HasLifecycleCallbacks()
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $username;
/**
* #ORM\ManyToOne(targetEntity="Usertype", inversedBy="users")
* #ORM\JoinColumn(name="usertype_id", referencedColumnName="id")
*/
protected $usertype;
/**
* #ORM\Column(type="string")
*/
protected $image;
/**
* Set usertype
*
* #param Medicine\UserBundle\Entity\Usertype $usertype
*/
public function setUsertype(\Medicine\UserBundle\Entity\Usertype $usertype)
{
$this->usertype = $usertype;
}
/**
* Get usertype
*
* #return Medicine\UserBundle\Entity\Usertype
*/
public function getUsertype()
{
return $this->usertype;
}
}
I am just showing the concerned code, i have all the getter and setter methods for the above code.
UserType
namespace Medicine\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="Medicine\UserBundle\Repository\UsertypeRepository")
* #ORM\Table(name="usertype")
* #ORM\HasLifecycleCallbacks()
*/
class Usertype
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\HasLifecycleCallbacks()
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="User", mappedBy="usertype")
*/
protected $users;
public function __construct()
{
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add users
*
* #param Medicine\UserBundle\Entity\User $users
*/
public function addUser(\Medicine\UserBundle\Entity\User $users)
{
$this->users[] = $users;
}
/**
* Get users
*
* #return Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
Controller
This Executes when a user wants to login. He will fill in the username password and a UserType:
public function indexAction()
{
$entity = new User();
$form = $this->createForm(new LoginForm(), $entity);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
echo "<pre>"; print_r($entity->getUsertype()); exit;
$em = $this->getDoctrine()
->getEntityManager();
$em->persist($entity);
$userrepository = $em->getRepository('MedicineUserBundle:User');
echo "<pre>"; print_r($entity->getUsertype()); exit;
$all = $userrepository->findOneBy(array('login' => $entity->getLogin(), 'password' => $entity->getPassword()));
if($all)
{
return $this->redirect($this->generateUrl('MedicineUserBundle_login'));
}
}
}
return $this->render('MedicineUserBundle:User:loginpage.html.twig',array(
'form' => $form->createView()
));
}
Login Form
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('login', 'text', array('label' => 'Username',))
->add('password','password')
->add('usertype', 'entity', array('class' => 'MedicineUserBundle:Usertype', 'property'=>'name', 'multiple' => true, ))
;
}
The 'multiple' => true in combination with your entity association definition is causing this problem.
You should find that if you change multiple to false (and as such can only select one UserType for your User), things work properly.
If you want multiple UserTypes for one User, you have a Many-to-Many association - one user can have many UserTypes, and one UserType can have many Users. See Doctrine's ManyToMany association type to implement this. Documentation Here.
Hope this helps.