Symfony2 form collection field not showing up - php

I'll explain what I'm trying to do.
I have the following entities, Dealers Brands and Types.
1 Dealer can have many brands associated and each relation will have one type associated as well, that's why is a manyToMany relationship with an intermediate table.
I want to create a Form to Add dealers to our system and when doing so they can choose which brands are associated (there are few brands so we want to display them as checkboxes) and of what type, but trying to show this form with the brands is been tricky until now.
Brand Entity
/**
* Brand
*
* #ORM\Table()
* #ORM\Entity
*/
class Brand
{
/**
* #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=255)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="TypeBrand")
* #ORM\JoinTable(name="brand_type",
* joinColumns={#ORM\JoinColumn(name="brand_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="type_id", referencedColumnName="id")}
* )
*/
private $type;
/**
* #ORM\OneToMany(targetEntity="DealerBrand", mappedBy="brand")
*/
private $dealerBrand;
public function __construct()
{
$this->type = new ArrayCollection();
$this->dealerBrand = new ArrayCollection();
}
public function __toString()
{
return $this->getName();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Brand
*/
public function setName($name)
{
$this->name = $name;
$this->setSlug($name);
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function addType(TypeBrand $type)
{
$this->type[] = $type;
}
public function getType()
{
return $this->type;
}
public function addDealerBrand($dealerBrand)
{
$this->dealerBrand[] = $dealerBrand;
}
public function getDealerBrand()
{
return $this->dealerBrand;
}
}
Dealer Entity
/**
* Dealer
*
* #ORM\Table("dealer")
* #ORM\Entity(repositoryClass="Project\DealersBundle\Entity\Repository\DealerRepository")
* #Gedmo\Loggable
*/
class Dealer
{
/**
* #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=255, unique=true)
* #Assert\NotBlank()
* #Assert\Length(min = "10")
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="DealerBrand", mappedBy="dealer")
*
*/
private $dealerBrand;
public function __construct()
{
$this->dealerBrand = new ArrayCollection();
}
public function __toString()
{
return $this->getName();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Dealer
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function addDealerBrand($dealerBrand)
{
$this->dealerBrand[] = $dealerBrand;
}
public function getDealerBrand()
{
return $this->dealerBrand;
}
}
DealerBrand Entity
/**
* DealerBrand
*
* #ORM\Table("dealer_brand")
* #ORM\Entity
*/
class DealerBrand
{
/**
* #var integer
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Dealer", inversedBy="dealerBrand")
*/
private $dealer;
/**
* #var integer
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Brand", inversedBy="dealerBrand")
*/
private $brand;
/**
* Set dealer
*
* #param integer $dealer
* #return DealerBrand
*/
public function setDealer($dealer)
{
$this->dealer = $dealer;
return $this;
}
/**
* Get dealer
*
* #return integer
*/
public function getDealer()
{
return $this->dealer;
}
/**
* Set brand
*
* #param integer $brand
* #return DealerBrand
*/
public function setBrand($brand)
{
$this->brand = $brand;
return $this;
}
/**
* Get brand
*
* #return integer
*/
public function getBrand()
{
return $this->brand;
}
}
Now this are my formtypes
DealerBrandType
class DealerBrandType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('brand', 'entity', array(
'class' => 'Project\DealersBundle\Entity\Brand',
'property' => 'name',
'multiple' => true,
'expanded' => true,
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Project\DealersBundle\Entity\DealerBrand'
)
);
}
public function getName()
{
return 'DealerBrand';
}
}
DealerType
class DealerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('dealerBrand', 'collection', array(
'type' => new DealerBrandType(),
'allow_add' => true,
'allow_delete' => true,
))
->add('Save', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Project\DealersBundle\Entity\Dealer'
)
);
}
public function getName()
{
return 'dealerType';
}
}
And this is my controller
public function addAction()
{
$dealer = new Dealer();
$form = $this->createForm(new DealerType(), $dealer);
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
$this->getDoctrine()->getManager()->persist($dealer);
$this->getDoctrine()->getManager()->flush();
return $this->redirect($this->generateUrl('dealers_list'));
}
return $this->render(
'ProjectDealersBundle:Dealers:AddDealer.html.twig',
array(
'form' => $form->createView()
)
);
}
If this is not the correct approach please tell me, tell me also if you see bad code, that way I can improve
* EDIT *
This is the result i need
http://tinypic.com/r/24pkzdc/8
You can see there the brands and so .. so the idea is that when saving the Dealer you also save the association with the brands
* END EDIT *
Thank you!

I'm not sure this is the best answer ever but you can achieve it by making a custom query in your form :
->add('contact', 'entity', array(
'class' => 'AcmeBundle:Entity'
'query_builder' => function ( \acme\bundle\Entity\entityRepository $c){
$qb = $c->createQueryBuilder('a');
return $qb->orderBy('a.nom', 'ASC')
->join('a.categories', 'c')
->where( $qb->expr()->in ( 'c.id', ':listCategories') )
->setParameter( 'listCategories', array (
7,
));
},
'attr' => array( 'class' => 'other')
))
;
}
by using an 'entity' field type, i can inject custom query with the option 'query_builder' ( for more information : http://symfony.com/doc/current/reference/forms/types/entity.html )
then, inside i declare an anonymous function ( http://php.net/manual/en/functions.anonymous.php ) to create my custom query with the createQueryBuilder.
With the createQueryBuilder , you create your custom query ( here i had almost like you a many to many relationship and i wanted to get only some of them with a filtering array ( the set parameter ) .
here is the doc for custom query : http://symfony.com/doc/current/book/doctrine.html
the results of the query, if not null , will be displayed in your form
/** ALTERNATIVE ANSWER **/
if you want to display your dealers AND brands with a tree in your select then your have to :
1) make a query to return an object container your dealers and brands
2) make an array with depth that the select will display as a tree :
here is an example to illustrate :
->add('contact', 'entity', array(
'class' => 'AcmeBundle:Entity'
'query_builder' => function ( \acme\bundle\Entity\entityRepository $c){
$dealers = $c->yourFunctionThatReturnesDealers('d');
$dealersGroupedByBrands = array();
foreach ( $dealers as $dealer) {
foreach ($dealers->getBrands() as $brand) {
$dealersGroupedByBrands[$brand->getName()][] = $dealer;
}
return $dealersGroupedByBrands;
},
'attr' => array( 'class' => 'other')
))
;
}
pretty cool , no ?

Related

Symfony form choice default value from entity

I having some troubles with symfony forms.
I have a boolean variable in my entity. I cant find a way to set that value in my form when i'm editing it.
Entity
namespace AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="pages")
*/
class Page
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="text")
*/
protected $slug;
/**
* #ORM\Column(type="text")
*/
protected $title;
/**
* #ORM\Column(type="text")
*/
protected $content;
/**
* #ORM\Column(name="creation_date", type="datetime")
*/
protected $creationDate;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
protected $isActive = true;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set slug
*
* #param string $slug
*
* #return Page
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set title
*
* #param string $title
*
* #return Page
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set content
*
* #param string $content
*
* #return Page
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set creationDate
*
* #param \DateTime $creationDate
*
* #return Page
*/
public function setCreationDate($creationDate)
{
$this->creationDate = $creationDate;
return $this;
}
/**
* Get creationDate
*
* #return \DateTime
*/
public function getCreationDate()
{
return $this->creationDate;
}
/**
* Set isActive
*
* #param boolean $isActive
*
* #return Page
*/
public function setIsActive($isActive)
{
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return boolean
*/
public function getIsActive()
{
return $this->isActive;
}
}
Controller function
public function editAction(Request $request, $pageId)
{
$em = $this->getDoctrine()->getManager();
$page = $em->getRepository('AdminBundle:Page')->find($pageId);
$form = $this->createForm('app_page', $page);
$form->handleRequest($request);
if($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($page);
$em->flush();
return $this->redirectToRoute('admin_pages');
}
return $this->render('AdminBundle::editPage.html.twig', array('page' => $page, 'form' => $form->createView()));
}
PageFormType
namespace AdminBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class PageFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title', 'text');
$builder->add('slug', 'text');
$builder->add('isActive', 'choice', array('choices' => array(
'true' => 'Active',
'false' => 'Inactive'
)));
$builder->add('content', 'textarea', array('required' => false));
}
public function getName()
{
return 'app_page';
}
}
As you can see i wrote my self in FormType class what choices it has. And now it is always displaying "Active" instead of displaying Entity's value. How should i do that?
Thanks!
Try to change your isActive in the Entity like
protected $isActive ;
and if you want to make a default true you can make it at the construct like :
public function __construct() {
$this->setIsActive = true ;
}
$builder->add('isActive', ChoiceType::class, [
'choices' => [
'Active' => true,
'Inactive' => false
],
'choices_as_values' => true,
'multiple' => true,
'expanded' => true,
'data' => array(true)
]);
A 2021 Solution: setting form choice default value (data) from entity
Sometimes your choice field values exist in another entity table, which means you cannot populate them using default form data_class. You only get the string value that saved in the form entity, resulting to error: ...must be an object or null, string given...
protected EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
// In your form
->add('membershipType', EntityType::class, [
'class' => MembershipType::class,
'label' => 'Enter membership type here',
'data' => $this->em->getRepository(MembershipType::class)->findOneBy([
'name' => $your_value_here
])
])

symfony2 embedded form collection and entity mapping

I was following the symfony2 tutorial on how to create an embedded form collection but wasn't able to implement it since it only creates a junction table.
According to doctrine2 documentation:
"Why are many-to-many associations less common? Because frequently you want to associate additional attributes with an association, in which case you introduce an association class. Consequently, the direct many-to-many association disappears and is replaced by one-to-many/many-to-one associations between the 3 participating classes."
Here are some snippets of my code:
src/AppBundle/Entity/Ingredient.php
/**
* Defines the properties of the Ingredient entity to represent the portal ingredients.
*
* #author furious_snail
*
* #ORM\Entity()
* #ORM\Table(name="ingredients")
* #UniqueEntity("name")
*/
class Ingredient
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="IngredientCategory")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
*/
private $category;
/**
* #ORM\Column(type="string", unique=true)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="IngredientNutrient", mappedBy="ingredient", cascade={"persist", "remove"})
*/
private $nutrientsPer100G;
public function __construct()
{
$this->substitute = new ArrayCollection();
$this->nutrientsPer100G = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
/**
* #param mixed $nutrientsPer100G
*/
public function setNutrientsPer100G($nutrientsPer100G)
{
$this->nutrientsPer100G = $nutrientsPer100G;
}
/**
* #return array
*/
public function getNutrientsPer100G()
{
return $this->nutrientsPer100G;
}
}
src/AppBundle/Entity/IngredientNutrient.php
/**
* #ORM\Entity()
* #ORM\Table(name="ingredient_nutrient")
*/
class IngredientNutrient
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Ingredient", inversedBy="nutrientsPer100G")
* #ORM\JoinColumn(name="ingredient_id", referencedColumnName="id", nullable=true)
*/
protected $ingredient;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Nutrient")
* #ORM\JoinColumn(name="nutrient_id", referencedColumnName="id", nullable=true)
*/
protected $nutrient;
/**
* #ORM\Column(type="float")
*/
private $quantity;
/**
* #ORM\ManyToOne(targetEntity="Unit")
* #ORM\JoinColumn(name="unit_id", referencedColumnName="id", nullable=true)
*/
private $unit;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getIngredient()
{
return $this->ingredient;
}
/**
* #param mixed $ingredient
*/
public function setIngredient($ingredient)
{
$this->ingredient = $ingredient;
}
/**
* #return mixed
*/
public function getNutrient()
{
return $this->nutrient;
}
/**
* #param mixed $nutrient
*/
public function setNutrient($nutrient)
{
$this->nutrient = $nutrient;
}
/**
* #return mixed
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* #param mixed $quantity
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
}
/**
* #return mixed
*/
public function getUnit()
{
return $this->unit;
}
/**
* #param mixed $unit
*/
public function setUnit($unit)
{
$this->unit = $unit;
}
}
src/AppBundle/Form/Type/IngredientNutrientType.php
class IngredientNutrientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nutrient', 'entity', array(
'class' => 'AppBundle\Entity\Nutrient',
'choice_label' => 'name',
'label' => 'Nutrient',
))
->add('quantity', null, array('label' => 'Cantitate'))
->add('unit', 'entity', array(
'class' => 'AppBundle\Entity\Unit',
'choice_label' => 'unit',
'label' => 'Unitate de masura'
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\IngredientNutrient',
));
}
public function getName()
{
return 'app_ingredient_nutrient';
}
}
src/AppBundle/Form/Type/IngredientType.php
class IngredientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', null, array('label' => 'Name'))
->add('nutrients_per_100_g', 'collection', array(
'type' => new IngredientNutrientType(),
'allow_add' => true,
'label' => 'Nutrient quantity per 100g',
'options' => array('label' => false),
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Ingredient',
));
}
public function getName()
{
return 'app_ingredient';
}
}
This works, I do get an embedded form collection but the issue is that the ingredient_id in the ingredient_nutrient table is null. How do I make it to fill the table with the right ID?
These are the fields I get on the page:
Name:
Nutrient:
Quantity:
Unit:
The idea is that if I have IngredientNutrient form tied with Ingredient form the user shouldn't have to specify ingredient name twice.
Thank you.
To start with, you need to "cross reference" your entities:
public function setNutrientsPer100G($nutrientsPer100G)
{
$this->nutrientsPer100G = $nutrientsPer100G;
$nutrientsPer100G->setIngrediant($this);
}
Make sure both sides of the relation are being set. That will take care of the null id issues.
The other problem is that you are using collections in your Ingrediant/Nutrient entities but your set methods are not using the array operators.

Symfony2 error on submitting form with a collection of forms - "Warning: spl_object_hash() expects parameter 1 to be object, array given"

I have an Employee class which has a OneToMany relation to the PhoneNumber class, and I'm using form builders, and using prototypes to embed multiple phone numbers into the New Employee form, with javascript.
From dumping my employee variable, I see that each submitted PhoneNumber is represented as an array, when I suppose it should be converted to a PhoneNumber object when the submitted data is processed.
My entitites are:
/**
* Employee
*
* #ORM\Table(uniqueConstraints={#UniqueConstraint(name="employee_username_idx", columns={"username"})})
* #ORM\Entity(repositoryClass="Acme\BambiBundle\Entity\EmployeeRepository")
*/
class Employee
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
*
* #OneToMany(targetEntity="PhoneNumber", mappedBy="employee", cascade={"persist","remove"}, fetch="EAGER")
**/
private $phoneNumbers;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Constructor
*/
public function __construct()
{
$this->phoneNumbers = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add phoneNumbers
*
* #param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
* #return Employee
*/
public function addPhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
{
$phoneNumbers->setEmployee($this);
$this->phoneNumbers[] = $phoneNumbers;
return $this;
}
/**
* Remove phoneNumbers
*
* #param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
*/
public function removePhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
{
$this->phoneNumbers->removeElement($phoneNumbers);
}
/**
* Get phoneNumbers
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPhoneNumbers()
{
return $this->phoneNumbers;
}
// ...
}
and
/**
* PhoneNumber
*
* #ORM\Table()
* #ORM\Entity
*/
class PhoneNumber
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="text", nullable=true)
*/
private $type;
/**
* #var string
*
* #ORM\Column(name="number", type="text")
*/
private $number;
/**
* #var Employee
*
* #ManyToOne(targetEntity="Employee", inversedBy="phoneNumbers")
* #JoinColumn(name="employee_id", referencedColumnName="id", onDelete="CASCADE")
**/
private $employee;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set number
*
* #param string $number
* #return PhoneNumber
*/
public function setNumber($number)
{
$this->number = $number;
return $this;
}
/**
* Get number
*
* #return string
*/
public function getNumber()
{
return $this->number;
}
/**
* Set employee
*
* #param \Acme\BambiBundle\Entity\Employee $employee
* #return PhoneNumber
*/
public function setEmployee(\Acme\BambiBundle\Entity\Employee $employee = null)
{
$this->employee = $employee;
return $this;
}
/**
* Get employee
*
* #return \Acme\BambiBundle\Entity\Employee
*/
public function getEmployee()
{
return $this->employee;
}
/**
* Set type
*
* #param string $type
* #return PhoneNumber
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType()
{
return $this->type;
}
}
My form types are:
class EmployeeType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('phoneNumbers', 'collection', array(
'type' => new PhoneNumberType(),
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype_name' => 'phoneNumberPrototype',
'by_reference' => false,
))
// ...
->add('save', 'submit', array('attr' => array('class' => 'btn btnBlue')));
}
public function getName() {
return 'employee';
}
}
and
class PhoneNumberType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('type', 'text', array('required' => false, 'label' => 'Type (optional)'))
->add('number', 'text');
}
public function getName() {
return 'phoneNumber';
}
}
Are there any things I could try to solve the problem? Is there anything that I am obviously doing wrong?
The solution was in a detail that I didn't know about - setting a data_class in the PhoneNumberType class:
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Acme\BambiBundle\Entity\PhoneNumber',
));
}
Without this, the code that processes the data from the submitted form does not know that each phone number should be converted to a PhoneNumber class, and thus they stay as arrays.
Please bear in mind that I am using Symfony 2.6. In Symfony 2.7 the above function is called configureOptions and has a slightly different definition:
public function configureOptions(OptionsResolver $resolver) {

Symfony2 relationship between two entities

I want to make a relationship between two entities but for some reason I am getting NULL on one of the values...
So in my skin entity I have an email_registration_id field with the relationship :
/**
* #ORM\ManyToOne(targetEntity="Project\UserBundle\Entity\Email")
* #ORM\JoinColumn(name="email_registration_id", referencedColumnName="id")
*/
protected $email_registration_id;
/**
* Set email_registration_id
*
* #param \Project\UserBundle\Entity\Email $email_registration_id
* #return Skin
*/
public function setEmailRegistrationId(\Project\UserBundle\Entity\Email $email_registration_id = null)
{
$this->email_registration_id = $email_registration_id;
return $this;
}
/**
* Get email_registration_id
*
* #return \Project\UserBundle\Entity\Email
*/
public function getEmailRegistrationId()
{
return $this->email_registration_id;
}
And this is the Email entity:
/**
* Project\UserBundle\Entity\Email
*
* #ORM\Entity
* #ORM\Table(name="email")
*/
class Email {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string")
*/
protected $title;
/**
* #var string $registration_content
*
* #ORM\Column(name="registration_content", type="string")
*/
protected $registration_content;
/**
* #var string $confirmation_apuestas
*
* #ORM\Column(name="confirmation_apuestas", type="string")
*/
protected $confirmation_apuestas;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setId() {
$this->id = null;
}
/**
* Set title
*
* #param string $title
* #return Email
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set registration_content
*
* #param string $registration_content
* #return Email
*/
public function setRegistrationContent($registration_content)
{
$this->registration_content = $registration_content;
return $this;
}
/**
* Get registration_content
*
* #return string
*/
public function getRegistrationContent()
{
return $this->registration_content;
}
/**
* Set $confirmation_apuestas
*
* #param string $confirmation_apuestas
* #return Email
*/
public function setConfirmationApuestas($confirmation_apuestas)
{
$this->confirmation_apuestas = $confirmation_apuestas;
return $this;
}
/**
* Get $confirmation_apuestas
*
*
#return string
*/
public function getConfirmationApuestas()
{
return $this->confirmation_apuestas;
}
}
Now in my cms i create a new email like this:
/**
* #Route("/new", name="cms_email_new")
* #Method({"GET"})
* #Template()
*/
public function newAction() {
$item = new Email();
$form = $this->createForm(new EmailType($this->container->getParameter("langs")), $item);
return array('form' => $form->createView(), 'item' => $item);
}
The form:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
$builder->add('registration_content', 'textarea', array('label' => 'cms.registration.content'));
$builder->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'));
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Project\UserBundle\Entity\Email',
);
}
This is how I persist the Email to the database:
/**
* #Route("/save", name="cms_email_save")
* #Template("ProjectUserBundle:EmailAdmin:new.html.twig")
* #Method({"POST"})
*/
public function saveAction(Request $request) {
$item = new Email();
$type = new EmailType($this->container->getParameter("langs"));
$form = $this->createForm($type, $item);
$form->bind($request);
$em = $this->getEntityManager();
if ($form->isValid()) {
$this->upload($form, $item);
$em->persist($item);
$em->flush();
return $this->redirect($this->generateUrl('cms_skin_email_list', array('skin_id' => $item->getId())));
}
return array('form' => $form->createView(), 'item' => $item);
}
The problem is that it creates an email, but in my skin entity, the email_registration_id is just NULL and not the same as emails Id... Maybe I missed something?
UPDATE
So this is what I made according to the responses I got:
class Email {
/**
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_registration_id")
*/
protected $skin;
/**
* Set skin
*
* #param string $skin
* #return Email
*/
public function setSkin(\Project\SkinBundle\Entity\Skin $skin = null)
{
$this->skin = $skin;
return $this;
}
/**
* Get skin
*
* #return string
*/
public function getSkin()
{
return $this->skin;
}
And the form:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
$builder->add('registration_content', 'textarea', array('label' => 'cms.registration.content'));
$builder->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'));
$builder->add('skin', 'entity', array(
'class' => 'ProjectSkinBundle:Skin',
'property' => 'id',
));
}
However when i am trying to flush to the database I get this error:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in C:\wamp\www\Company\front\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php on line 528 and defined in C:\wamp\www\Company\front\vendor\doctrine\collections\lib\Doctrine\Common\Collections\ArrayCollection.php line 48
It's normal that the creation of a new email is not associated to a skin object. How could it ? The relation is unidirectional, and only works when you create a skin and you give it an email. To create an email and give it a skin, you have to make the relation bidirectional, and add it to your email form.
To do this, I'd do the following :
/*
* Class Project\UserBundle\Entity\Email
*/
class Email {
...
/**
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_registration_id")
*/
protected $skin;
and in your form :
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'))
->add('registration_content', 'textarea', array('label' => 'cms.registration.content'))
->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'))
->add('skin')
;
}
And PS : You should not use the bind() method to handle the request, it is deprecated. Instead use :
$form->handleRequest($request);
UPDATE 1 : Don't forget to also update your ManyToOne annotation adding the inversedBy part :
#ORM\ManyToOne(targetEntity="Project\UserBundle\Entity\Email", inversedBy="skin")
And also, of course, update your database.

symfony2 Catchable Fatal Error: Object of class could not be converted to string

I have this Entity defined:
<?php
namespace Apw\BlackbullBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Categories
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Apw\BlackbullBundle\Entity\CategoriesRepository")
*/
class Categories
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="categories_image", type="string", length=64, nullable = true)
*/
private $categoriesImage;
/**
* #var integer
*
* #ORM\Column(name="parent_id", type="integer", nullable = true, options={"default":0})
*/
private $parentId;
/**
* #var integer
*
* #ORM\Column(name="sort_order", type="integer", nullable = true, options={"default":0})
*/
private $sortOrder;
/**
* #var \DateTime
*
* #ORM\Column(name="date_added", type="datetime", nullable = true)
*/
private $dateAdded;
/**
* #var \DateTime
*
* #ORM\Column(name="last_modified", type="datetime", nullable = true)
*/
private $lastModified;
/**
* #var boolean
*
* #ORM\Column(name="categories_status", type="boolean", nullable = true, options={"default" = 1})
*/
private $categoriesStatus;
/**
* #ORM\OneToMany(targetEntity="CategoriesDescription", mappedBy="category", cascade={"persist", "remove"})
*/
private $categoryDescription;
/**
* #ORM\ManyToMany(targetEntity="Products", mappedBy="categories")
**/
private $products;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set categoriesImage
*
* #param string $categoriesImage
* #return Categories
*/
public function setCategoriesImage($categoriesImage)
{
$this->categoriesImage = $categoriesImage;
return $this;
}
/**
* Get categoriesImage
*
* #return string
*/
public function getCategoriesImage()
{
return $this->categoriesImage;
}
/**
* Set parentId
*
* #param integer $parentId
* #return Categories
*/
public function setParentId($parentId)
{
$this->parentId = $parentId;
return $this;
}
/**
* Get parentId
*
* #return integer
*/
public function getParentId()
{
return $this->parentId;
}
/**
* Set sortOrder
*
* #param string $sortOrder
* #return Categories
*/
public function setSortOrder($sortOrder)
{
$this->sortOrder = $sortOrder;
return $this;
}
/**
* Get sortOrder
*
* #return string
*/
public function getSortOrder()
{
return $this->sortOrder;
}
/**
* Set dateAdded
*
* #param \DateTime $dateAdded
* #return Categories
*/
public function setDateAdded($dateAdded)
{
$this->dateAdded = $dateAdded;
return $this;
}
/**
* Get dateAdded
*
* #return \DateTime
*/
public function getDateAdded()
{
return $this->dateAdded;
}
/**
* Set lastModified
*
* #param \DateTime $lastModified
* #return Categories
*/
public function setLastModified($lastModified)
{
$this->lastModified = $lastModified;
return $this;
}
/**
* Get lastModified
*
* #return \DateTime
*/
public function getLastModified()
{
return $this->lastModified;
}
/**
* Constructor
*/
public function __construct()
{
$this->categoryDescription = new ArrayCollection();
$this->products = new ArrayCollection();
}
/**
* Add categoryDescription
*
* #param \Apw\BlackbullBundle\Entity\CategoriesDescription $categoryDescription
* #return Categories
*/
public function addCategoryDescription(\Apw\BlackbullBundle\Entity\CategoriesDescription $categoryDescription)
{
$this->categoryDescription[] = $categoryDescription;
return $this;
}
/**
* Remove categoryDescription
*
* #param \Apw\BlackbullBundle\Entity\CategoriesDescription $categoryDescription
*/
public function removeCategoryDescription(\Apw\BlackbullBundle\Entity\CategoriesDescription $categoryDescription)
{
$this->categoryDescription->removeElement($categoryDescription);
}
/**
* Get categoryDescription
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategoryDescription()
{
return $this->categoryDescription;
}
/**
* Add products
*
* #param \Apw\BlackbullBundle\Entity\Products $products
* #return Categories
*/
public function addProduct(\Apw\BlackbullBundle\Entity\Products $products)
{
$this->products[] = $products;
return $this;
}
/**
* Remove products
*
* #param \Apw\BlackbullBundle\Entity\Products $products
*/
public function removeProduct(\Apw\BlackbullBundle\Entity\Products $products)
{
$this->products->removeElement($products);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
/**
* Set categoriesStatus
*
* #param boolean $categoriesStatus
* #return Categories
*/
public function setCategoriesStatus($categoriesStatus)
{
$this->categoriesStatus = $categoriesStatus;
return $this;
}
/**
* Get categoriesStatus
*
* #return boolean
*/
public function getCategoriesStatus()
{
return $this->categoriesStatus;
}
}
Then I have this method in my controller for handle form submission:
<?php
namespace Apw\BlackbullBundle\Controller;
use Apw\BlackbullBundle\Entity\Categories;
use Apw\BlackbullBundle\Entity\CategoriesDescription;
use Apw\BlackbullBundle\Form\CategoriesType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
class CategoriesController extends Controller
{
/**
* #Security("has_role('ROLE_ADMIN')")
* #Route("/createCategory")
* #Template()
*/
public function createCategoryAction(Request $request){
$category = new Categories();
$categoryDesc = new CategoriesDescription();
$category->addCategoryDescription($categoryDesc);
$categoryDesc->setCategory($category);
$form = $this->createForm(new CategoriesType(), $category);
$form->handleRequest($request);
if($form->isValid()){
//exit(\Doctrine\Common\Util\Debug::dump($category));
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->persist($categoryDesc);
$em->flush();
return $this->redirect($this->generateUrl('apw_blackbull_categories_showcategories'));
}
return array(
'form' => $form->createView()
);
}
}
And finally this is my CategoryType.php:
<?php
namespace Apw\BlackbullBundle\Form;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CategoriesType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('categoryDescription', 'collection',
array(
'type' => new CategoriesDescriptionType(),
'allow_add' => true,
'options' => array('data_class' => 'Apw\BlackbullBundle\Entity\CategoriesDescription'),
'by_reference' => false,
))
->add('categoriesImage', null, array('label'=>'Foto:'))
->add('categoriesStatus', null, array('label'=>'Stato:'))
->add('parentId', 'entity', array( //provare a mettere una querybuiler
'class' => 'ApwBlackbullBundle:CategoriesDescription',
'property' => 'categoriesName',
'empty_value' => 'Scegliere una categoria',
'required' => false,
'label' => 'Crea in:'))
->add('salva','submit')
->add('azzera','reset')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Apw\BlackbullBundle\Entity\Categories',
));
}
/**
* #return string
*/
public function getName()
{
return 'categories';
}
}
When I try to save data I get this error:
An exception occurred while executing 'INSERT INTO Categories
(categories_image, parent_id, sort_order, date_added, last_modified,
categories_status) VALUES (?, ?, ?, ?, ?, ?)' with params ["as", {},
null, null, null, 1]:
Catchable Fatal Error: Object of class
Apw\BlackbullBundle\Entity\CategoriesDescription could not be
converted to string
What I'm doing wrong?
You need to implement the __toString() method in your Apw\BlackbullBundle\Entity\CategoriesDescription.
You could do:
public function __toString() {
return $this->name;
}
For Symfony 3.x
According with Symfony docs v3.x you should use choice_label property to specify the entity field name to be used here.
->add('categoryDescription', 'collection',
array(
'type' => new CategoriesDescriptionType(),
'allow_add' => true,
'options' => array('data_class' => 'Apw\BlackbullBundle\Entity\CategoriesDescription'),
'choice_label' => 'name',
'by_reference' => false,
))
I got the same error but i tweaked it a little bit by adding:
public function __toString()
{
return (string) $this->name;
}
I'm sure i was getting null instead of a string value. (I was working with sonata-project).
so I solved the problem by get the value of relative parent in the method $form->isValid()
public function createCategoryAction(Request $request){
$category = new Categories();
$categoryDesc = new CategoriesDescription();
$category->addCategoryDescription($categoryDesc);
$categoryDesc->setCategory($category);
$form = $this->createForm(new CategoriesType(), $category);
$form->handleRequest($request);
if($form->isValid()){
//exit(\Doctrine\Common\Util\Debug::dump($parentCategory->getId()));
$em = $this->getDoctrine()->getManager();
if(!$category->getParentId()){
$category->setParentId(0);
}else{
// get parent id value from input choice
$parent = $category->getParentId();
$parentCategory = $parent->getCategory();
// end
$category->setParentId($parentCategory->getId());
}
$em->persist($category);
$em->persist($categoryDesc);
$em->flush();
return $this->redirect($this->generateUrl('apw_blackbull_categories_showcategories'));
}
return array(
'form' => $form->createView()
);
}
thanks!
You can also use the property accessor into your form:
->add('categoryDescription', 'collection',
array(
'type' => new CategoriesDescriptionType(),
'allow_add' => true,
'options' => array('data_class' => 'Apw\BlackbullBundle\Entity\CategoriesDescription'),
'by_reference' => false,
))
And add 'property' => 'name' in your CategoriesDescriptionType.
By the way the #CoachNono answer is ok too.

Categories