2

enter image description hereenter image description hereI have a single form which inserts data in following table:

  • Vendor

    1. first_name
    2. last_name
    3. address
  • address

    1. address
    2. city
    3. state
    4. pincode
    5. country

Note: I have not created address as FK in Vendor table but it does saves the id for address table.

I made this form class by reference of docs: https://symfony.com/doc/current/form/embedded.html

VendorType form class:

class VendorType extends AbstractType {
     public function buildForm(FormBuilderInterface $builder, array $options)  
     {  
         $builder
             ->add('first_name',TextType::class,[
                 'attr' => [
                     'placeholder' => 'Enter First name',
                 ]
             ])  
             ->add('last_name',TextType::class,[
                 'attr' => [
                     'placeholder' => 'Enter Last name'
                 ]
             ])  
             ->add('address',TextAreaType::class,[
                 'attr' => [
                     'placeholder' => 'Enter your current address'
                 ],
                 'mapped' => false,
                 //if given then value wont be fetched for address in entity object.
             ])  
             ->add('city',TextType::class,[
                 'attr' => [
                     'placeholder' => 'Enter city'
                 ]
             ])  
             ->add('state',TextType::class,[
                 'attr' => [
                     'placeholder' => 'Enter state'
                 ]
             ])  
             ->add('country',TextType::class,[
                 'attr' => [
                     'placeholder' => 'Enter country'
                 ]
             ])  
             ->add('pincode',TextType::class,[
                 'attr' => [
                     'placeholder' => 'Enter Pincode'
                 ]
             ])  
             ->add('Save',SubmitType::class,[
                 'attr' => [
                     'class' => 'btn btn-success'
                 ]
             ])  

         ;  
     }  

     public function configureOptions(OptionsResolver $resolver)  
     {  
         $resolver->setDefaults([
             'data_class' => Vendor::class,
         ]);
     }  

Controller:  

$vendor = new Vendor();  
        $manager = $this->getDoctrine()->getManager();  
        $vendorForm = $this->createForm(VendorType::class, $vendor);  

        $vendorForm->handleRequest($request);  

        if ($vendorForm->isSubmitted()) {
            if ($vendorForm->isValid()) {
                $address = new Address;

                $address->setAddress($request->request->get('vendor')['address']);
                $address->setCity($request->request->get('vendor')['city']);
                $address->setState($request->request->get('vendor')['state']);
                $address->setCountry($request->request->get('vendor')['country']);
                $address->setPincode($request->request->get('vendor')['pincode']);


                $manager->persist($address);
                $manager->flush();
                if(null != $address->getId()){

                    $vendor->setFirstName($request->request->get('vendor')['first_name']);

                    $vendor->setLastName($request->request->get('vendor')['last_name']);

                    $vendor->setAddress($address->getId());
                    // dump($ven);
                    // die('uygyu');
                    $manager->persist($vendor);

                    $manager->flush();

                    $this->addFlash('success', 'Article Created! Knowledge is power!');
                }     
            }

Note: Insertion is successful in Address table but data is not inserted into vendor table due following error.

Error message: An exception occurred while executing 'INSERT INTO vendor (first_name, last_name, address, city, state, country, pincode) VALUES (?, ?, ?, ?, ?, ?, ?)' with params ["miss", "Negi", 62, null, null, null, null]:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'city' in 'field list'

How can I submit my form data into their respective tables?

Edit: I understand that vendor object has all the properties so it is not able to execute the query. I want to know how this situation can be solved? What else can be done here? and is there any better way to save such kinds of form?

Address Entity:

namespace App\Entity;


/**
 * @ORM\Entity(repositoryClass="App\Repository\AddressRepository")
 */
class Address
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="text")
     */
    private $address;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $city;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $state;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $country;

    /**
     * @ORM\Column(type="integer")
     */
    private $pincode;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $address_type;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Customer", mappedBy="address")
     */
    private $customers;

    public function __construct()
    {
        $this->customers = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getAddress(): ?string
    {
        return $this->address;
    }

    public function setAddress(string $address): self
    {
        $this->address = $address;

        return $this;
    }

    public function getCity(): ?string
    {
        return $this->city;
    }

    public function setCity(string $city): self
    {
        $this->city = $city;

        return $this;
    }

    public function getState(): ?string
    {
        return $this->state;
    }

    public function setState(string $state): self
    {
        $this->state = $state;

        return $this;
    }

    public function getCountry(): ?string
    {
        return $this->country;
    }

    public function setCountry(string $country): self
    {
        $this->country = $country;

        return $this;
    }

    public function getPincode(): ?int
    {
        return $this->pincode;
    }

    public function setPincode(int $pincode): self
    {
        $this->pincode = $pincode;

        return $this;
    }

    public function getAddressType(): ?string
    {
        return $this->address_type;
    }

    public function setAddressType(string $address_type): self
    {
        $this->address_type = $address_type;

        return $this;
    }

    /**
     * @return Collection|Customer[]
     */
    public function getCustomers(): Collection
    {
        return $this->customers;
    }

    public function addCustomer(Customer $customer): self
    {
        if (!$this->customers->contains($customer)) {
            $this->customers[] = $customer;
            $customer->setAddress($this);
        }

        return $this;
    }

    public function removeCustomer(Customer $customer): self
    {
        if ($this->customers->contains($customer)) {
            $this->customers->removeElement($customer);
            // set the owning side to null (unless already changed)
            if ($customer->getAddress() === $this) {
                $customer->setAddress(null);
            }
        }

        return $this;
    }
}

Vendor Entity:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\VendorRepository")
 */
class Vendor
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $first_name;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $last_name;

   /**
     * @ORM\Column(type="integer")
     */
    private $address;

    /**
     * @ORM\Column(type="string", length=255)
     */
    public $city;

    /**
     * @ORM\Column(type="string", length=255)
     */
    public $state;

    /**
     * @ORM\Column(type="string", length=255)
     */
    public $country;

    /**
     * @ORM\Column(type="integer", length=255)
     */
    public $pincode;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getFirstName(): ?string
    {
        return $this->first_name;
    }

    public function setFirstName(string $first_name): self
    {
        $this->first_name = $first_name;

        return $this;
    }

    public function getLastName(): ?string
    {
        return $this->last_name;
    }

    public function setLastName(string $last_name): self
    {
        $this->last_name = $last_name;

        return $this;
    }

    public function getAddress(): ?int
    {
        return $this->address;
    }

    public function setAddress(int $address): self
    {
        $this->address = $address;

        return $this;
    }

    public function getCity(): ?string
    {
        return $this->city;
    }

    public function getState(): ?string
    {
        return $this->state;
    }

    public function getCountry(): ?string
    {
        return $this->country;
    }

    public function getPincode(): ?int
    {
        return $this->pincode;
    }
}
Saurabh
  • 432
  • 1
  • 10
  • 23
  • can you post full error message from MySQL query? Did you try to insert directly one record into MySQL to see what happens? – Nikola Kirincic Mar 13 '19 at 05:57
  • @niklaz : I have updated the error message, please check. The data is inserted into address table but not in Vendor table. – Saurabh Mar 13 '19 at 06:00
  • bin/console doctrine:schema:update (if you are aware of what you are doing use --force) your database seems not up to date with doctrine entities. – Vytenis Ščiukas Mar 13 '19 at 06:15
  • @vytsci: If I perform bin/console d:s:u --force then this will change my vendor table. city, address, country, pincode columns will be added into it. I don't want that. I want first_name, last_name, address's id to get saved in vendor table and rest dta to be inserted into address table. – Saurabh Mar 13 '19 at 06:24
  • @Saurabh that means you have wrong doctrine mapping and you should start there. doctrine:schema:validate may help you in his way, but doctrine entities must work correctly. – Vytenis Ščiukas Mar 13 '19 at 06:30
  • Are these tables not related. Also your `address` fields in each table are different datatype. So either that is a poor design or you messed something up there. one is long text the other is an int. I would think if they are related you could build the whole object tree and persist it as a whole to the DB, that way you have transitional protection; instead of persisting them separately. It looks like in the first table you should name `address` to `street` as it could be confusing calling two like methods with different datatypes. Just my thoughts. – ArtisticPhoenix Mar 13 '19 at 06:33
  • @vytsci: running doctrine:schema:validate gives "[Mapping] FAIL - The entity-class 'App\Entity\Address' mapping is invalid: * The association App\Entity\Address#customers refers to the owning side field App\Entity\Customer#address which does not exist. [Database] FAIL - The database schema is not in sync with the current mapping file. " – Saurabh Mar 13 '19 at 06:35
  • @ArtisticPhoenix: Is it compulsory/ necessary to make relation between both tables? I have address field in address table to save full line address while address field in vendor save address id of address table. – Saurabh Mar 13 '19 at 06:39
  • @Saurabh well, your mapping is messed up. First of all, please properly develop your entities and when you do this see if the problem persists and let us know. – Vytenis Ščiukas Mar 13 '19 at 06:41
  • As I said it would be very easy to confuse the two as they are named the same, it's just a bad practice IMO. In any case I haven't used Doctrine in a while. its probably been about 3 years...lol I guess this says it all `Note: I have not created address as FK in Vendor table but it does saves the id for address table.` You might want to. An Address can belong to Many Vendors, Vendors can have one address. So the vendor needs the FK unless you want them to have multiple addresses, then you need a Many to Many relationship. – ArtisticPhoenix Mar 13 '19 at 06:42
  • please update your questions with the entities Vendor and Address as well. – Jakumi Mar 13 '19 at 06:42
  • I find it much easier to think about if you actually say "An Address can belong to Many Vendors" and "Vendors can have one address" - then you know you need a way to store the id in the Vendors as they can have only one address or one KEY in the FK field, the address ID can be in many rows in the Vendor table etc. `@ArtisticPhoenix: Is it compulsory/ necessary to make relation between both tables` That's kind of the point of an ORM, I don't think you are forced to but you loose things Like transactions, that protect against one table inserting and the related one failing etc. – ArtisticPhoenix Mar 13 '19 at 06:47
  • Having an Address belong to many vendors *appears* to be sensible, but actually causes some weird problems, because what happens when one of those vendors moves? you must take extra precaution not to move all vendors. This *might* appear obvious, but you have to remember that when you introduce that feature. In the end, I'm not convinced in this case a shared address entity is really what someone would want. Just my two cents. Working with DTOs might help, but in the end it just produces more logic, more code without (in this case) any gain. – Jakumi Mar 13 '19 at 06:53
  • @Jakumi: I have updated the question with entities, please3 have a look. – Saurabh Mar 13 '19 at 06:54
  • @ArtisticPhoenix: I am going to implement foreign key with one to one relation as each vendor will have their own address id. As jakumi said, what if there is need to change address of a particular vendor, that might hamper the address of other vendors having same address id. – Saurabh Mar 13 '19 at 07:06
  • Just don't do edits on the table only do inserts and remove orphan addresses. Then before inserting you can just look up the address to see if it exists. If me an you have the same address does it need to be its own record. If I move so I edit my address you can just insert me a new one. If you move, then you get a new one (if they dont exist) if no one owns a given address just remove it. – ArtisticPhoenix Mar 13 '19 at 07:07
  • I have a large DB (with doctrine) of litigation (lawsuits). around 1.2 million participants (plaintiffs, defendants, plaintiff attorneys etc.) with over 200k lawsuits. Thats what I did, I probably have 3 or 4 million addresses as its many to many. participants can have many address and an address can belong to many participants. etc.. Id probably have double that if I didn't normalize it. Besides whats the difference between a one to one, and a single table. Last I checked we were doing about 180 million client searches each day, it's pretty insane. – ArtisticPhoenix Mar 13 '19 at 07:13
  • @ArtisticPhoenix: thanks man, I am new to symfony and doctrine, going to implement the same, hope it works. cheers – Saurabh Mar 13 '19 at 07:21
  • @ArtisticPhoenix I see your point and the gains, of course. And I would argue that each approach has its merits and it depends. But this discussion probably goes too far for this comment section. ^^ – Jakumi Mar 13 '19 at 07:24
  • @Jakumi - I agree. there is also an argument to be made for updating all the addresses. But its so use case oriented its basically theoretical...lol I only mentioned it as it seemed a solution to the update issue. Cheers! – ArtisticPhoenix Mar 13 '19 at 07:40

2 Answers2

0

Error message: An exception occurred while executing 'INSERT INTO vendor (first_name, last_name, address, city, state, country, pincode) VALUES (?, ?, ?, ?, ?, ?, ?)' with params ["miss", "Negi", 62, null, null, null, null]

Check your Getters and Setters. In this case, you have not setter for city property (and something more). Thats why Symfony is not be able to insert those properties in bbdd.

public function getCity(): ?string
{
    return $this->city;
}

public function setCity(string $city): self
{
    $this->city = $city;

    return $this;
}

public function getState(): ?string
{
    return $this->state;
}

public function setState(string $state): self
{
    $this->state = $state;

    return $this;
}

public function getCountry(): ?string
{
    return $this->country;
}

public function setCountry(string $country): self
{
    $this->country = $country;

    return $this;
}

public function getPincode(): ?int
{
    return $this->pincode;
}

public function setPincode(int $pincode): self
{
    $this->pincode = $pincode;

    return $this;
}

One more thing. You have an error in ORM annotation of pincode in ventor entity. It is int and you are specifying length of string.

/**
 * @ORM\Column(type="integer", length=255)
 */
public $pincode;
AythaNzt
  • 1,057
  • 6
  • 14
0

As we can see in provided screenshot, there is only three fields in Vendor table. There is simple error, the form class is not embedded properly, this is not the way to embed one form to another. The concept is to create 2 different form and embed one into another. Here we embed AddressType form class into VendorType form class.

VendorType form class:

class VendorType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('first_name',TextType::class,[
                'attr' => [
                    'placeholder' => 'Enter First name',
                ]
            ])
            ->add('last_name',TextType::class,[
                'attr' => [
                    'placeholder' => 'Enter Last name'
                ]
            ])
            //Embeding AddressType form in VendorType form.
            ->add('address', AddressType::class)
            ->add('Save',SubmitType::class,[
                'attr' => [
                    'class' => 'btn btn-success'
                ]
            ])

        ;
    }

Note: look for the comment into code above.

Saurabh
  • 432
  • 1
  • 10
  • 23