Symfony 3 multiple entities in one form - php

I stuck with this for past two days. I am creating bus traveling website. Currently I am in phase of adding new bus to database.
One bus (or all of them) have many amenities (like AirCon, WiFi, Kitchen, ...) and each of these needs to have custom prices. Let says that our bus have AirCon. AirCon for this bus will cost 50 USD but for other bus AirCon might cost 100 USD. To do that I created 3 Entities (Bus Vehicles Entity, Amenities Entity and Bus Vehicles Amenities Entity). Inside Amenities Entity I iwll store Id of bus, ID of amenity and price for that amenity for that bus ID.
Problem is that I can't get it work. I got blank HTML element when rendering form for that field.I can't add or delete multiple amenities and I am not sure why it is not working.
Does someone knows where is the problem?
Here is the code that I use:
Amenities Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Amenities
*
* #ORM\Table(name="amenities", indexes={#ORM\Index(name="administrator_id", columns={"administrator_id"})})
* #ORM\Entity
*/
class Amenities
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100, nullable=true)
*/
private $name;
/**
* #var \DateTime
*
* #ORM\Column(name="created_at", type="datetime", nullable=false)
*/
private $createdAt = 'CURRENT_TIMESTAMP';
/**
* #var \DateTime
*
* #ORM\Column(name="modified_at", type="datetime", nullable=false)
*/
private $modifiedAt = 'CURRENT_TIMESTAMP';
/**
* #var \AppBundle\Entity\Users
*
* #ORM\ManyToOne(targetEntity="Users")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="administrator_id", referencedColumnName="id")
* })
*/
private $administrator;
/**
* #ORM\OneToMany(targetEntity="BusVehiclesAmenities", mappedBy="amenities")
*/
private $amenities;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Amenities
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
*
* #return Amenities
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Constructor
*/
public function __construct()
{
$this->amenities = new ArrayCollection();
}
/**
* Add amenities
*
* #param \AppBundle\Entity\BusVehiclesAmenities $amenities
* #return Amenities
*/
public function addAmenities(BusVehiclesAmenities $amenities)
{
$this->amenities[] = $amenities;
return $this;
}
/**
* Remove amenities
*
* #param \AppBundle\Entity\BusVehiclesAmenities $amenities
*/
public function removeAmenities(BusVehiclesAmenities $amenities)
{
$this->amenities->removeElement($amenities);
}
/**
* Get amenities_bus_vehicles
*
* #return ArrayCollection
*/
public function getAmenities()
{
return $this->amenities;
}
}
Bus Vehicles Entity:
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* BusVehicles
*
* #ORM\Table(name="bus_vehicles", indexes={#ORM\Index(name="company_id", columns={"company_id"}), #ORM\Index(name="bus_type", columns={"bus_type"}), #ORM\Index(name="fuel_type", columns={"fuel_type"}), #ORM\Index(name="emission_class", columns={"emission_class"})})
* #ORM\Entity
*/
class BusVehicles
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="licence_plate", type="string", length=100, nullable=false)
*/
private $licencePlate;
/**
* #var \AppBundle\Entity\Companies
*
* #ORM\ManyToOne(targetEntity="Companies")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="company_id", referencedColumnName="id")
* })
*/
private $company;
/**
* #var \AppBundle\Entity\BusTypes
*
* #ORM\ManyToOne(targetEntity="BusTypes", inversedBy="busType")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="bus_type", referencedColumnName="id")
* })
*/
/**
* #ORM\OneToMany(targetEntity="BusVehiclesAmenities", mappedBy="bus")
*/
private $busVehiclesAmenities;
public function __construct()
{
$this->busVehiclesAmenities = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add busVehiclesAmenities
*
* #param \AppBundle\Entity\BusVehiclesAmenities busVehiclesAmenities
* #return BusVehicles
*/
public function addBusVehiclesAmenities(BusVehiclesAmenities $busVehiclesAmenities)
{
$this->busVehiclesAmenities[] = $busVehiclesAmenities;
return $this;
}
/**
* Remove busVehiclesAmenities
*
* #param \AppBundle\Entity\BusVehiclesAmenities $busVehiclesAmenities
*/
public function removeBusVehiclesAmenities(BusVehiclesAmenities $busVehiclesAmenities)
{
$this->busVehiclesAmenities->removeElement($busVehiclesAmenities);
}
/**
* Get busVehiclesAmenities
*
* #return ArrayCollection
*/
public function getBusVehiclesAmenities()
{
return $this->busVehiclesAmenities;
}
/**
* Set licencePlate
*
* #param string $licencePlate
*
* #return BusVehicles
*/
public function setLicencePlate($licencePlate)
{
$this->licencePlate = $licencePlate;
return $this;
}
/**
* Set company
*
* #param \AppBundle\Entity\Companies $company
*
* #return BusVehicles
*/
public function setCompany(Companies $company = null)
{
$this->company = $company;
return $this;
}
/**
* Get company
*
* #return \AppBundle\Entity\Companies
*/
public function getCompany()
{
return $this->company;
}
}
Bus Amenities Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* BusVehiclesAmenities
*
* #ORM\Table(name="bus_vehicles_amenities", indexes={#ORM\Index(name="amenities_id", columns={"amenities_id"}), #ORM\Index(name="bus_id", columns={"bus_id"})})
* #ORM\Entity
*/
class BusVehiclesAmenities
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="BusVehicles", inversedBy="busVehiclesAmenities")
* #ORM\JoinColumn(name="bus_id", referencedColumnName="id")
*
*/
private $bus;
/**
*
* #ORM\ManyToOne(targetEntity="Amenities", inversedBy="amenities")
* #ORM\JoinColumn(name="amenities_id", referencedColumnName="id")
*
*/
private $amenities;
/**
* #var float
* #ORM\Column(name="price", type="float", scale=2)
*/
protected $price;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set Bus
*
* #param \AppBundle\Entity\BusVehicles
*
* #return BusVehiclesAmenities
*/
public function setBus($bus)
{
$this->bus = $bus;
return $this;
}
/**
* Get busId
*
* #return integer
*/
public function getBus()
{
return $this->bus;
}
/**
* Set amenities
*
* #param \AppBundle\Entity\Amenities
*
* #return BusVehiclesAmenities
*/
public function setAmenities($amenities)
{
$this->amenities = $amenities;
return $this;
}
/**
* Get amenities
*
* #return \AppBundle\Entity\Amenities
*/
public function getAmenities()
{
return $this->amenities;
}
/**
* Set price
*
* #param float $price
*
* #return BusVehiclesAmenities
*/
public function sePrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return float
*/
public function getPrice()
{
return $this->price;
}
}
FORMS:
Add new bus form:
<?php
namespace AdminBundle\Form\Type;
use AdminBundle\Form\Type\BusVehiclesAmenitiesType;
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\Extension\Core\Type\CollectionType;
class BusVehiclesType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('licencePlate')
->add('company', EntityType::class, array(
'class' => 'AppBundle:Companies',
'choice_label' => 'name',
->add('busVehiclesAmenities', CollectionType::class, array(
'entry_type' => BusVehiclesAmenitiesType::class,
'allow_add' => true,
));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\BusVehicles'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'adminbundle_busvehicles';
}
}
Bus Vehicles Amenities Form
<?php
namespace AdminBundle\Form\Type;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\FormBuilderInterface;
use AppBundle\Entity\BusVehiclesAmenities;
use Symfony\Component\OptionsResolver\OptionsResolver;
class BusVehiclesAmenitiesType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('price', MoneyType::class, array(
'scale' => 2,
))
->add('amenities', EntityType::class, array(
'class' =>'AppBundle:Amenities',
'choice_label' => 'name',
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => BusVehiclesAmenities::class
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_busvehiclesamenities';
}
}

I would not use the entity classes for form binding.
I would create a new class, (e.g. BusVehicle) which contains all properties that need to be on the form (particular fields) and use that as the 'data_class'. This way you would not only solve your problem, but you would also decouple presentation layer from business layer (see Multitier Architecture).
I usually put these classes in Form/Model directory.
In your case the class would be Form/Model/BusVehicle, and it would have $amenities property.
The amenities would be an array of Form/Model/Amenity objects.
You would probably need to use embedded forms just don't use entity classes as 'data_object'. After a successful bind, you instantiate and populate entities for persist or update.
And you don't need the third entity ("Bus Vehicles Amenities").

Related

PHP Symfony Many to Many form

I have a many-to-many relationship between two tables in my database (1 artikel has more than 1 bestelling and vice versa), so I made a link table(bestelregel).
But now I want to make a form so that I can add a new order with multiple products, but as I am new to this, I am not sure how to do it. I've tried to make a form for the entity Bestelling so that I can make a new order. And tried adding products to the order with another form(form based on the link table), but I recieved the following error:
Expected value of type "AppBundle\Entity\Artikel" for association field "AppBundle\Entity\Bestelregel#$bestelordernummer", got "AppBundle\Entity\Bestelling" instead.
I hope you guys can help me. Maybe with another way?
My code:
Entity Artikel
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Artikel
*
* #ORM\Table(name="artikel")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ArtikelRepository")
*/
class Artikel
{
//Mapping naar de database
/**
* #var string
*
* #ORM\Column(name="artikelnummer", type="integer", length=20, unique=true)
* #ORM\Id
* #Assert\Length(
* min = 10,
* max = 10,
* minMessage = "Minimaal 10 karakters",
* maxMessage = "Maximaal 10 karakters"
*)
*/
private $artikelnummer;
/**
* #var string
*
* #ORM\Column(name="omschrijving", type="string", length=255, nullable=true)
*/
private $omschrijving;
/**
* #var string
*
* #ORM\Column(name="specificaties", type="string", length=255, nullable=true)
*/
private $specificaties;
/**
* #var string
*
* #ORM\Column(name="Magazijnlocatie", type="string", length=6)
* #Assert\Regex(
* pattern = "/^20|[0-1]{1}[0-9]{1}\/[A-Z][0]{1}[0-9]{1}|10$/i",
* match=true,
* message="Ongeldige locatie [ERROR1]")
* #Assert\Regex(
* pattern = "/^[2]{1}[1-9]{1}\/[A-Z]{1}[0-9]{1}$/i",
* match=false,
* message="Ongeldige locatie [ERROR2]")
* #Assert\Regex(
* pattern = "/^[3-9]{1}[0-9]{1}\/[A-Z][0-9]{1}$/i",
* match=false,
* message="Ongeldige locatie [ERROR3]")
* #Assert\Regex(
* pattern = "/^[0-1]{1}[0-9]{1}\/[A-Z][1]{1}[1-9]{1}$/i",
* match=false,
* message="Ongeldige locatie [ERROR4]")
* #Assert\Regex(
* pattern = "/^[0-1]{1}[0-9]{1}\/[A-Z][2-9]{1}[0-9]{1}$/i",
* match=false,
* message="Ongeldige locatie [ERROR5]")
* #Assert\Regex(
* pattern = "/^[0-9A-Za-z]+$/i",
* match=false,
* message="Ongeldige locatie [ERROR6]")
* #Assert\Length(
* max = 6,
* maxMessage = "Mag niet meer zijn dan {{ limit }} karakters"
* )
*/
private $magazijnlocatie;
/**
* #var decimal
*
* assert
* #ORM\Column#Column(type="decimal", precision= 10, scale=2, nullable=true)
*/
private $inkoopprijs;
/**
* #var string
*
* #ORM\Column(name="vervangendArtikel", type="string", length=255, nullable=true)
*/
private $vervangendArtikel;
/**
* #var integer
*
* #ORM\Column(name="minimumVoorraad", type="integer", length=20, nullable=true)
*/
private $minimumVoorraad;
/**
* #var integer
*
* #ORM\Column(name="voorraadaantal", type="integer", length=20, nullable=true)
*/
private $voorraadaantal;
/**
* #var integer
*
* #ORM\Column(name="bestelserie", type="integer", length=20, nullable=true)
*/
private $bestelserie;
/**
* #var integer
*
* #ORM\Column(name="verkopen", type="integer", length=20, nullable=true)
*/
private $verkopen;
/**
* #var integer
*
* #ORM\Column(name="gereserveerdeVoorraad", type="integer", length=10, nullable=true)
*/
private $gereserveerdeVoorraad;
/**
* #var integer
*
* #ORM\Column(name="vrijeVoorraad", type="integer", length=10, nullable=true)
*/
private $vrijeVoorraad;
/**
* #var bool
*
* #ORM\Column(name="in_voorraad", type="boolean")
*/
private $inVoorraad;
/**
* #var int
*
* #ORM\OneToMany(targetEntity="Bestelregel", mappedBy="artikelnummer")
*/
private $bestelregels;
public function __construct() {
$this->bestelregels = new ArrayCollection();
}
//**************************************************Set/Get Functies hieronder!*********************************
/**
* Set artikelnummer
*
* #param string $artikelnummer
*
* #return Artikel
*/
public function setArtikelnummer($artikelnummer)
{
$this->artikelnummer = $artikelnummer;
return $this;
}
/**
* Get artikelnummer
*
* #return string
*/
public function getArtikelnummer()
{
return $this->artikelnummer;
}
/**
* Set omschrijving
*
* #param string $omschrijving
*
* #return Artikel
*/
public function setOmschrijving($omschrijving)
{
$this->omschrijving = $omschrijving;
return $this;
}
/**
* Get omschrijving
*
* #return string
*/
public function getOmschrijving()
{
return $this->omschrijving;
}
/**
* Set specificaties
*
* #param string $specificaties
*
* #return Artikel
*/
public function setSpecificaties($specificaties)
{
$this->specificaties = $specificaties;
return $this;
}
/**
* Get specificaties
*
* #return string
*/
public function getSpecificaties()
{
return $this->specificaties;
}
/**
* Set magazijnlocatie
*
* #param string $magazijnlocatie
*
* #return Artikel
*/
public function setMagazijnlocatie($magazijnlocatie)
{
$this->magazijnlocatie = $magazijnlocatie;
return $this;
}
/**
* Get magazijnlocatie
*
* #return string
*/
public function getMagazijnlocatie()
{
return $this->magazijnlocatie;
}
/**
* Set inkoopprijs
*
* #param decimal $inkoopprijs
*
* #return Artikel
*/
public function setInkoopprijs($inkoopprijs)
{
$this->inkoopprijs = $inkoopprijs;
return $this;
}
/**
* Get inkoopprijs
*
* #return decimal
*/
public function getInkoopprijs()
{
return $this->inkoopprijs;
}
/**
* Set vervangendArtikel
*
* #param string $vervangendArtikel
*
* #return Artikel
*/
public function setVervangendartikel($vervangendeArtikel)
{
$this->vervangendArtikel = $vervangendArtikel;
return $this;
}
/**
* Get vervangendArtikel
*
* #return string
*/
public function getVervangendartikel()
{
return $this->vervangendArtikel;
}
/**
* Set minimumVoorraad
*
* #param integer $minimumVoorraad
*
* #return Artikel
*/
public function setMinimumvoorraad($minimumVoorraad)
{
$this->minimumVoorraad = $minimumVoorraad;
return $this;
}
/**
* Get minimumVoorraad
*
* #return integer
*/
public function getMinimumvoorraad()
{
return $this->minimumVoorraad;
}
/**
* Set voorraadaantal
*
* #param integer $voorraadaantal
*
* #return Artikel
*/
public function setVoorraadaantal($voorraadaantal)
{
$this->voorraadaantal = $voorraadaantal;
return $this;
}
/**
* Get voorraadaantal
*
* #return integer
*/
public function getVoorraadaantal()
{
return $this->voorraadaantal;
}
/**
* Set bestelserie
*
* #param integer $bestelserie
*
* #return Artikel
*/
public function setBestelserie($bestelserie)
{
$this->bestelserie = $bestelserie;
}
/**
* Get bestelserie
*
* #return integer
*/
public function getBestelserie()
{
return $this->bestelserie;
}
/**
* Set verkopen
*
* #param integer $verkopen
*
* #return Verkopen
*/
public function setVerkopen($verkopen)
{
$this->verkopen= $verkopen;
return $this;
}
/**
* Get verkopen
*
* #return integer
*/
public function getVerkopen()
{
return $this->verkopen;
}
/**
* Set gereserveerdeVoorraad
*
* #param integer $gereserveerdeVoorraad
*
*/
public function setGereserveerdevoorraad($gereserveerdeVoorraad)
{
$this->gereserveerdeVoorraad= $gereserveerdeVoorraad;
return $this;
}
/**
* Get gereserveerdeVoorraad
*
* #return integer
*/
public function getGereserveerdevoorraad()
{
return $this->gereserveerdeVoorraad;
}
/**
* Set vrijeVoorraad
*
* #param integer $vrijeVoorraad
*
* #return Artikel
*/
public function setVrijevoorraad($vrijeVoorraad)
{
$this->vrijeVoorraad= $vrijeVoorraad;
return $this;
}
/**
* Get vrijeVoorraad
*
* #return integer
*/
public function getVrijevoorraad()
{
return $this->vrijeVoorraad;
}
/**
* #return bool
*/
public function getInVoorraad()
{
return $this->inVoorraad;
}
/**
* #param bool $inVoorraad
*/
public function setInVoorraad($inVoorraad)
{
$this->inVoorraad = $inVoorraad;ity
}
}
Entity Bestelling
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Bestelling
*
* #ORM\Table(name="bestelling")
* #ORM\Entity(repositoryClass="AppBundle\Repository\BestellingRepository")
*/
class Bestelling
{
/**
* #var int
*
* #ORM\Column(name="bestelordernummer", type="integer", unique=true)
* #ORM\Id
*/
private $bestelordernummer;
/**
* #var string
*
* #ORM\Column(name="leverancier", type="string", length=100, nullable=true)
*/
private $leverancier;
/**
* #var int
*
* #ORM\Column(name="keuringseisen", type="integer", length=4, nullable=true)
*/
private $keuringseisen;
/**
* #var int
*
* #ORM\OneToMany(targetEntity="Bestelregel", mappedBy="bestelordernummer")
*/
private $bestelregels;
public function __construct() {
$this->bestelregels = new ArrayCollection();
}
/**
* Set bestelordernummer
*
* #param integer $bestelordernummer
*
* #return Bestelling
*/
public function setBestelordernummer($bestelordernummer)
{
$this->bestelordernummer = $bestelordernummer;
return $this;
}
/**
* Get bestelordernummer
*
* #return integer
*/
public function getBestelordernummer()
{
return $this->bestelordernummer;
}
/**
* Set leverancier
*
* #param string $leverancier
*
* #return Bestelling
*/
public function setLeverancier($leverancier)
{
$this->leverancier = $leverancier;
return $this;
}
/**
* Get leverancier
*
* #return string
*/
public function getLeverancier()
{
return $this->leverancier;
}
/**
* Set keuringseisen
*
* #param integer $keuringseisen
*
* #return Bestelling
*/
public function setKeuringseisen($keuringseisen)
{
$this->keuringseisen = $keuringseisen;
return $this;
}
/**
* Get keuringseisen
*
* #return integer
*/
public function getKeuringseisen()
{
return $this->keuringseisen;
}
}
Entity Bestelregel (Link table)
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Bestelregel
*
* #ORM\Table(name="bestelregel")
* #ORM\Entity(repositoryClass="AppBundle\Repository\BestelregelRepository")
*/
class Bestelregel
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\ManyToOne(targetEntity="Artikel", inversedBy="bestelregels")
* #ORM\JoinColumn(name="artikelnummer", referencedColumnName="artikelnummer")
*/
private $artikelnummer;
/**
* #var int
*
* #ORM\ManyToOne(targetEntity="Artikel", inversedBy="bestelregels")
* #ORM\JoinColumn(name="bestelordernummer", referencedColumnName="bestelordernummer")
*/
private $bestelordernummer;
/**
* Set id
*
* #param integer $id
*
* #return Bestelregel
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set artikelnummer
*
* #param integer $artikelnummer
*
* #return Bestelregel
*/
public function setArtikelnummer($artikelnummer)
{
$this->artikelnummer = $artikelnummer;
return $this;
}
/**
* Get artikelnummer
*
* #return integer
*/
public function getArtikelnummer()
{
return $this->artikelnummer;
}
/**
* Set bestelordernummer
*
* #param integer $bestelordernummer
*
* #return Bestelregel
*/
public function setBestelordernummer($bestelordernummer)
{
$this->bestelordernummer = $bestelordernummer;
return $this;
}
/**
* Get bestelordernummer
*
* #return integer
*/
public function getBestelordernummer()
{
return $this->bestelordernummer;
}
}
Form Bestelling
<?php
namespace AppBundle\Form\Type;
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\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class BestellingType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
//gebruiken wat je nodig hebt, de id hoeft er niet bij als deze auto increment is
$builder
->add('bestelordernummer', IntegerType::class) //naam is b.v. een attribuut of variabele van klant
;
$builder
->add('leverancier', TextType::class) //naam is b.v. een attribuut of variabele van klant
;
$builder
->add('keuringseisen', TextType::class) //naam is b.v. een attribuut of variabele van klant
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Bestelling'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_bestelregel';
}
}
Form Bestelregel (Link table)
<?php
namespace AppBundle\Form\Type;
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\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class BestelregelType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
//gebruiken wat je nodig hebt, de id hoeft er niet bij als deze auto increment is
$builder
->add('artikelnummer', EntityType::class, array(
'class' => 'AppBundle:Artikel',
'choice_label' => 'artikelnummer'))
;
$builder
->add('bestelordernummer', EntityType::class, array(
'class' => 'AppBundle:Bestelling',
'choice_label' => 'bestelordernummer'))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Bestelregel'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_bestelregel';
}
}
Picture Database
You don'e need to add an intermediate entity (bestelregel here), unless it has to have its own unique properties (like the timestamp for which the relation stablished, or the user who stablished the relation or anything else).
In other words, if your bestelregel entity has ONLY this list of properties:
id
artikle
bestelling (or bestelorder or whatever you call it in Dutch)
forget about creating it. you only need these two entity classes:
Beselling
Artikel
Taking advantage of Doctrine ORM relations, the relation database table would be created and manipulated automatically behind the scene.
Also, keep your code in English, as you have the opportunity of a World get in touch in case you need a hand, instead of using Dutch or any other language. You may use translation tools to translate the interface, but use English for your code base as it is a best practice all over the world.
Article entity:
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="`article`")
*/
class Article
{
/**
* #ORM\ManyToMany(targetEntity="Order", mappedBy="articles")
*/
private $orders;
public function __construct() {
$this->orders = new ArrayCollection();
}
public function addOrder(Order $order)
{
if ($this->orders->contains($order)) {
return;
}
$this->orders->add($order);
$order->addArticle($this);
}
public function removeOrder(Order $order)
{
if (!$this->orders->contains($order)) {
return;
}
$this->orders->removeElement($order);
$order->removeArticle($this);
}
}
Order entity:
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="`order`")
*/
class Order
{
/**
* #ORM\ManyToMany(targetEntity="Article", inversedBy="orders")
*/
private $articles;
public function __construct() {
$this->articles = new ArrayCollection();
}
public function addArticle(Article $article)
{
if ($this->articles->contains($article)) {
return;
}
$this->articles->add($article);
$article->addOrder($this);
}
public function removeArticle(Article $article)
{
if (!$this->articles->contains($article)) {
return;
}
$this->articles->removeElement($article);
$article->removeOrder($this);
}
}
OrderType form:
namespace AppBundle\Form;
use AppBundle\Entity\Article;
use AppBundle\Entity\Order;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class OrderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('articles', EntityType::class, array(
'class' => Article::class,
'expanded' => true,
'multiple' => true,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Order::class
));
}
}
I had the same exact problem and worked it on the same way as the first answer of this question. The problem was that when the form was rendered as html the checkboxes were rendered as
<input type="checkbox" name="form_name[field_name][]" value ="entityid"/> <input type="checkbox" name ="form_name[field_name][]" value="otherentityid"/>
When the form was submitted only one of the checked checkboxes is submitted

SQLSTATE[42S22]:Column not found

I have create Formtype UniversitaireType but I have this error:
attribut condidat_id doesn't create in database when I try command php bin/console doctrine:schema:update --force (all attributs create in database except id_condidat) .. I make mapping OneToMany $condidat in entity Universitaire
code entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\Condidat;
/**
* Universitaire.
*
* #ORM\Table(name="universitaires")
* #ORM\Entity(repositoryClass="AppBundle\Entity\UniversitaireEntityRepository")
*/
class Universitaire
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="date_start", type="string", length=255, nullable=true)
*/
private $dateStart;
/**
* #var string
*
* #ORM\Column(name="date_end", type="string", length=255, nullable=true)
*/
private $dateEnd;
/**
* #var string
*
* #ORM\Column(name="establishment", type="string", length=255, nullable=true, unique=true)
*/
private $establishment;
/**
* #var string
*
* #ORM\Column(name="diploma", type="string", length=255, nullable=true, unique=true)
*/
private $diploma;
/**
*#ORM\OneToMany(targetEntity="AppBundle\Entity\Condidat",mappedBy="id_universitaire",cascade={"persist"})
*#ORM\JoinColumn(name="id_condidat", referencedColumnName="id")
*/
private $condidat;
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Add Condidat
*
* #param \AppBundle\Entity\Condidat $condidat
* #return Universitaire
*/
public function addCondidat(\AppBundle\Entity\Condidat $condidat)
{
$this->condidat[] = $condidat;
return $this;
}
/**
* Remove Condidat
*
* #param \AppBundle\Entity\Condidat $condidat
*/
public function removeCondidat(\AppBundle\Entity\Condidat $condidat)
{
$this->Condidat->removeElement($condidat);
}
/**
* Get Condidat
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCondidat()
{
return $this->condidat;
}
/**
* Set dateStart.
*
* #param string $dateStart
*
* #return Universitaire
*/
public function setdateStart($dateStart)
{
$this->dateStart = $dateStart;
return $this;
}
/**
* Get dateStart.
*
* #return string
*/
public function getdateStart()
{
return $this->dateStart;
}
/**
* Set dateEnd.
*
* #param string $dateEnd
*
* #return Universitaire
*/
public function setDateEnd($dateEnd)
{
$this->dateEnd = $dateEnd;
return $this;
}
/**
* Get dateEnd.
*
* #return string
*/
public function getdateEnd()
{
return $this->dateEnd;
}
/**
* Set establishment.
*
* #param string $establishment
*
* #return Universitaire
*/
public function setEstablishment($establishment)
{
$this->establishment = $establishment;
return $this;
}
/**
* Get establishment.
*
* #return string
*/
public function getEstablishment()
{
return $this->establishment;
}
/**
* Set diploma.
*
* #param string $diploma
*
* #return Universitaire
*/
public function setDiploma($diploma)
{
$this->diploma = $diploma;
return $this;
}
/**
* Get diploma.
*
* #return string
*/
public function getDiploma()
{
return $this->diploma;
}
public function __construct()
{
$this->ResponsableCategory = new \Doctrine\Common\Collections\ArrayCollection();
}
}
code FormType:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Entity\Universitaire;
use AppBundle\Entity\Condidat;
class UniversitaireType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('dateStart')->add('dateEnd')->add('establishment')->add('diploma')
->add('condidat',null, array(
'class' => 'AppBundle:Condidat',
'choice_label' => 'condidat',));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Universitaire',
"csrf_protection" => "false"
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_universitaire';
}
}
You have two mistakes in your "condidat" property.
You used One-To-Many (Bidirectional). If you want to have only one
candidate per "Universitaire" - then you have to use One-To-One (Bidirectional).
class Universitaire
{
## ...
/**
* Bidirectional One-To-One (Owning Side)
*
* #ORM\OneToOne(
* targetEntity="AppBundle\Entity\Condidat",
* inversedBy="universitaire",
* cascade={"persist", "remove"}
* )
* #ORM\JoinColumn(
* name="condiat_id",
* referencedColumnName="id"
* )
*/
private $condidat;
class Condidat
{
## ...
/**
* Bidirectional One-To-One (Inversed Side)
*
* #ORM\OneToOne(
* targetEntity="AppBundle\Entity\Universitaire",
* mappedBy="condidat",
* )
*/
private $universitaire;
If not, and One-To-Many was exactly you wanted to have, than you have to set in your __construct() that "condidat" is an array collection
public function __construct()
{
$this->condidat = new \Doctrine\Common\Collections\ArrayCollection();
}
If I were you I'd rather use "candidates" with "s" - to show, that this an arrayCollection.
As I've already said - your example is Bidirectional One-To-Many. In this case we use mappedBy and inversedBy. Entity, in which you set Join column is Owning side. And of course JoinColumn has to be in the "Candidate" entity. So:
class Universitaire
{
## ...
/**
* Bidirectional One-To-Many (Owning Side)
* Predicate: One Universitaire can have a lot of candidates
*
* #ORM\OneToMany(
* targetEntity="AppBundle\Entity\Condidat",
* mappedBy="universitaire",
* cascade={"persist", "remove"}
* )
*/
private $condidats;
class Condidat
{
## ...
/**
* Bidirectional Many-To-One (Owning Side)
* Predicate: Each Condidat belongs to one Universitaire
*
* #ORM\ManyToOne(
* targetEntity="AppBundle\Entity\Universitaire",
* inversedBy="condidats",
* )
* #ORM\JoinColumn(
* name="universitaire_id",
* referencedColumnName="id",
* onDelete="SET NULL"
* )
*/
private $universitaire;
I added onDelete="SET NULL". If you delete universitaire then in field universitaire of each "condidate" you will see null value.

Symfony2 - show one property in form, mapping by another property

So I'm working on application to handle library maintenance. In my database I have three tables: Book, Category and BookCategory. In Book table I have two fields: BookID and BookTitle, in Category I have CategoryID and CategoryName and in BookCategory I have BookID (foreign key of Book(BookID)) and CategoryID (foreign key of Category(CategoryID). I autogenerated controllers and form by using
php app/console generate:doctrine:crud --entity=AppBundle:EntityName
The point is, when I try to add new book to database, I can enter title of book and it's category by category ID (picture related), but I want to add new book using category name, not category ID, though it still should be mapped by category ID to BookCategory table. How to do it? How it looks like and how I want it to look like
Book.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Book
*
* #ORM\Table(name="book")
* #ORM\Entity
*/
class Book
{
/**
* #var integer
*
* #ORM\Column(name="book_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $bookId;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=50, nullable=false)
*/
private $title;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Category", inversedBy="bookId")
* #ORM\JoinTable(name="book_category",
* joinColumns={
* #ORM\JoinColumn(name="book_id", referencedColumnName="book_id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="category_id", referencedColumnName="category_id")
* }
* )
*/
private $categoryId;
/**
* Constructor
*/
public function __construct()
{
$this->categoryId = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get bookId
*
* #return integer
*/
public function getBookId()
{
return $this->bookId;
}
/**
* Set title
*
* #param string $title
* #return Book
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Add categoryId
*
* #param \AppBundle\Entity\Category $categoryId
* #return Book
*/
public function addCategoryId(\AppBundle\Entity\Category $categoryId)
{
$this->categoryId[] = $categoryId;
return $this;
}
/**
* Remove categoryId
*
* #param \AppBundle\Entity\Category $categoryId
*/
public function removeCategoryId(\AppBundle\Entity\Category $categoryId)
{
$this->categoryId->removeElement($categoryId);
}
/**
* Get categoryId
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategoryId()
{
return $this->categoryId;
}
public function __toString()
{
return (string)$this->bookId;
}
}
Category.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="category_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $categoryId;
/**
* #var string
*
* #ORM\Column(name="category_name", type="string", length=50, nullable=false)
*/
private $categoryName;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Book", mappedBy="categoryId")
*/
private $bookId;
/**
* Constructor
*/
public function __construct()
{
$this->bookId = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get categoryId
*
* #return integer
*/
public function getCategoryId()
{
return $this->categoryId;
}
/**
* Set categoryName
*
* #param string $categoryName
* #return Category
*/
public function setCategoryName($categoryName)
{
$this->categoryName = $categoryName;
return $this;
}
/**
* Get categoryName
*
* #return string
*/
public function getCategoryName()
{
return $this->categoryName;
}
/**
* Add bookId
*
* #param \AppBundle\Entity\Book $bookId
* #return Category
*/
public function addBookId(\AppBundle\Entity\Book $bookId)
{
$this->bookId[] = $bookId;
return $this;
}
/**
* Remove bookId
*
* #param \AppBundle\Entity\Book $bookId
*/
public function removeBookId(\AppBundle\Entity\Book $bookId)
{
$this->bookId->removeElement($bookId);
}
/**
* Get bookId
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getBookId()
{
return $this->bookId;
}
public function __toString()
{
return (string)$this->categoryId;
}
}
BookType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class BookType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('categoryId')
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Book'
));
}
}
This should do it:
$builder->add('categoryId', EntityType::class, array(
'class' => 'AppBundle:Category',
'choice_label' => 'categoryName',
'expanded' => true,
));
Add category to the form as entity:
$builder
->add('title')
->add('category', 'entity', [
'class' => Category::class,
'choice_label' => 'categoryName'
])
;

Symfony One-To-One Unidirectional relationship How can I make Doctrine create a new Menu if a new Coffeeshop is made?

I have a bit of a problem figuring out the following:
How can I make Symfony insert a new menu when a new coffeeshop has been made with a form? (foreign key in menu is shopid)
Thanks in advance, code below.
Menu Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Menu
*
* #ORM\Table(name="menu")
* #ORM\Entity(repositoryClass="AppBundle\Repository\MenuRepository")
*
*/
class Menu
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Coffeeshop")
* #ORM\JoinColumn(name="coffeeshop_id", referencedColumnName="id")
*/
private $shopId;
/**
* #var \DateTime $updated
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
*/
private $updated;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set shopId
*
* #param integer $shopId
*
* #return Menu
*/
public function setShopId($shopId)
{
$this->shopId = $shopId;
return $this;
}
/**
* Get shopId
*
* #return int
*/
public function getShopId()
{
return $this->shopId;
}
/**
* Set lastUpdated
*
* #param \DateTime $lastUpdated
*
* #return Menu
*/
public function setLastUpdated($lastUpdated)
{
$this->lastUpdated = $lastUpdated;
return $this;
}
/**
* Get lastUpdated
*
* #return \DateTime
*/
public function getLastUpdated()
{
return $this->lastUpdated;
}
/**
* Set updated
*
* #param \DateTime $updated
*
* #return Menu
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
}
Coffeeshop Entity:
<?php
/// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="coffeeshop")
*/
class Coffeeshop
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* #ORM\Column(type="string")
*/
private $phone;
/**
* #ORM\Column(type="string", length=50)
*/
private $streetName;
/**
* #ORM\Column(type="string", length=6)
*/
private $houseNumber;
/**
* #ORM\Column(type="string", length=7)
*/
private $zipcode;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Coffeeshop
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set phone
*
* #param string $phone
*
* #return Coffeeshop
*/
public function setPhone($phone)
{
$this->phone = $phone;
return $this;
}
/**
* Get phone
*
* #return string
*/
public function getPhone()
{
return $this->phone;
}
/**
* Set streetName
*
* #param string $streetName
*
* #return Coffeeshop
*/
public function setStreetName($streetName)
{
$this->streetName = $streetName;
return $this;
}
/**
* Get streetName
*
* #return string
*/
public function getStreetName()
{
return $this->streetName;
}
/**
* Set houseNumber
*
* #param string $houseNumber
*
* #return Coffeeshop
*/
public function setHouseNumber($houseNumber)
{
$this->houseNumber = $houseNumber;
return $this;
}
/**
* Get houseNumber
*
* #return string
*/
public function getHouseNumber()
{
return $this->houseNumber;
}
/**
* Set description
*
* #param string $description
*
* #return Coffeeshop
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set zipcode
*
* #param string $zipcode
*
* #return Coffeeshop
*/
public function setZipcode($zipcode)
{
$this->zipcode = $zipcode;
return $this;
}
/**
* Get zipcode
*
* #return string
*/
public function getZipcode()
{
return $this->zipcode;
}
/**
* Set menu
*
* #param \AppBundle\Entity\Menu $menu
*
* #return Coffeeshop
*/
public function setMenu(\AppBundle\Entity\Menu $menu = null)
{
$this->menu = $menu;
return $this;
}
/**
* Get menu
*
* #return \AppBundle\Entity\Menu
*/
public function getMenu()
{
return $this->menu;
}
/**
* Set coffeeshopmenu
*
* #param \AppBundle\Entity\Menu $coffeeshopmenu
*
* #return Coffeeshop
*/
public function setCoffeeshopmenu(\AppBundle\Entity\Menu $coffeeshopmenu = null)
{
$this->coffeeshopmenu = $coffeeshopmenu;
return $this;
}
/**
* Get coffeeshopmenu
*
* #return \AppBundle\Entity\Menu
*/
public function getCoffeeshopmenu()
{
return $this->coffeeshopmenu;
}
}
Coffeeshop FormBuilder:
<?php
/**
* Created by PhpStorm.
* User:
* Date: 23-9-2016
* Time: 14:20
*/
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class CoffeeshopType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('phone')
->add('streetName')
->add('houseNumber')
->add('zipcode')
->add('description')
->add('save', SubmitType::class, array('label' => 'Add shop'))
;
}
}
In many ways:
you can define Coffeeshoptypeas a service, then inject ManagerRegistry (#doctrine) to __construct() (or just EntityManager), set an event listener for event FormEvents::POST_SUBMIT. Something like that:
$this->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {/*...*/});
in controller, where you persist changes from Coffeeshoptype
use an event listener for Doctrine (or create an entity listener, feature from Doctrine). With doctrine events, you can find if entity (Coffeeshop) is persisting or updating and depends of situation, create new menu.
All of above methods can have access to Doctrine (thanks to Dependency Injection), also some of these methods are bad approaches. I suggest to attach EventListener (or EventSubscriber) to one of Doctrine Events and then do persisting for new menu. But if you need to create a new menu only when Coffeeshop is submitted by form, create event listener in form type.

Symfony Form with Doctrine Entity - Relation not loading for editing

I'm having an issue with something I think is probably fairly basic but the cause is escaping me.
I have a two entities, an Organisation and a Subscription. An organisation is linked with one subscription.
I want to be able to edit this via a form (creating via form already works). When I do the following:
$organisation = $this->getDoctrine()->getRepository('AppBundle\Entity\Organisation')
->findOneBy(array(
'id' => $id
));
$form = $this->createForm(new OrganisationType(), $organisation, array(
'method' => 'POST'
));
$form->submit($paramFetcher->all());
I get an exception because the subscription property of the organisation entity is not set (despite passing one which has a subscription into the form defaults). The exception is as follows:
Expected argument of type "AppBundle\Entity\Subscription", "NULL" given
This is obviously being thrown by the setSubscription method on the Organisation entity but I'm not sure why as the form should be converting the int value passed to a Subscription entity automatically.
Am I doing something stupid here? I have attached the relevant code below. Thank you!
The simplest controller action that replicates this issue
public function testAction(Request $request)
{
$organisation = $this->getDoctrine()->getRepository('AppBundle\Entity\Organisation')
->findOneBy(array('id' => 7));
$form = $this->createForm(new OrganisationType(), $organisation);
$form->submit($request->request->all());
return $this->render('test.html.twig', array(
'testform' => $form->createView()
));
}
Organisation.php
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Organisation
*
* #ORM\Table(name="organisation")
* #ORM\Entity(repositoryClass="AppBundle\Repository\OrganisationRepository")
*/
class Organisation
{
const ENABLED = 1;
const DISABLED = 2;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #JMS\Groups({"default", "list-organisation"})
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #JMS\Groups({"default", "list-organisation"})
*/
private $name;
/**
* #var Subscription|null The subscription this organisation is currently linked to
* #ORM\ManyToOne(targetEntity="Subscription", inversedBy="organisations")
* #ORM\JoinColumn(name="subscription_id", referencedColumnName="id", onDelete="set null")
* #JMS\Groups({"default", "list-organisation"})
*/
private $subscription;
/**
* #var Collection
* #ORM\OneToMany(targetEntity="User", mappedBy="organisation")
* #JMS\Groups({})
*/
private $users;
/**
* #var Collection
* #ORM\OneToMany(targetEntity="Subgroup", mappedBy="organisation")
* #JMS\Groups({"default"})
*/
private $subgroups;
/**
* #var string $enabled
*
* #ORM\Column(type="string")
*/
private $enabled = self::ENABLED;
/**
* #var datetime $created
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
* #JMS\Groups({"default", "list-organisation"})
*/
private $created;
/**
* #var datetime $updated
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
* #JMS\Groups({"default", "list-organisation"})
*/
private $updated;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Organisation
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Sets subscription
*
* #param Subscription $subscription
* #return $this
*/
public function setSubscription(Subscription $subscription)
{
$this->subscription = $subscription;
return $this;
}
/**
* Gets subscription
*
* #return Subscription|null
*/
public function getSubscription()
{
return $this->subscription;
}
/**
* Sets enabled
*
* #param $enabled
*/
public function setEnabled($enabled)
{
if (!in_array($enabled, array(self::ENABLED, self::DISABLED))) {
throw new \InvalidArgumentException('Invalid enabled status');
}
$this->enabled = $enabled;
}
/**
* Gets enabled
*
* #return string
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns Users belonging to this organisation
*
* #return Collection
*/
public function getUsers()
{
return $this->users;
}
public function __toString()
{
return $this->getName();
}
}
Subscription.php
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Organisation
*
* #ORM\Table(name="subscription")
* #ORM\Entity(repositoryClass="AppBundle\Repository\SubscriptionRepository")
*/
class Subscription
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #JMS\Groups({"default", "list-organisation"})
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #JMS\Groups({"default", "list-organisation"})
*/
private $name;
/**
* #var Collection
* #ORM\OneToMany(targetEntity="Organisation", mappedBy="subscription")
* #JMS\Groups({"default"})
*/
private $organisations;
/**
* #var datetime $created
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
* #JMS\Groups({"default"})
*/
private $created;
/**
* #var datetime $updated
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
* #JMS\Groups({"default"})
*/
private $updated;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Subscription
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns Organisations with this subscription type
*
* #return Collection
*/
public function getOrganisations()
{
return $this->organisations;
}
/**
* #return string
*/
public function __toString()
{
return $this->getName();
}
}
OrganisationType.php
<?php
namespace AppBundle\Form;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class OrganisationType extends AbstractType
{
private $manager;
public function __construct(ObjectManager $objectManager)
{
$this->manager = $objectManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('subscription', EntityType::class, array(
'class' => 'AppBundle\Entity\Subscription'
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Organisation',
'csrf_protection' => false
));
}
}
On a fresh Symfony 3.1, this works like a charm (and this is the recommended way to handle form submission, as stated in a previous comment) :
public function testAction(Request $request)
{
$organisation = $this->getDoctrine()->getRepository('AppBundle\Entity\Organisation')
->find(1);
$form = $this->createForm(OrganisationType::class, $organisation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->persist($organisation);
$this->getDoctrine()->getManager()->flush();
die('saved into database.');
}
return $this->render('test.html.twig', array(
'testform' => $form->createView()
));
}

Categories