Skip to content
Advertisement

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 “AppBundleEntityArtikel” for association field “AppBundleEntityBestelregel#$bestelordernummer”, got “AppBundleEntityBestelling” instead.

I hope you guys can help me. Maybe with another way?

My code:

Entity Artikel

<?php

namespace AppBundleEntity;

use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;
use SymfonyComponentSecurityCoreUserUserInterface;
use DoctrineCommonCollectionsArrayCollection;

/**
 * Artikel
 *
 * @ORMTable(name="artikel")
 * @ORMEntity(repositoryClass="AppBundleRepositoryArtikelRepository")
 */
class Artikel
{

    //Mapping naar de database

     /**
     * @var string
     *
     * @ORMColumn(name="artikelnummer", type="integer", length=20, unique=true)
     * @ORMId
     * @AssertLength(
     *      min = 10,
     *      max = 10,
     *      minMessage = "Minimaal 10 karakters",
     *      maxMessage = "Maximaal 10 karakters"
     *)
     */
    private $artikelnummer;

    /**
     * @var string
     *
     * @ORMColumn(name="omschrijving", type="string", length=255, nullable=true)
     */
    private $omschrijving;

    /**
     * @var string
     *
     * @ORMColumn(name="specificaties", type="string", length=255, nullable=true)
     */
    private $specificaties;

    /**
     * @var string
     *
     * @ORMColumn(name="Magazijnlocatie", type="string", length=6)
         * @AssertRegex(
         *    pattern = "/^20|[0-1]{1}[0-9]{1}/[A-Z][0]{1}[0-9]{1}|10$/i",
         *    match=true,
         *    message="Ongeldige locatie [ERROR1]")
         * @AssertRegex(
         *    pattern = "/^[2]{1}[1-9]{1}/[A-Z]{1}[0-9]{1}$/i",
         *    match=false,
         *    message="Ongeldige locatie [ERROR2]")
         * @AssertRegex(
         *    pattern = "/^[3-9]{1}[0-9]{1}/[A-Z][0-9]{1}$/i",
         *    match=false,
         *    message="Ongeldige locatie [ERROR3]")
         * @AssertRegex(
         *    pattern = "/^[0-1]{1}[0-9]{1}/[A-Z][1]{1}[1-9]{1}$/i",
         *    match=false,
         *    message="Ongeldige locatie [ERROR4]")
         * @AssertRegex(
         *    pattern = "/^[0-1]{1}[0-9]{1}/[A-Z][2-9]{1}[0-9]{1}$/i",
         *    match=false,
         *    message="Ongeldige locatie [ERROR5]")
         * @AssertRegex(
         *    pattern = "/^[0-9A-Za-z]+$/i",
         *    match=false,
         *    message="Ongeldige locatie [ERROR6]")
         * @AssertLength(
         *      max = 6,
         *      maxMessage = "Mag niet meer zijn dan {{ limit }} karakters"
         * )
         */
    private $magazijnlocatie;

    /**
     * @var decimal
     *
     * assert
     * @ORMColumn@Column(type="decimal", precision= 10, scale=2, nullable=true)
     */
    private $inkoopprijs;

    /**
     * @var string
     *
     * @ORMColumn(name="vervangendArtikel", type="string", length=255, nullable=true)
     */

    private $vervangendArtikel;

    /**
     * @var integer
     *
     * @ORMColumn(name="minimumVoorraad", type="integer", length=20, nullable=true)
     */
    private $minimumVoorraad;

    /**
     * @var integer
     *
     * @ORMColumn(name="voorraadaantal", type="integer", length=20, nullable=true)
     */
    private $voorraadaantal;

    /**
     * @var integer
     *
     * @ORMColumn(name="bestelserie", type="integer", length=20, nullable=true)
     */
    private $bestelserie;

    /**
     * @var integer
     *
     * @ORMColumn(name="verkopen", type="integer", length=20, nullable=true)
     */
    private $verkopen;

    /**
     * @var integer
     *
     * @ORMColumn(name="gereserveerdeVoorraad", type="integer", length=10, nullable=true)
     */

    private $gereserveerdeVoorraad;

    /**
     * @var integer
     *
     * @ORMColumn(name="vrijeVoorraad", type="integer", length=10, nullable=true)
     */

    private $vrijeVoorraad;

    /**
     * @var bool
     *
     * @ORMColumn(name="in_voorraad", type="boolean")
     */
    private $inVoorraad;

    /**
     * @var int
     *
     * @ORMOneToMany(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 AppBundleEntity;

use DoctrineORMMapping as ORM;
use DoctrineCommonCollectionsArrayCollection;

/**
 * Bestelling
 *
 * @ORMTable(name="bestelling")
 * @ORMEntity(repositoryClass="AppBundleRepositoryBestellingRepository")
 */
class Bestelling
{

    /**
     * @var int
     *
     * @ORMColumn(name="bestelordernummer", type="integer", unique=true)
     * @ORMId
     */
    private $bestelordernummer;

    /**
     * @var string
     *
     * @ORMColumn(name="leverancier", type="string", length=100, nullable=true)
     */
    private $leverancier;

    /**
     * @var int
     *
     * @ORMColumn(name="keuringseisen", type="integer", length=4, nullable=true)
     */
    private $keuringseisen;

    /**
     * @var int
     *
     * @ORMOneToMany(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 AppBundleEntity;

use DoctrineORMMapping as ORM;

/**
 * Bestelregel
 *
 * @ORMTable(name="bestelregel")
 * @ORMEntity(repositoryClass="AppBundleRepositoryBestelregelRepository")
 */
class Bestelregel
{
    /**
     * @var int
     *
     * @ORMColumn(name="id", type="integer")
     * @ORMId
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int
     *
     * @ORMManyToOne(targetEntity="Artikel", inversedBy="bestelregels")
     * @ORMJoinColumn(name="artikelnummer", referencedColumnName="artikelnummer")
     */
    private $artikelnummer;

    /**
     * @var int
     *
     * @ORMManyToOne(targetEntity="Artikel", inversedBy="bestelregels")
     * @ORMJoinColumn(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 AppBundleFormType;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;

use SymfonyBridgeDoctrineFormTypeEntityType;
use SymfonyComponentFormExtensionCoreTypeIntegerType;
use SymfonyComponentFormExtensionCoreTypeTextType;


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' => 'AppBundleEntityBestelling'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'appbundle_bestelregel';
    }

}

Form Bestelregel (Link table)

<?php

namespace AppBundleFormType;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;

use SymfonyBridgeDoctrineFormTypeEntityType;
use SymfonyComponentFormExtensionCoreTypeIntegerType;
use SymfonyComponentFormExtensionCoreTypeTextType;

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' => 'AppBundleEntityBestelregel'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'appbundle_bestelregel';
    }


}

Picture Database

Pic Database

Advertisement

Answer

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 AppBundleEntity;

use DoctrineCommonCollectionsArrayCollection;
use DoctrineORMMapping as ORM;

/**
 * @ORMEntity
 * @ORMTable(name="`article`")
 */
class Article
{
    /**
     * @ORMManyToMany(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 AppBundleEntity;

use DoctrineCommonCollectionsArrayCollection;
use DoctrineORMMapping as ORM;

/**
 * @ORMEntity
 * @ORMTable(name="`order`")
 */
class Order
{
    /**
     * @ORMManyToMany(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 AppBundleForm;

use AppBundleEntityArticle;
use AppBundleEntityOrder;
use SymfonyBridgeDoctrineFormTypeEntityType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;

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
        ));
    }
}
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement