Unclear Symfony form error "This value is already used" - forms

I use Symfony 2.7.3 and I have following form ("app_cargo_source"):
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('country', 'choice', [
'choices' => $this->worldManager->getCountriesByRegionIds([1, 2]),
'choice_label' => 'name',
'choice_value' => 'id',
'label' => false,
// *this line is important* see docs for choice type
'choices_as_values' => true
])
// ...
;
// ...
}
The form is used in another form (app_cargo):
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('source', 'app_cargo_source')
// ...
;
// ...
}
“choices” field in first form is an array of WorldCountry objects, which are selected from database by regions id. Here is a picture of the array from Profiler:
WorldCountry and WorldRegion have unidirectional ManyToOne relationship.
The problem is, when I select country in country field and submit the form, back I receive following error for country field:
Why that happens, and why Symfony at all try assign a value to region?
P.S. Please let me know if more information is needed.

Right! It seems that problem was in uniqueness of region field in my WorldCountry entity. My WorldRegion entity is following:
/**
* WorldRegion
*
* #ORM\Table(name="world_region")
* #ORM\Entity(repositoryClass="AppBundle\Repository\WorldRegionRepository")
*
* #UniqueEntity(fields={"code"}, message="Region code must be unique")
*/
class WorldRegion
{
/**
* #var integer
*
* #ORM\Column(name="region_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #Assert\NotBlank()
*
* #ORM\Column(name="region_code", type="string", length=5,
* unique = true, nullable=false)
*/
protected $code;
// ...
}
And WorldCountry:
/**
* WorldCountry
*
* #ORM\Table(name="world_country")
* #ORM\Entity(repositoryClass="AppBundle\Repository\WorldCountryRepository")
*
* #UniqueEntity(fields={"iso2"})
* #UniqueEntity(fields={"iso3"})
* #UniqueEntity(fields={"region"}) // This line should be removed!
*/
class WorldCountry
{
/**
* #var integer
*
* #ORM\Column(name="country_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var WorldRegion
*
* #ORM\ManyToOne(targetEntity="WorldRegion",
* cascade={"all"}
* )
* #ORM\JoinColumn(name="region_id", referencedColumnName="region_id")
*/
protected $region;
// ...
}
As seen WorldCountry has unique constraint on region field. In this case it is logical error. Because ManyToOne states that in database table for WorldCountry, countries are unique, but regions - not. But I, using #UniqueEntity, claim that regions also should be unique. So, annotation #UniqueEntity(fields={"region"}) should be removed from WorldCountry entity.
P.S. Please let me know if I can improve my answer.

Related

Symfony2 using entities in form builder only works if multiple is set to true

I've likely asked a question like this before but I don't think it was answered fully. This is really bugging me because I honestly cannot understand why this is a problem.
I have two entities, one called Containers.php and one called ContainerType.php - a user can add a Container and select a Type from a drop down (which is generated using the Entity in the form builder). This works, and is saved correctly in the join table. But, if the user goes on to try and edit this later, the drop down is reset (i.e. it cannot find the existing type) and if another type is chosen from the edit form it just adds it into the join table rather than updating so you get two associations.
Here is the mapping for Containers and ContainerType:
/**
* Containers
*
* #ORM\Table(name="containers")
* #ORM\Entity
*/
class Containers
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="number", type="string", length=255)
*/
private $number;
/**
* #ORM\ManyToMany(targetEntity="ContainerType")
*
* #ORM\JoinColumn(name="id", referencedColumnName="container")
*/
protected $type;
public function __construct()
{
$this->type = new ArrayCollection();
}
And my setters and getters for Type:
/**
* Add type
*
* #param \AppBundle\Entity\ContainerType $type
*
* #return Containers
*/
public function addType(ContainerType $type)
{
$this->type[] = $type;
return $this;
}
/**
* Set type
*
* #param ArrayCollection $type
*
* #return Containers
*/
public function setType($type)
{
$this->type[] = $type;
return $this;
}
/**
* Get type
*
* #return ContainerType
*/
public function getType()
{
return $this->type;
}
Here is the mapping in ContainerType.php:
/**
* ContainerType
*
* #ORM\Table(name="container_type")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
*/
class ContainerType
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=255)
*/
private $type;
/**
* #param \AppBundle\Entity\Containers
*
* ORM\#ManyToMany(targetEntity="Containers", mappedBy="type")
*/
protected $container;
My form type for adding / editing containers is as follows:
$builder->add('number' , 'text', array('label' => 'Container Number'));
$builder->add('type' , 'entity',
array(
'class' => 'AppBundle:ContainerType',
'label' => 'Container Type',
'choice_label' => 'type',
'empty_value' => '-- Please Select --',
'multiple' => false
));
$builder->add('save', 'submit', array(
'attr' => array(
'class' => 'btn btn-material-blue-800 btn-raised',
'value' => 'Save'
),
));
As you can see, multiple is set to FALSE which is what I want - I only want to display a drop down with options as only one type can be assigned to a container. If anyone can help me with my mappings (if they are incorrect, though when I run doctrine:schema:validate it seems they are fine) then I would be grateful.
Otherwise, I do not understand why it only works / saves correctly on Edit when I set multiple to true. Surely this is not the only way to do it?
Thanks in advance
Michael
You need to implement this not as a many-to-many relationship but as a many-to-one relationship. See these docs for more info:
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/association-mapping.html
http://symfony.com/doc/current/book/doctrine.html

symfony form entity update

I'm trying to create a for with an entity.
My controller:
$questionnaire = $em->getRepository('questionnaireBundle:questionnaire')->findOneBy(array('id' => $id));
$form = $this->createForm(new questionnaireType(), $questionnaire);
QuestionnaireType:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('nom', 'text', array('label' => 'Nom:'));
$builder->add('nbreQuestions', 'text', array('label' => 'Nombre de questions:'));
$builder->add('type', 'entity', array('class' => 'questionnaireBundle:type', 'property' => 'type'));
$builder->add('envoyer', 'submit', array('label' => 'Enregistrer', 'attr' => array('class' => 'btn btn-success col-md-12')));
}
The entity: questionnaire
namespace questionnaireBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* questionnaire
*
* #ORM\Table()
* #ORM\Entity
*/
class questionnaire {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=255)
*/
private $nom;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=255)
*/
private $type;
/**
* #var integer
*
* #ORM\Column(name="nbreQuestions", type="integer")
*
* #Assert\NotBlank(message="Veuillez entrer un nombre de questions.")
* #Assert\Type(type="integer")
*/
private $nbreQuestions;
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set nom
*
* #param string $nom
* #return questionnaire
*/
public function setNom($nom) {
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom() {
return $this->nom;
}
/**
* Set type
*
* #param string $type
* #return type
*/
public function setType($type) {
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType() {
return $this->type;
}
/**
* Set nbreQuestions
*
* #param integer $nbreQuestions
* #return questionnaire
*/
public function setNbreQuestions($nbreQuestions) {
$this->nbreQuestions = $nbreQuestions;
return $this;
}
/**
* Get nbreQuestions
*
* #return integer
*/
public function getNbreQuestions() {
return $this->nbreQuestions;
}
public function __toString() {
return (string) $this->getNom();
}
}
The field nom, nbreQuestions will automatically be fully with the entity questionnaire, but type is not update!
Anybody knows why?
Thanks
Best regards
that must do a second query behind the sense, but you can increase performance by dql & join:
use this code:
$questionnaire = $em->createQuery('select q from questionnaireBundle:questionnaire q join q.type t where q.id = :id')->setParameter('id', $id)->getSingleResult();
$form = $this->createForm(new questionnaireType(), $questionnaire);
The reason of not selecting the proper type in your for is that entity type builds choices as
entity_id => property_value
So it is comparing your values from questionnaire type to the ids from your type entity and it will not find a match. Moreover if you update your questionnaire object the type will be changed to the id of type entity.
I see here two solutions:
proposed by #ghanbari to make relation from questionnaire to type
make your form as a service and inject entityManager than build your choices like you want (type => type) and change the field from entity type to choice type

Entity field form Symfony2

My goal is to display a social networks form in users dashboard like :
- Facebook : <input>
- Twitter : <input>
- Linkedin : <input>
Social networks are dynamic (manage by administration panel).
I've got currently 3 Entities (Social, UserSocial and User (FOS...)).
In User entity, I just added it :
/**
*#ORM\OneToMany(targetEntity="Application\SocialBundle\Entity\UserSocial", mappedBy="user")
*/
private $userSocials;
My Social entity :
class Social
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $name;
/**
* #var string
*/
private $class;
...
}
My UserSocial entity :
class UserSocial
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*#ORM\ManyToOne(targetEntity="Admin\UserBundle\Entity\User", inversedBy="userSocials")
*/
private $user;
/**
*#ORM\ManyToMany(targetEntity="Admin\SocialBundle\Entity\Social", inversedBy="userSocials")
*/
private $social;
/**
* #var string
*
* #ORM\Column(name="value", type="string", length=255)
*/
// Not really sure about it
private $value;
....
And finally, the UserSocialType, this is where i'm stuck :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('social', 'entity', array(
'class' => 'Admin\SocialBundle\Entity\Social',
'property' => 'name',
'required' => false,
))
->add('value')
;
}
It gave me just a select with all social name in DB and a value input. I would like a value input for each social entity in DB.
Thank you in advance for your help.
May be you do it a little different?
Craete a SocialType:
$builder
->add('social', 'text', array(
'data' => $existingSocial
))
...
;
UserSocialType:
$builder
->add('social', new SocialType(), array(
// pass social to the Social type
...
))
...
;
PS// These are just my general thoughts, here are some wrong lines my snippet, you should not pass an object to the text field, but you can use data transformers to get an object from the text value.. Also I think your UserSocial entity unproperly configured, $social field should receive manyToOne relationship

Symfony 2.1 : How to set default value based on my user in drop down list

I want to create a form with a drop-down list and text field.
My drop-down list contains values of my Agency Entity and my text field a week number.
I want to set default value based on my connected user but I don't know how.
I have modified my entity, my form and my controller:
I have an Entity Week with my Agency relation :
class Week
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="Agency", inversedBy="week", cascade={"persist"})
* #ORM\JoinColumn(name="agency_id", referencedColumnName="id")
*/
private $agency;
/**
* #var integer
*
* #ORM\Column(name="week_number", type="integer")
*/
private $week_number;
/**
* #var \DateTime
*
* #ORM\Column(name="week_start", type="datetime")
*/
private $week_start;
/**
* #var \DateTime
*
* #ORM\Column(name="week_end", type="datetime")
*/
private $week_end;
public function getAgency()
{
return $this->agency;
}
.... public function get.....
}
Then my Agency Entity :
class Agency
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=50)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="nb_team", type="integer")
*/
private $nb_team;
/**
* #var \DateTime
*
* #ORM\Column(name="date_creation", type="datetime")
*/
private $date_creation;
/**
*
* #ORM\OneToMany(targetEntity="Week", mappedBy="agency", cascade={"persist"})
*/
private $week;
public function .....
}
My Form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('agency', 'entity', array(
'class' => 'MyProjectBundle:Agency',
'property' => 'name',
/* 'query_builder' => function(\Doctrine\ORM\EntityRepository $er) {
return $er->createQueryBuilder('a')->orderBy('a.name', 'ASC');
},*/
'attr' => array('onchange' => 'javascript:this.form.submit();')
))->add('week_number', 'text');
}
And my Controller :
$num_week = 4;
$id = 3;
$agency_id = $em->getRepository('MyProjectBundle:Agency')->find($id);
$week = $em->getRepository('MyProjectBundle:Week')->WeekExiste($num_week, $week_start, $agency_id);
$form2 = $this->createForm(new FormType(), $week);
if ($request->isMethod('POST')) {
$form2->bind($request);
$data = $form2->getData();
$agency = $data['agency'];
}
else {
$agency = $em->getRepository('MyProjectBundle:Agency')->find($id);
}
$week return a correct Entity.
My form works for the week_number field but my drop down list doesn't select my agency I set in my controller.
I had the same problem with the default option value, you can check it on my question.
I've shared a full code.
symfony2 selected option

Many to many on Forms with entities having composite primary key on Symfony2

I´m trying to create a form to manage relations on 2 entities related on a many-to-many way.
These entities are PHONE and GROUP.
Both entities have a composite primary key, ID and USER for GROUP entity and PHONE and USER for PHONE entity, being:
ID: Numeric autoincremental unique
PHONE: Numeric
USER: User ID, linked to another entity not shown.
I'm using composite keys to cluster my indexes on the DB server.
My 2 entities are defined as shown:
Phone entity
class Phone
{
/**
* #var integer $phoneNo
*
* #ORM\Column(name="phone_no", type="bigint", nullable=false)
* #ORM\Id
*
*/
private $phoneNo;
/**
* #var Group
*
* #ORM\ManyToMany(targetEntity="Group", inversedBy="phone")
* #ORM\JoinTable(name="phone_has_group",
* joinColumns={
* #ORM\JoinColumn(name="user", referencedColumnName="user"),
* #ORM\JoinColumn(name="phone_no", referencedColumnName="phone_no")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="group_contact", referencedColumnName="id")
* }
* )
*/
private $group;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user", referencedColumnName="id")
* })
* #ORM\Id
*/
private $user;
// more properties, getters and setters...
}
Group entity
class Group
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=45, nullable=false)
*/
private $name;
/**
* #var Phone
*
* #ORM\ManyToMany(targetEntity="Phone", mappedBy="group")
*/
private $phone;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user", referencedColumnName="id")
* })
* #ORM\Id
*/
private $user;
// more properties, getters and setters...
}
The relationships on this entities are working just fine. The problem arises when I try to create a Form to manage the relationships between this 2 entities.
My code:
class GroupType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name', 'text',
array('label' => 'Nombre'))
->add('phone', 'entity',
array(
'label' => 'Contactos en este grupo',
'class' => 'SMSBundle:Phone',
'expanded' => false,
'required' => false,
'multiple' => true,
))
;
}
Generates this:
<select id="e_keyword_phone" name="e_keyword[phone][]" multiple="multiple">
<option value="0">4490000000</option>
<option value="1">4490000001</option>
<option value="2">4490000002</option>
<option value="3">4490000003</option>
<option value="4">4490000004</option>
<option value="5">4490000005</option>
</select>
Normally, value attribute on each option tag represents the ID of the entity being chosen... but I'm not using a single-column ID but a 2 column composite key!!!
Here, an arbitrary incremental number is being generated, causing the selected values not being linked to the proper entities, and not being persisted on the database.
How could I make this work without getting rid of my composite keys?
This question has been asked long time ago, I'm newbie in this subject but I'm pretty sure you have to create one extra Entity class and follow on case already described in Doctrine 2 and Many-to-many link table with an extra field