Symfony form choice default value from entity - php

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
])
])

Related

Catchable Fatal Error: Invalid argument passed to method, expected some time and null given

I have this problem when i execute my project, I use FormEvent in FormType
entity Departement.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Departement
*
* #ORM\Table(name="departement")
* #ORM\Entity(repositoryClass="AppBundle\Repository\DepartementRepository")
*/
class Departement
{
/**
* #var int
*
* #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;
/**
* #var int
*
* #ORM\Column(name="code", type="integer")
*/
private $code;
/**
*#ORM\ManyToOne(targetEntity="AppBundle\Entity\Region")
*/
private $region;
/**
*#ORM\OneToMany(targetEntity="AppBundle\Entity\Ville", mappedBy="departement")
*/
private $villes;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Departement
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set code
*
* #param integer $code
* #return Departement
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return integer
*/
public function getCode()
{
return $this->code;
}
/**
* Constructor
*/
public function __construct()
{
$this->villes = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set region
*
* #param \AppBundle\Entity\Region $region
* #return Departement
*/
public function setRegion(\AppBundle\Entity\Region $region = null)
{
$this->region = $region;
return $this;
}
/**
* Get region
*
* #return \AppBundle\Entity\Region
*/
public function getRegion()
{
return $this->region;
}
/**
* Add villes
*
* #param \AppBundle\Entity\Ville $villes
* #return Departement
*/
public function addVille(\AppBundle\Entity\Ville $villes)
{
$this->villes[] = $villes;
return $this;
}
/**
* Remove villes
*
* #param \AppBundle\Entity\Ville $villes
*/
public function removeVille(\AppBundle\Entity\Ville $villes)
{
$this->villes->removeElement($villes);
}
/**
* Get villes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVilles()
{
return $this->villes;
}
public function __toString(){
return $this->name;
}
}
entity ville.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Ville
*
* #ORM\Table(name="ville")
* #ORM\Entity(repositoryClass="AppBundle\Repository\VilleRepository")
*/
class Ville
{
/**
* #var int
*
* #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;
/**
* #var int
*
* #ORM\Column(name="code", type="integer")
*/
private $code;
/**
*#ORM\ManyToOne(targetEntity="AppBundle\Entity\Departement")
*/
private $departement;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Ville
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set code
*
* #param integer $code
* #return Ville
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return integer
*/
public function getCode()
{
return $this->code;
}
/**
* Set departement
*
* #param \AppBundle\Entity\Departement $departement
* #return Ville
*/
public function setDepartement(\AppBundle\Entity\Departement $departement = null)
{
$this->departement = $departement;
return $this;
}
/**
* Get departement
*
* #return \AppBundle\Entity\Departement
*/
public function getDepartement()
{
return $this->departement;
}
public function __toString(){
return $this->name;
}
}
Form MedecinType.php:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormInterface;
use AppBundle\Entity\Region;
use AppBundle\Entity\Departement;
use AppBundle\Entity\Ville;
class MedecinType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('region', EntityType::class, [
'class' => 'AppBundle\Entity\Region',
'placeholder' => 'Sélectionnez votre région',
'mapped' => false,
'required' => false
]);
$builder->get('region')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$this->addDepartementField($form->getParent(), $form->getData());
}
);
}
private function addDepartementField(FormInterface $form, Region $region)
{
$builder = $form->getConfig()->getFormFactory()->createNamedBuilder(
'departement',
EntityType::class,
null,
[
'class' => 'AppBundle\Entity\Departement',
'placeholder' => 'Sélectionnez votre département',
'mapped' => false,
'required' => false,
'auto_initialize' => false,
'choices' => $region->getDepartements()
]);
$builder->addEventListener(
FormEvents::POST_SUBMIT,
function(FormEvent $event) {
$form= $event->getForm();
$this->addVilleField($form->getParent(), $form->getData());
}
);
$form->add($builder->getForm());
}
private function addVilleField(FormInterface $form, Departement $departement)
{
$form->add('ville', EntityType::class, [
'class' => 'AppBundle\Entity\Ville',
'placeholder' => 'Sélectionnez votre ville',
'choices' => $departement->getVilles()
]);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Medecin'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_medecin';
}
}
help me please for resolve this problem and thank you advanced
Since you've set departement field as nullable with 'required' => false,, the method $form->getData() in event listener may be either an instance of Departement entity or null if no departement was chosen.
You have to check if $form->getData() returns instance of your entity and
handle if it's not.
That would be something like:
$builder->addEventListener(
FormEvents::POST_SUBMIT,
function(FormEvent $event) {
$form= $event->getForm();
$formData = $form->getData();
if(! $formData instanceof Departement) {
//handle this case or just do nothing and return from the listener
return;
}
// here's the default case
$this->addVilleField($form->getParent(), $form->getData());
}
);

Create form from variable classnames with parameters

I have a controller ment to give the user the correct form type using variable classnames.
There is a entity named EntityForm which stores data of all forms avaible, with methods to give class name and form type names:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="entity_form")
*/
class EntityForm
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #var string
*
* #ORM\Column(length=12)
*/
protected $url;
/**
* #var string
*
* #ORM\Column
*/
protected $name;
/**
* #var string
*
* #ORM\Column(name="class_name")
*/
protected $className;
/**
* #var string
*
* #ORM\Column(name="description")
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set url
*
* #param string $url
*
* #return Form
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Set name
*
* #param string $name
*
* #return Form
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set className
*
* #param string $className
*
* #return Form
*/
public function setClassName($className)
{
$this->className = $className;
return $this;
}
/**
* Get className
*
* #return string
*/
public function getClassName()
{
return $this->className;
}
public function createEntity()
{
$entity = sprintf('%s\%s', __NAMESPACE__, $this->getClassName());
return new $entity;
}
public function createType()
{
return sprintf('AppBundle\Form\%sType', $this->getClassName());
}
/**
* Set description
*
* #param string $description
*
* #return Form
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
The action mend to create proper forms looks like this:
/**
* #Route("/form/ent/{url}", name="entity_form")
* #Method("GET")
*/
public function formAction(EntityForm $entityForm)
{
$form = $this->createForm($entityForm->createType())
->add('Dodaj!', SubmitType::class, array(
'attr' => array(
'class' => 'btn-info'
)
))
;
return $this->render('default/form.html.twig', [
'form_name' => $entityForm->getName(),
'form_description' => $entityForm->getDescription(),
'form' => $form->createView(),
]);
}
This controller links to a proper form type ie. for the cyclicNewsletter
class CyclicNewsletterType extends AbstractType
{
private $doctrine;
public function __construct($doctrine)
{
$this->doctrine = $doctrine;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$currencies = $this->doctrine->getRepository('AppBundle:Currency')->findAll();
$currenciesFormat = array();
foreach($currencies as $currency){
$currenciesFormat += array($currency->getName() .' ('. $currency->getShortName() . ')' => $currency);
}
$cycles = $this->doctrine->getRepository('AppBundle:Cycle')->findAll();
$cyclesFormat = array();
foreach($cycles as $cycle){
$cyclesFormat += array($cycle->getName() => $cycle);
}
$builder
->add('currency', ChoiceType::class, array(
'label' => 'Waluta',
'choices' => $currenciesFormat,
))
->add('cycle', ChoiceType::class, array(
'label' => 'Cykl',
'choices' => $cyclesFormat,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => CyclicNewsletter::class,
));
}
}
Now with a simple POST action i can eaisly add new values to the database without writing separate actions for all forms:
/**
* #Route("/form/ent/{url}", name="form_entity_post")
* #Method("POST")
*
*/
public function formPostAction(EntityForm $entityForm, Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm($entityForm->createType())
->add('Dodaj!', SubmitType::class)
;
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$formData = $form->getData();
$formData->setUser($this->container->get('security.token_storage')->getToken()->getUser());
$em->persist($formData);
$em->flush();
return $this->redirectToRoute('form_complete', ['url' => $entityForm->getUrl(), 'entityId' => $formData->getId()]);
}
var_dump('problem ' . $form->getErrors());
exit;
}
However
I cant seem to get the method to work for injecting an already created object into the form builder for editing.
What i mean is write a form create with variables classnames that would also store one instance of entity, which values will be already set in the form.
Is such way possible in symfony?
You will need to add the id of the entity you are editing into your url, and make it optional.
* #Route("/form/ent/{url}/{id}", name="form_entity_post", defaults={"id" = null})
In your controller, when you are building the form you need to get that object from the database and pass it to createForm method as the second argument.
/**
* #Route("/form/ent/{url}/{id}", name="form_entity_post", defaults={"id" = null})
* #Method("POST")
*
*/
public function formPostAction(EntityForm $entityForm, Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = null;
if ($id) {
$entity = $em->getRepository($entityForm->getClassName)->find($id);
}
$form = $this->createForm($entityForm->createType(), $entity)
->add('Dodaj!', SubmitType::class)
;

Symfony2 form - Remove related entity form on submit

I have an inherited entity CalendarMeeting from CalendarEvent that adds two related entities. One of which is an Address entity. When the CalendarMeetingis submitted I want to check if the Address form is empty, and if so, remove the form so that no Address is saved to the database. My code is as follows:
CalendarMeeting:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="AppBundle\Entity\CalendarMeetingRepository")
* #ORM\Table(name="calendar_meetings")
*/
class CalendarMeeting extends CalendarEvent
{
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Address", cascade={"persist"})
* #ORM\JoinColumn(name="address_id", referencedColumnName="id")
*/
private $address;
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\User")
* #ORM\JoinTable(
* name="User2CalendarMeeting",
* joinColumns={#ORM\JoinColumn(name="calendar_meeting_id", referencedColumnName="id", nullable=false)},
* inverseJoinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)}
* )
*/
private $users;
/**
* #return mixed
*/
public function getAddress()
{
return $this->address;
}
/**
* #param mixed $address
* #return CalendarMeeting
*/
public function setAddress($address)
{
$this->address = $address;
return $this;
}
/**
* #return ArrayCollection
*/
public function getUsers()
{
return $this->users;
}
/**
* #param User $user
* #return void
*/
public function addUser(User $user)
{
$this->users->add($user);
}
/**
* #param User $user
* #return void
*/
public function removeUser(User $user)
{
$this->users->removeElement($user);
}
}
The Address entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Entity\AddressRepository")
* #ORM\Table(name="addresses")
* #ORM\HasLifecycleCallbacks
*/
class Address
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $name;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $address_1;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $address_2;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $postal_code;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $postal_address;
/**
* #ORM\Column(type="decimal", nullable=true, precision=10, scale=6)
*/
private $latitude;
/**
* #ORM\Column(type="decimal", nullable=true, precision=11, scale=6)
*/
private $longitude;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $created;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $updated;
/**
* #return mixed
*/
public function getId() {
return $this->id;
}
/**
* #return mixed
*/
public function getName() {
return $this->name;
}
/**
* #param mixed $name
* #return Address
*/
public function setName($name) {
$this->name = $name;
return $this;
}
/**
* #return mixed
*/
public function getAddress1() {
return $this->address_1;
}
/**
* #param mixed $address_1
* #return Address
*/
public function setAddress1($address_1) {
$this->address_1 = $address_1;
return $this;
}
/**
* #return mixed
*/
public function getAddress2() {
return $this->address_2;
}
/**
* #param mixed $address_2
* #return Address
*/
public function setAddress2($address_2) {
$this->address_2 = $address_2;
return $this;
}
/**
* #return mixed
*/
public function getPostalCode() {
return $this->postal_code;
}
/**
* #param mixed $postal_code
* #return Address
*/
public function setPostalCode($postal_code) {
$this->postal_code = $postal_code;
return $this;
}
/**
* #return mixed
*/
public function getPostalAddress() {
return $this->postal_address;
}
/**
* #param mixed $postal_address
* #return Address
*/
public function setPostalAddress($postal_address) {
$this->postal_address = $postal_address;
return $this;
}
/**
* #return mixed
*/
public function getLatitude() {
return $this->latitude;
}
/**
* #param mixed $latitude
* #return Address
*/
public function setLatitude($latitude) {
$this->latitude = $latitude;
return $this;
}
/**
* #return mixed
*/
public function getLongitude() {
return $this->longitude;
}
/**
* #param mixed $longitude
* #return Address
*/
public function setLongitude($longitude) {
$this->longitude = $longitude;
return $this;
}
/**
* #return mixed
*/
public function getCreated()
{
return $this->created;
}
/**
* #param \DateTime $created
* #return Address
*/
public function setCreated(\DateTime $created)
{
$this->created = $created;
return $this;
}
/**
* #return mixed
*/
public function getUpdated()
{
return $this->updated;
}
/**
* #param mixed $updated
* #return ShiftChange
*/
public function setUpdated(\DateTime $updated)
{
$this->updated = $updated;
return $this;
}
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updateTimestamps()
{
$this->setUpdated(new \DateTime('now'));
if ($this->getCreated() === null) {
$this->setCreated(new \DateTime('now'));
}
}
}
There is no CalendarMeetingType just the inherited CalendarEventType where I check what entity type is edited by using event listeners. It looks like this:
<?php
namespace AppBundle\Form;
use AppBundle\Entity\CalendarMeeting;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
class CalendarEventType extends AbstractType
{
protected $start = false;
protected $end = false;
public function __construct($date = null)
{
if ($date) {
$this->start = new \DateTime($date . ' 09:00:00');
$this->end = new \DateTime($date . ' 10:00:00');
}
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', null, array(
'attr' => array(
'placeholder' => 'app.forms.calendar.name',
),
'label' => 'app.forms.calendar.name',
'translation_domain' => 'AppBundle'
))
->add('description', null, array(
'label' => 'app.forms.calendar.description',
'translation_domain' => 'AppBundle'
))
->add('event_type', 'choice', array(
'label' => "app.forms.calendar.event_type.label",
'choices' => array(
'event' => 'app.forms.calendar.event_type.event',
'meeting' => 'app.forms.calendar.event_type.meeting',
'holiday' => 'app.forms.calendar.event_type.holiday',
),
'required' => true,
'expanded' => false,
'multiple' => false,
'mapped' => false,
'translation_domain' => 'AppBundle'
));
if ($this->start && $this->end) {
$builder
->add('start', 'datetime', array(
'date_widget' => 'single_text',
'time_widget' => 'text',
'data' => $this->start,
'label' => 'app.forms.calendar.start',
'translation_domain' => 'AppBundle',
))
->add('end', 'datetime', array(
'date_widget' => 'single_text',
'time_widget' => 'text',
'data' => $this->end,
'label' => 'app.forms.calendar.end',
'translation_domain' => 'AppBundle'
));
} else {
$builder
->add('start', 'datetime', array(
'date_widget' => 'single_text',
'time_widget' => 'text',
'label' => 'app.forms.calendar.start',
'translation_domain' => 'AppBundle',
))
->add('end', 'datetime', array(
'date_widget' => 'single_text',
'time_widget' => 'text',
'label' => 'app.forms.calendar.end',
'translation_domain' => 'AppBundle'
));
}
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
array($this, 'onPreSetData')
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
array($this, 'onPreSubmit')
);
}
/**
* #param \Symfony\Component\Form\FormEvent $event
*/
public function onPreSetData(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
/* Check we're looking at the right data/form */
if ($data instanceof CalendarMeeting) {
$form->add('address', new AddressType());
}
}
/**
* #param \Symfony\Component\Form\FormEvent $event
*/
public function onPreSubmit(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
if ($data instanceof CalendarMeeting) {
if ($data->getAddress()->getAddress1() == "") {
$form->remove('address');
}
}
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\CalendarEvent'
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_calendarevent';
}
}
The onPreSubmit function is not working obviously, but alas, this is what I hoped was the right way to do it. I can not figure out how to solve this (another way).
What happens now is that when I submit the form without any data in the address form fields, the address is saved to the database only with empty values. How can I stop the address in getting saved?
Thank you very much for your time.
Regards,
Tommy
I figured this out. I was going about it completely wrong. The solution was to add onDelete="CASCADE" on the CalendarMeeting address:
(edit: The onDelete="CASCADE" was removed from the join column as it was not needed)
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Address", cascade={"persist"})
* #ORM\JoinColumn(name="address_id", referencedColumnName="id", nullable=true)
*/
private $address;
And on the setAddress function, initially set the address parameter to null:
/**
* #param Address $address
* #return CalendarMeeting
*/
public function setAddress(Address $address = null)
{
$this->address = $address;
return $this;
}
Then on the CalendarEventType I changed adding the address type to the following so it accepts null:
if ($data instanceof CalendarMeeting) {
$form->add('address', new AddressType(), array(
'required' => false,
));
}
Finally in the CalendarEventController, I check if the address fields contains any values. If not, set the address to null:
// Check if calendar meeting
if($entity instanceof CalendarMeeting) {
$address_form = $editForm->get('address')->getData();
if($address_form === null ||
($address_form->getName() === null &&
$address_form->getAddress1() === null &&
$address_form->getPostalCode() === null &&
$address_form->getPostalAddress() == null)
) {
$entity->setAddress(null);
}
}
$em->flush();
return ...redirect...
If anyone has a better solution, please post an answer, and I will accept it. Also, please comment if this is a dirty solution. I have a feeling it is.. :)

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