I'm using EasyAdminBundle in Symfony 4 and I would like to create a multiple image upload in my form with VichUploaderBundle (or without), but I can't find any updated documentation for Symfony 4, I do not know what to do to make it work.
I created a Photo entity and a Product entity with the relationship many-to-many unidirectional :
Product.php :
<?php
declare(strict_types = 1);
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Product
*
* #package App\Entity
*
* #ORM\Entity
*/
class Product
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", options={"unsigned":true}, nullable=false)
*
* #var int
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Photo", cascade={"persist"})
*
* #var Photo[]|ArrayCollection
*/
protected $photos;
/**
* Product constructor.
*/
public function __construct()
{
$this->photos = new ArrayCollection();
}
Photo.php :
<?php
declare(strict_types = 1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* Photo
*
* #ORM\Entity()
* #Vich\Uploadable
*/
class Photo
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
* #var int
*/
protected $id;
/**
* #ORM\Column(name="name", type="string", length=255)
*
* #var string
*/
protected $name;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
protected $photo;
/**
* #Vich\UploadableField(mapping="photos", fileNameProperty="photo")
*
* #var File
*/
protected $photoFile;
/**
* #ORM\Column(type="datetime", length=255)
*
* #var \DateTime
*/
protected $updatedAt;
/**
* #return int
*/
public function getId(): ?int
{
return $this->id;
}
/**
* #param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* #return string
*/
public function getName(): ?string
{
return $this->name;
}
/**
* #param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* #param File|null $photo
* #return Photo
*/
public function setPhotoFile(File $photo = null)
{
$this->photoFile = $photo;
if ($photo) {
$this->updatedAt = new \DateTime('now');
}
return $this;
}
/**
* #return File
*/
public function getPhotoFile() : ?File
{
return $this->photoFile;
}
/**
* #param string $photo
* #return Photo
*/
public function setPhoto($photo)
{
$this->photo = $photo;
return $this;
}
/**
* #return string
*/
public function getPhoto() : ?string
{
return $this->photo;
}
}
The vich_uploader.yaml file :
vich_uploader:
db_driver: orm
mappings:
photos:
uri_prefix: "/products/"
upload_destination: '%kernel.root_dir%/../public/build/images/products/'
namer: vich_uploader.namer_uniqid
easy_admin.yaml :
easy_admin:
entities:
Product:
class: App\Entity\Product
form:
fields:
- { property: 'photos', type: 'collection', type_options: { entry_type: 'App\Form\PhotoType' } }
PhotoType.php :
<?php
declare(strict_types = 1);
namespace App\Form;
use App\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
/**
* Class PhotoType
*
* #package App\Form
*/
class PhotoType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('photos', CollectionType::class, ['entry_type' => VichFileType::class])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Photo::class,
]);
}
}
Related
Following the symfony documentation I am trying to embed a collection to a form. But when sending a post request to my endpoint the embedded form with the People collection stays empty.
My entities:
user.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* User
*
* #ORM\Entity
* #UniqueEntity(fields="email", message="Email already taken")
* #ORM\HasLifecycleCallbacks()
*/
class User implements UserInterface
{
use Mapping\UserTrait;
/**
* #param Person $person
*/
public function addPeople(Person $person)
{
$this->people->add($person);
$person->setOwner($this);
}
/**
* #param Person $person
*/
public function removePeople(Person $person)
{
$this->people->removeElement($person);
}
}
UserTrait.php
<?php
namespace App\Entity\Mapping;
use App\Entity\Person;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* #ORM\Table()
*/
trait UserTrait
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="hash", type="string")
*/
private $hash;
/**
* #var bool
*
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
/**
* #var \DateTime
*
* #ORM\Column(name="updated_at", type="datetime")
*/
private $updatedAt;
/**
* #var \DateTime
*
* #ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* #var string
* #ORM\Column(name="email", type="string")
* #Assert\NotBlank
* #Assert\Email
*/
private $email;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\OneToMany(targetEntity="App\Entity\Person", mappedBy="owner", cascade={"persist"})
*/
private $people;
/**
* #var string
* #Assert\NotBlank
* #Assert\Length(max=4096)
*/
private $plainPassword;
/**
* Constructor
*/
public function __construct()
{
$this->people = new ArrayCollection();
$this->roles = ['ROLE_USER'];
$this->isActive = 1;
}
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* #return bool
*/
public function isActive(): bool
{
return $this->isActive;
}
/**
* #param bool $isActive
*/
public function setIsActive(bool $isActive): void
{
$this->isActive = $isActive;
}
/**
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* #param string $email
*/
public function setEmail(string $email): void
{
$this->email = $email;
}
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getPeople(): \Doctrine\Common\Collections\Collection
{
return $this->people;
}
/**
* #param \Doctrine\Common\Collections\Collection $people
*/
public function setPeople(\Doctrine\Common\Collections\Collection $people): void
{
$this->people = $people;
}
/**
* #return string
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* #param string $plainPassword
*/
public function setPlainPassword(string $plainPassword): void
{
$this->plainPassword = $plainPassword;
}
/**
* Implementation of UserInterface: Get password hash.
* #return string
*/
public function getPassword()
{
return $this->hash;
}
/**
* Implementation of UserInterface
*/
public function eraseCredentials()
{
$this->plainPassword = null;
}
/**
* Implementation of UserInterface
*/
public function getUsername()
{
return $this->email;
}
public function getSalt()
{
return null;
}
public function getRoles()
{
return ["User"];
}
/**
* #return string
*/
public function getHash(): string
{
return $this->hash;
}
/**
* #param string $hash
*/
public function setHash(string $hash): void
{
$this->hash = $hash;
}
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updatedTimestamps(): void
{
$dateTimeNow = new \DateTime('now');
$this->setUpdatedAt($dateTimeNow);
if ($this->getCreatedAt() === null) {
$this->setCreatedAt($dateTimeNow);
}
}
/**
* #return \DateTime
*/
public function getUpdatedAt(): \DateTime
{
return $this->updatedAt;
}
/**
* #param \DateTime $updatedAt
*/
public function setUpdatedAt(\DateTime $updatedAt): void
{
$this->updatedAt = $updatedAt;
}
/**
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* #param \DateTime $createdAt
*/
public function setCreatedAt(\DateTime $createdAt): void
{
$this->createdAt = $createdAt;
}
}
Person.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Person
*
* #ORM\Entity
*/
class Person
{
use Mapping\PersonTrait;
}
PersonTrait.php
<?php
namespace App\Entity\Mapping;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Person
*
* #ORM\Table()
*/
trait PersonTrait
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="family_name", type="string")
* #Assert\NotBlank
*/
private $familyName;
/**
* #var string
*
* #ORM\Column(name="given_name", type="string")
* #Assert\NotBlank
*/
private $givenName;
/**
* #var string
*
* #ORM\Column(name="title", type="string")
*/
private $title;
/**
* #var \DateTime
*
* #ORM\Column(name="birth_date", type="datetime")
*/
private $birthDate;
/**
* #var string
*
* #ORM\Column(name="salutation", type="string")
*/
private $salutation;
/**
* #var string
*
* #ORM\Column(name="gender", type="string")
*/
private $gender;
/**
* #var \App\Entity\User
*
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="people")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="owner_id", referencedColumnName="id")
* })
*/
private $owner;
/**
* #return string
*/
public function getFamilyName()
{
return $this->familyName;
}
/**
* #param string $familyName
*/
public function setFamilyName($familyName)
{
var_dump($familyName);
$this->familyName = $familyName;
}
/**
* #return string
*/
public function getGivenName()
{
return $this->givenName;
}
/**
* #param string $givenName
*/
public function setGivenName($givenName)
{
$this->givenName = $givenName;
}
/**
* #return string
*/
public function getTitle(): string
{
return $this->title;
}
/**
* #param string $title
*/
public function setTitle(string $title): void
{
$this->title = $title;
}
/**
* #return \DateTime
*/
public function getBirthDate(): \DateTime
{
return $this->birthDate;
}
/**
* #param \DateTime $birthDate
*/
public function setBirthDate(\DateTime $birthDate): void
{
$this->birthDate = $birthDate;
}
/**
* #return string
*/
public function getSalutation(): string
{
return $this->salutation;
}
/**
* #param string $salutation
*/
public function setSalutation(string $salutation): void
{
$this->salutation = $salutation;
}
/**
* #return string
*/
public function getGender(): string
{
return $this->gender;
}
/**
* #param string $gender
*/
public function setGender(string $gender): void
{
$this->gender = $gender;
}
/**
* #return \App\Entity\User
*/
public function getOwner(): \App\Entity\User
{
return $this->owner;
}
/**
* #param \App\Entity\User $owner
*/
public function setOwner(\App\Entity\User $owner): void
{
$this->owner = $owner;
}
}
Now to my form types:
UserType.php
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class)
->add('plainPassword', PasswordType::class)
->add(
"people",
CollectionType::class,
[
'entry_type' => PersonType::class,
'allow_add' => true,
'by_reference' => false,
]
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => User::class,
'csrf_protection' => false
]
);
}
}
PersonType.php
<?php
namespace App\Form;
use App\Entity\Person;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PersonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('familyName', TextType::class)
->add('givenName', TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => Person::class,
'csrf_protection' => false,
]
);
}
}
Using this Types I am now trying to register a user and create a Person and add it to the user using this code:
/**
* #Route("/register")
* #param Request $request
* #param UserPasswordEncoderInterface $passwordEncoder
*/
public function register(Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->submit($request->request->all());
if ($form->isSubmitted() && $form->isValid()) {
$password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
$user->setHash($password);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
return new Response("ok", 300);
}
return new Response("not ok", 500);
}
My problem now is that when I send a post request with postman with following parameters and content:
email: test#test.de
plainPassword: test1234
people.familyName: testLastname
people.givenName: testFirstname
I get the following error which means that it does not recognize the data for the person entity
"This form should not contain extra fields."
How do I make symfony forms to recognize that people.givenName and people.familyName are meant to create a instance of Person
Edit: comment by u_mulder suggested to change the post body to person[0].givenName and now I am getting the error message
This value is not valid.
I had two problems which had to be fixed. First hint from u_mulder was that I have to use the index for people since its a collection. So instead of
people["givenName"]
I had to use
people[0]["givenName"]
Second mistake was that the structure of the postman body was wrong. Instead of
people[0]["givenName"]
I had to remove the quotes.
people[0][givenName]
After fixing both problems the forms work as expected.
I have an entity "FicheProduit" in relation OneToMany with my entity "Photo" because a product sheet can have several photos. In my form, I would like to create a multiple upload via VichUploaderBundle but I get this error :
Too few arguments to function Vich\UploaderBundle\Form\Type\VichImageType::__construct(), 0 passed in C:\wamp64\www\blh_wines\vendor\symfony\form\FormRegistry.php on line 92 and at least 3 expected
FicheProduit.php :
<?php
declare(strict_types = 1);
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class FicheProduit
*
* #package App\Entity
*
* #ORM\Entity
*/
class FicheProduit
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", options={"unsigned":true}, nullable=false)
*
* #var int
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="Photo", mappedBy="ficheProduit", cascade={"persist"})
*
* #Assert\Valid()
*
* #var Photo[]|ArrayCollection
*/
protected $photos;
/**
* FicheProduit constructor.
*/
public function __construct()
{
$this->photos = new ArrayCollection();
}
/**
* #return int
*/
public function getId(): ?int
{
return $this->id;
}
/**
* #param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* #return Photo[]|ArrayCollection
*/
public function getPhotos()
{
return $this->photos;
}
/**
* #param Photo[]|ArrayCollection $photos
*/
public function setPhotos($photos): void
{
$this->photos = $photos;
}
/**
* Add photo
*
* #param Photo $photo
*
* #return FicheProduit
*/
public function addPhoto(Photo $photo)
{
$photo->setProduct($this);
$this->photos[] = $photo;
return $this;
}
/**
* Remove photo
*
* #param Photo $photo
*/
public function removePhoto(Photo $photo)
{
$this->photos->removeElement($photo);
}
}
Photo.php
<?php
declare(strict_types = 1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity
* #Vich\Uploadable
*/
class Photo
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Vich\UploadableField(mapping="fiche_produit_photo", fileNameProperty="imageName", size="imageSize")
*
* #var File
*/
protected $imageFile;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
protected $imageName;
/**
* #ORM\Column(type="integer")
*
* #var integer
*/
protected $imageSize;
/**
* #ORM\Column(type="datetime")
*
* #var \DateTime
*/
protected $updatedAt;
/**
* #ORM\ManyToOne(targetEntity="FicheProduit", inversedBy="photos")
*/
protected $ficheProduit;
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*/
public function setImageFile(?File $image = null): void
{
$this->imageFile = $image;
if (null !== $image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTimeImmutable();
}
}
/**
* #return null|File
*/
public function getImageFile(): ?File
{
return $this->imageFile;
}
/**
* #param null|string $imageName
*/
public function setImageName(?string $imageName): void
{
$this->imageName = $imageName;
}
/**
* #return null|string
*/
public function getImageName(): ?string
{
return $this->imageName;
}
/**
* #param int|null $imageSize
*/
public function setImageSize(?int $imageSize): void
{
$this->imageSize = $imageSize;
}
/**
* #return int|null
*/
public function getImageSize(): ?int
{
return $this->imageSize;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* #return \DateTime
*/
public function getUpdatedAt(): ?\DateTime
{
return $this->updatedAt;
}
/**
* #param \DateTime $updatedAt
*/
public function setUpdatedAt(\DateTime $updatedAt): void
{
$this->updatedAt = $updatedAt;
}
/**
* #return mixed
*/
public function getFicheProduit()
{
return $this->ficheProduit;
}
/**
* #param mixed $ficheProduit
*/
public function setFicheProduit($ficheProduit): void
{
$this->ficheProduit = $ficheProduit;
}
}
vich_uploader.yaml :
vich_uploader:
db_driver: orm
mappings:
fiche_produit_photo:
uri_prefix: /images/products
upload_destination: '%kernel.project_dir%/public/images/products'
inject_on_load: false
delete_on_update: true
delete_on_remove: true
easy_admin.yaml :
easy_admin:
entities:
FicheProduit:
class: App\Entity\FicheProduit
list:
title: 'Fiche produit'
form:
title: 'Ajouter une fiche produit'
fields:
- { property: 'photos', type: 'collection', type_options: { entry_type: 'App\Form\PhotoType', by_reference: false }}
PhotoType.php :
<?php
declare(strict_types = 1);
namespace App\Form;
use App\Entity\Photo;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichImageType;
/**
* Class PhotoType
*
* #package App\Form
*/
class PhotoType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('imageName')
->add('imageFile', VichImageType::class, [
'required' => false,
'allow_delete' => true,
'download_label' => '...',
'download_uri' => true,
'image_uri' => true,
'imagine_pattern' => '...',
])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Photo::class,
]);
}
}
I tried to replace this:
->add('imageFile', VichImageType::class, [
'required' => false,
'allow_delete' => true,
'download_label' => '...',
'download_uri' => true,
'image_uri' => true,
'imagine_pattern' => '...',
])
By this :
->add('imageFile', CollectionType::class, ['entry_type' => VichImageType::class])
I have no more errors, but my file input isn't displayed and I have a "0" next to it.
I followed this documentation but it did not help me much :
https://github.com/dustin10/VichUploaderBundle/blob/master/Resources/doc/form/vich_image_type.md
https://github.com/dustin10/VichUploaderBundle/blob/master/Resources/doc/usage.md
Well i never used EasyAdmin myself but I think you need an admin definition for the Photo entity:
easy_admin:
entities:
Photo:
# ...
form:
fields:
- { property: 'imageFile', type: 'vich_image' }
I think you don't need the PhotoType formType for the EasyAdmin interface.
If you follow this tutorial: https://symfony.com/doc/master/bundles/EasyAdminBundle/integration/vichuploaderbundle.html#uploading-the-images-in-the-edit-and-new-views
You will see there is no FormType in the example.
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").
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()
));
}
I'm using VichUploader in my Symfony2.3 application. I created one to one relationship between my Post entity and Image entity and I'm using Data Transformer for adding images through Post Form. Everything is working well, I'm getting no exception but post_id is not saved in Image table in database. Probably because of that every image I want to post is broken.
I would appreciate any help!
Image entity:
namespace BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* Class Image.
*
* #package Model
* #author Monika Malinowska
*
* #ORM\Table(name="images")
* #ORM\Entity(repositoryClass="BlogBundle\Repository\Image")
* #Vich\Uploadable
*/
class Image
{
/**
* #ORM\Id
* #ORM\Column(
* type="integer",
* nullable=false,
* options={
* "unsigned" = true
* }
* )
* #ORM\GeneratedValue(strategy="IDENTITY")
* #var integer $id
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Post", inversedBy="image")
* #ORM\JoinColumn(name="post_id", referencedColumnName="id")
*/
protected $post;
/**
*
* #Vich\UploadableField(mapping="image", fileNameProperty="imageName")
*
* #var File
*/
private $imageFile;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
private $imageName;
/**
* #ORM\Column(type="datetime")
*
* #var \DateTime
*/
private $updatedAt;
/**
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*
* #return Image
*/
public function __construct()
{
$this->updatedAt= new \DateTime();
}
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTime('now');
}
return $this;
}
/**
* #return File
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* #param string $imageName
*
* #return Image
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
/**
* Set Id.
*
* #param integer $id Id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get Id.
*
* #return integer Result
*/
public function getId()
{
return $this->id;
}
/**
* Set Post.
*
* #param integer $post Post
*/
public function setPost($post)
{
$this->post = $post;
}
/**
* Get Post.
*
* #return integer Result
*/
public function getPost()
{
return $this->post;
}}
Post Entity:
namespace BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Class Post.
*
* #package Model
*
* #ORM\Table(name="posts")
* #ORM\Entity(repositoryClass="BlogBundle\Repository\Post")
*/
class Post
{
/**
* #ORM\Id
* #ORM\Column(
* type="integer",
* nullable=false,
* options={
* "unsigned" = true
* }
* )
* #ORM\GeneratedValue(strategy="IDENTITY")
* #var integer $id
*/
private $id;
...
/**
* #ORM\OneToOne(targetEntity="Image", mappedBy="post")
*/
protected $image;
/**
* Get Id.
*
* #return integer Result
*/
public function getId()
{
return $this->id;
}
/**
* Set Id.
*
* #param integer $id Id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Set image.
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
* #return $image
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image.
*
* #return file Image
*/
public function getImage()
{
return $this->image;
}
/**
* Add images.
*
* #param \BlogBundle\Entity\Image $image
* #return Image
*/
public function addImage(\BlogBundle\Entity\Image $image)
{
$this->image = $image;
$image->setImage($this);
return $this;
}
/**
* Remove image
*
* #param \BlogBundle\Entity\Image $image
*/
public function removeImage(\BlogBundle\Entity\Image $image)
{
$this->$image->removeElement($image);
$image->setImage(null);
}
ImageType
namespace BlogBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Form\Type\VichImageType;
/**
* Class ImageType.
*
* #package BlogBundle\Form
*/
class ImageType extends AbstractType
{
/**
* Form builder.
*
* #param FormBuilderInterface $builder Form builder
* #param array $options Form options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'id',
'hidden'
);
if (isset($options['validation_groups'])
&& count($options['validation_groups'])
&& !in_array('image-delete', $options['validation_groups'])
) {
// $builder->add('name', 'file', array('label' => 'Obrazek (format JPG)'));
//$builder->add('name', 'text');
$builder->add('imageFile', 'vich_image');
}
$builder->add(
'save',
'submit',
array(
'label' => 'Save'
)
);
}
/**
* Sets default options for form.
*
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'BlogBundle\Entity\Image',
'validation_groups' => 'image-default',
)
);
}
/**
* Getter for form name.
*
* #return string Form name
*/
public function getName()
{
return 'image_form';
}
}
PostType
namespace BlogBundle\Form;
use BlogBundle\Form\DataTransformer\TagDataTransformer;
use BlogBundle\Form\DataTransformer\ImageDataTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\HttpFoundation\File\File;
use BlogBundle\Form\ImageType;
/**
* Class PostType.
*
* #package BlogBundle\Form
*/
class PostType extends AbstractType
{
/**
* Form builder.
*
* #param FormBuilderInterface $builder Form builder
* #param array $options Form options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$imageDataTransformer = new ImageDataTransformer($options['image_model']);
$builder->add(
'id',
'hidden'
);
if (isset($options['validation_groups'])
&& count($options['validation_groups'])
&& !in_array('post-delete', $options['validation_groups'])
) {
...
$builder->add(
$builder
->create('image', 'file')
->addModelTransformer($imageDataTransformer)
);
}
$builder->add(
'save',
'submit',
array(
'label' => 'form.save'
)
);
}
/**
* Sets default options for form.
*
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'BlogBundle\Entity\Post',
'validation_groups' => 'post-default',
)
);
$resolver->setRequired(array('image_model'));
$resolver->setAllowedTypes(
array(
'image_model' => 'Doctrine\Common\Persistence\ObjectRepository'
)
);
}
/**
* Getter for form name.
*
* #return string Form name
*/
public function getName()
{
return 'post_form';
}
}
config.yml
vich_uploader:
db_driver: orm
mappings:
image:
uri_prefix: /assetic/images
upload_destination: '%kernel.root_dir%/../web/assetic/images'
namer: vich_uploader.namer_uniqid
inject_on_load: false
delete_on_update: true
delete_on_remove: true
You don't need any data transformer, but you should use 'vich_image' type instead of 'file' type.
Add cascade={"persist"} option to oneToOne annotation in your Post entity.