I'm actually creating an api. I'm using vichuploaderBundler to import file and to put them in a specific directory. Since i use my form to send a POST request to create a resource, my ressource get created but the files aren't saved anymore. Here is my current code.
postController
/**
* #Rest\View(statusCode=Response::HTTP_CREATED)
* #Rest\Post("/posts")
*/
public function postPostsAction(Request $request)
{
$post = new Post();
$form = $this->createForm(PostType::class, $post);
$form->submit($request->request->all()); // Validation des données
if ($form->isValid()) {
$post->setUpdatedAt(new \DateTime());
$em = $this->get('doctrine.orm.entity_manager');
$em->persist($post);
$em->flush();
return $post;
} else {
return $form;
}
}
PostType
class PostType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title');
$builder->add('description');
$builder->add('imageName');
$builder->add('imageFile', FileType::class);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Post',
//An API must be stateless, Cross-Site Request Forgery must be disable
'csrf_protection' => false,
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_post';
}
}
The post entity :
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\VirtualProperty;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* Post
* #ORM\Entity(repositoryClass="AppBundle\Repository\PostRepository")
* #ExclusionPolicy("all")
* #Vich\Uploadable
*/
class Post
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Expose
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Title", type="string", length=100)
*/
private $title;
/**
* #var string
* #Expose
* #ORM\Column(name="Description", type="string", length=400, nullable=true)
*/
private $description;
/**
* #var string
* #Expose
* #ORM\Column(name="imageName", type="string", length=255)
*/
private $imageName;
/**
* #ORM\Column(type="datetime")
*
* #var \DateTime
*/
private $updatedAt;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* #Vich\UploadableField(mapping="product_image", fileNameProperty="imageName")
* #var File
*/
private $imageFile;
/**
* 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
* #Expose
* #return Post
*/
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 \DateTimeImmutable();
}
return $this;
}
/**
* #return File|null
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* Set imageName
*
* #param string $imageName
*
* #return Post
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* Get imageName
*
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
*
* #return Post
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* #param \DateTime $updatedAt
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
}
/**
* Set description
*
* #param string $description
*
* #return Post
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
EDIT :
Here is my vichuploader configuration, in config.yml
#vich uploader Configuration
vich_uploader:
db_driver: orm
mappings:
product_image:
uri_prefix: /images/posts
upload_destination: '%kernel.root_dir%/../web/images/posts'
namer: vich_uploader.namer_uniqid
inject_on_load: false
delete_on_update: true
delete_on_remove: true
Before using my form i was uploading on that way :
public function postPostsAction(Request $request)
{
$post = new Post();
$post->setTitle($request->get('title'))
->setDescription($request->get('description'))
->setImageName($request->get('image_name'))
->setImageFile($request->files->get('imageFile'))
// 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
->setUpdatedAt(new \DateTime());
// On fait appel à doctrine pour seter un id lors de la création en base
$em = $this->get('doctrine.orm.entity_manager');
$em->persist($post);
$em->flush();
return $post;
}
Thanks for helping !
Related
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.
Well I'm trying to create a form which can handle multiple file uploads. So far so good. I have two tables image and product which has ManyToOne relationship. I'm using CollecitonType field for the images so I can dynamically add/remove fields on the fly. The problem is that I get this exception on form rendering
Neither the property "imageFile" nor one of the methods "getImageFile()", "imageFile()", "isImageFile()", "hasImageFile()", "__get()" exist and have public access in class "AppBundle\Entity\Product".
What I'm doing wrong?
AppBundle\Entity\Image
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* Product
*
* #ORM\Table()
* #ORM\Entity
*/
class Image
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Product")
*/
protected $product;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* #Vich\UploadableField(mapping="product_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;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* 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)
{
$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 File
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* #param string $imageName
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
}
/**
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
*
* #return Image
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set product
*
* #param \AppBundle\Entity\Product $product
*
* #return Image
*/
public function setProduct(\AppBundle\Entity\Product $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return \AppBundle\Entity\Product
*/
public function getProduct()
{
return $this->product;
}
}
AppBundle\Entity\Product
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection ;
use Doctrine\ORM\Mapping as ORM;
/**
* Product
*
* #ORM\Table()
* #ORM\Entity
*/
class Product
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Product
*/
private $image;
/**
* Constructor
*/
public function __construct()
{
$this->image = new ArrayCollection;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function getImages()
{
return $this->images;
}
public function addImage(ImageInterface $image)
{
if (!$this->images->contains($image)) {
$this->images->add($image);
}
return $this;
}
public function removeImage(ImageInterface $image)
{
$this->images->remove($image);
return $this;
}
public function setImages(Collection $images)
{
$this->images = $images;
}
}
AppBundle\Form\ImageType
..............
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('imageFile', 'file')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Image',
'attr'=> array('novalidate'=>'novalidate')
));
}
.............
AppBundle\Form\ProductType
...........
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('imageFile', 'collection', array(
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'type' => new ImageType(),
'prototype' => true,
'attr' => array(
'class' => 'selection',
),
))
->add('upload', 'submit')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Product',
'attr'=> array('novalidate'=>'novalidate')
));
}
......
First :
In your Product class:
Your variable is named private $image, it should be private $images; with the 'S' for plurial.
Second :
In your product form builder, you ask for a field named ImageFile, but it doesn't exist in Product class (but exists on Image class), it should be images.
i'm trying to make a multiple upload file on an entity with the vlabsmediaBundle.
So i have an advert who can have many images but each can be linked with only one advert.
I followed the tutorial(tuto) of the bundle but get an error.
Here:
Entity Image.php
namespace MDB\PlatformBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Vlabs\MediaBundle\Entity\BaseFile as VlabsFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Image
*
* #ORM\Table()
* #ORM\Entity
*/
class Image extends VlabsFile {
/**
* #var string
*
* #ORM\Column(name="url", type="string", length=255)
*/
private $url;
/**
* #var string
*
* #ORM\Column(name="alt", type="string", length=255)
*/
private $alt;
/**
* #ORM\ManyToOne(targetEntity="MDB\AnnonceBundle\Entity\Annonce", inversedBy="images")
* #ORM\JoinColumn(nullable=true)
*/
private $annonce;
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set url
*
* #param string $url
* #return Image
*/
public function setUrl($url) {
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl() {
return $this->url;
}
/**
* Set alt
*
* #param string $alt
* #return Image
*/
public function setAlt($alt) {
$this->alt = $alt;
return $this;
}
/**
* Get alt
*
* #return string
*/
public function getAlt() {
return $this->alt;
}
public function getAnnonce() {
return $this->annonce;
}
public function setAnnonce($annonce) {
$this->annonce = $annonce;
}
/**
* #var string $path
*
* #ORM\Column(name="path", type="string", length=255)
* #Assert\Image()
*/
private $path;
/**
* Set path
*
* #param string $path
* #return Image
*/
public function setPath($path) {
$this->path = $path;
return $this;
}
/**
/**
* Get path
*
* #return string
*/
public function getPath() {
return $this->path;
}
}
Annonce.php (advert enity)
<?php
namespace MDB\AnnonceBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Vlabs\MediaBundle\Annotation\Vlabs;
/**
* Annonce
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="MDB\AnnonceBundle\Entity\AnnonceRepository")
*/
class Annonce {
public function __construct() {
$this->date = new \Datetime();
$this->categories = new ArrayCollection();
$this->images = new ArrayCollection();
}
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="titre", type="string", length=255)
*/
private $titre;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255)
*/
private $description;
/**
* #ORM\Column(name="date", type="date")
*/
private $date;
/**
* #var float
*
* #ORM\Column(name="prix", type="float")
*/
private $prix;
/**
* #ORM\ManyToOne(targetEntity="MDB\AdresseBundle\Entity\Ville", inversedBy="annonces")
*/
private $ville;
/**
* #ORM\ManyToMany(targetEntity="MDB\AnnonceBundle\Entity\Category", cascade={"persist"})
*/
private $categories;
/**
* #ORM\ManyToMany(targetEntity="MDB\UserBundle\Entity\User")
*
*/
private $wishlist;
/**
* #var boolean
*
* #ORM\Column(name="telAppear", type="boolean")
*/
private $telAppear;
/**
* #ORM\ManyToOne(targetEntity="MDB\UserBundle\Entity\User", inversedBy="annonces")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* #var VlabsFile
* #ORM\OneToMany(targetEntity="MDB\PlatformBundle\Entity\Image", mappedBy="annonce")
* #Vlabs\Media(identifier="image_entity", upload_dir="files/images")
* #Assert\Valid()
*/
private $images;
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set titre
*
* #param string $titre
* #return Annonce
*/
public function setTitre($titre) {
$this->titre = $titre;
return $this;
}
/**
* Get titre
*
* #return string
*/
public function getTitre() {
return $this->titre;
}
/**
* Set description
*
* #param string $description
* #return Annonce
*/
public function setDescription($description) {
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription() {
return $this->description;
}
/**
* Set prix
*
* #param float $prix
* #return Annonce
*/
public function setPrix($prix) {
$this->prix = $prix;
return $this;
}
/**
* Get prix
*
* #return float
*/
public function getPrix() {
return $this->prix;
}
public function addCategory(Category $category) {
// Ici, on utilise l'ArrayCollection vraiment comme un tableau
$this->categories[] = $category;
return $this;
}
public function removeCategory(Category $category) {
$this->categories->removeElement($category);
}
public function getCategories() {
return $this->categories;
}
public function getDate() {
return $this->date;
}
public function setDate($date) {
$this->date = $date;
}
public function getWishlist() {
return $this->wishlist;
}
public function setWishlist($wishlist) {
$this->wishlist = $wishlist;
}
public function getVille() {
return $this->ville;
}
public function setVille($ville) {
$this->ville = $ville;
}
public function getTelAppear() {
return $this->telAppear;
}
public function setTelAppear($telAppear) {
$this->telAppear = $telAppear;
}
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
}
public function addImage(Image $image) {
$this->images[] = $image;
$image->setUser($this);
return $this;
}
public function removeImage(Image $image) {
$this->images->removeElement($image);
}
public function getImages() {
return $this->images;
}
}
config.yml
vlabs_media:
image_cache:
cache_dir: files/c
mapping:
image_entity:
class: MDB\PlatformBundle\Entity\Image
AnnonceSellType.php
<?php
namespace MDB\AnnonceBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use MDB\PlatformBundle\Form\ImageType;
class AnnonceSellType extends AbstractType {
private $arrayListCat;
public function __construct( $arrayListCat)
{
$this->arrayListCat = $arrayListCat;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->remove('wishlist')
->remove('date')
->remove('images')
->add('titre')
->add('description', 'textarea')
->add('prix')
->add('categories', 'choice', array(
'choices' => $this->arrayListCat,
'multiple' => true,
'mapped'=>false,
))
//->add('images', 'collection', array('type' => new ImageType()))
->add('image', 'vlabs_file', array(
'required' => false
))
;
}
/**
* #return string
*/
public function getName() {
return 'mdb_annoncebundle_annonce_sell';
}
public function getParent() {
return new AnnonceType();
}
}
And i have the following error : Catchable Fatal Error: Argument 1 passed to Vlabs\MediaBundle\EventListener\BaseFileListener::preSetData() must be an instance of Symfony\Component\Form\Event\DataEvent, instance of Symfony\Component\Form\FormEvent given in C:\wamp\www\Mdb\vendor\vlabs\media-bundle\Vlabs\MediaBundle\EventListener\BaseFileListener.php line 59
i tried to change this line :
->add('image', 'vlabs_file', array(
'required' => false
))
with :
->add('images', 'collection', array('type' => 'vlabs_file'))
but i just have the image label who appear in this case
if someone have an idea ?
I was a little bit investigating about your problem and Vlabs Media Bundle seems to be unmaintained. There is form listener on PRE_SET_DATA event (Vlabs\MediaBundle\EventListener\BaseFileListener::preSetData()) that is not compatible with new version of Symfony (it expects DataEvent as parametr instead FormEvent). They fixed it but after 1.1.1 release (you can compare dates from links). If really wanna give a try, change composer.json and run composer update. I can't guarantee there will not be another possible issues.
composer.json
"vlabs/media-bundle": "dev-master"
Library update
composer update vlabs/media-bundle
Experiencing some serious problems in getting a OneToMany relationship to work. The error happens when trying to add "Children" to Beauties in Sonata Admin.
Using:
Symfony2
Doctrine
Sonata Admin
Been trying to follow the guide at: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional
and
http://sonata-project.org/bundles/doctrine-orm-admin/2-2/doc/reference/form_field_definition.html
Error:
"CRITICAL - Uncaught PHP Exception
Doctrine\ORM\ORMInvalidArgumentException: "A new entity was found
through the relationship
'Beautify\BeautiesBundle\Entity\Beauty#children' that was not
configured to cascade persist operations for entity:
Beautify\BeautiesBundle\Entity\Children#000000000eff91d5000000017f8ca53b.
To solve this issue: Either explicitly call EntityManager#persist() on
this unknown entity or configure cascade persist this association in
the mapping for example #ManyToOne(..,cascade={"persist"}). If you
cannot find out which entity causes the problem implement
'Beautify\BeautiesBundle\Entity\Children#__toString()' to get a clue."
at
/Users/gmf/symfony/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php
line 91 "
.
.
BeautyAdmin.php
<?php
// src/Beautify/BeautiesBundle/Admin/BeautyAdmin.php
namespace Beautify\BeautiesBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Beautify\CategoryBundle\Entity\Category;
use Beautify\CategoryBundle\Entity\Children;
class BeautyAdmin extends Admin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('General')
->add('name', 'text', array('label' => 'Name'))
->add('content', 'textarea', array('label' => 'Content'))
->add('imageFile', 'file', array('label' => 'Image file', 'required' => false))
->end()
->with('Category')
->add('category', 'sonata_type_model', array('expanded' => true))
->end()
->with('Children')
->add('children', 'sonata_type_collection', array(), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
->end()
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('name')
->add('content')
->add('category')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('content')
->add('category')
->add('imageName')
->add('_action', 'actions', array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
)
))
;
}
}
Beauty.php Entity
<?php
// src/Beautify/BeautiesBundle/Entity/Beauty.php
namespace Beautify\BeautiesBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="beauties")
* #ORM\HasLifecycleCallbacks
* #Vich\Uploadable
*/
class Beauty
{
/**
* #ORM\OneToMany(targetEntity="Children", mappedBy="beauties")
**/
private $children;
public function __construct()
{
$this->children = new ArrayCollection();
}
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=100)
*/
protected $name;
/**
* #ORM\Column(type="text")
*/
protected $content;
/**
* #Vich\UploadableField(mapping="beauty_image", fileNameProperty="imageName")
* #var File $imageFile
*/
protected $imageFile;
/**
* #ORM\Column(type="string", length=255, nullable=true, name="image_name")
* #var string $imageName
*/
protected $imageName;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="beauties")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
/**
* 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
*/
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 File
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* #param string $imageName
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
}
/**
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
public function __toString()
{
return ($this->getName()) ? : '';
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Beauty
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set content
*
* #param string $content
* #return Beauty
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set category
*
* #param \Beautify\BeautiesBundle\Entity\Category $category
* #return Beauty
*/
public function setCategory(\Beautify\BeautiesBundle\Entity\Category $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \Beautify\BeautiesBundle\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
/**
* Set children
*
* #param \Beautify\BeautiesBundle\Entity\Children $children
* #return Beauty
*/
public function setChildren(\Beautify\BeautiesBundle\Entity\Children $children = null)
{
$this->children = $children;
return $this;
}
/**
* Get children
*
* #return \Beautify\BeautiesBundle\Entity\Children
*/
public function getChildren()
{
return $this->children;
}
/**
* Add children
*
* #param \Beautify\BeautiesBundle\Entity\Children $children
* #return Beauty
*/
public function addChild(\Beautify\BeautiesBundle\Entity\Children $children)
{
$this->children[] = $children;
return $this;
}
/**
* Remove children
*
* #param \Beautify\BeautiesBundle\Entity\Children $children
*/
public function removeChild(\Beautify\BeautiesBundle\Entity\Children $children)
{
$this->children->removeElement($children);
}
}
Children.php Entity
<?php
namespace Beautify\BeautiesBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Children
*
* #ORM\Table(name="children")
* #ORM\Entity
*/
class Children
{
/**
* #ORM\ManyToOne(targetEntity="Beauty", inversedBy="children")
* #ORM\JoinColumn(name="beauty_id", referencedColumnName="id")
**/
private $beauties;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="image", type="string", length=255)
*/
private $image;
/**
* #var string
*
* #ORM\Column(name="content", type="text")
*/
private $content;
/**
* #var integer
*
* #ORM\Column(name="priority", type="integer")
*/
private $priority;
/**
* #var integer
*
* #ORM\Column(name="parent_id", type="integer")
*/
private $parentId;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set image
*
* #param string $image
* #return Children
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string
*/
public function getImage()
{
return $this->image;
}
/**
* Set content
*
* #param string $content
* #return Children
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set priority
*
* #param integer $priority
* #return Children
*/
public function setPriority($priority)
{
$this->priority = $priority;
return $this;
}
/**
* Get priority
*
* #return integer
*/
public function getPriority()
{
return $this->priority;
}
/**
* Set parentId
*
* #param integer $parentId
* #return Children
*/
public function setParentId($parentId)
{
$this->parentId = $parentId;
return $this;
}
/**
* Get parentId
*
* #return integer
*/
public function getParentId()
{
return $this->parentId;
}
/**
* Set beauties
*
* #param \Beautify\BeautiesBundle\Entity\Beauty $beauties
* #return Children
*/
public function setBeauties(\Beautify\BeautiesBundle\Entity\Beauty $beauties = null)
{
$this->beauties = $beauties;
return $this;
}
/**
* Get beauties
*
* #return \Beautify\BeautiesBundle\Entity\Beauty
*/
public function getBeauties()
{
return $this->beauties;
}
}
Very thankful for any help...
The error says it all. You need to add cascade="persist" to the children property.
/**
* #ORM\OneToMany(targetEntity="Children", mappedBy="beauties", cascade={"persist"})
**/
private $children;
See http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations
I'm trying to do file upload for my Task entity. I working with two sources:
http://symfony.com/doc/3.4/controller/upload_file.html and Symfony2 file upload step by step but I can't figure out how to keep uploaded file during editing.
I'm not sure if I implemented right the part:
My form was complaining when I tried to edit any Task:
The form's view data is expected to be an instance of class
Symfony\Component\HttpFoundation\File\File, but is a(n) string. You
can avoid this error by setting the "data_class" option to null or by
adding a view transformer that transforms a(n) string to an instance
of Symfony\Component\HttpFoundation\File\File.
So I modified getter getBrochure() in my Task entity which I want to expand of PDF file. Please, see below my getBrochure method This is code of my entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
/**
* Task
*
* #ORM\Table(name="task")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TaskRepository")
*/
class Task
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \DateTime
*
* #ORM\Column(name="datetime", type="datetime")
*/
private $datetime;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories_tasks")
*/
private $categories;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\Column(type="string")
*
* #Assert\File(mimeTypes={ "application/pdf" })
*/
private $brochure;
public function __construct() {
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Task
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set datetime
*
* #param \DateTime $datetime
*
* #return Task
*/
public function setDatetime($datetime)
{
$this->datetime = $datetime;
return $this;
}
/**
* Get datetime
*
* #return \DateTime
*/
public function getDatetime()
{
return $this->datetime;
}
public function getCategories()
{
return $this->categories;
}
public function setCategories(Category $categories)
{
$this->categories = $categories;
}
public function getDescription()
{
return $this->description;
}
public function setDescription($description)
{
$this->description = $description;
}
public function getBrochure()
{
//return $this->brochure;
return new File($this->brochure);
}
public function setBrochure($brochure)
{
$this->brochure = $brochure;
return $this;
}
public function __toString() {
return $this->name;
}
}
?>
The result is that I can load edit page, but the field of file upload is empty, there is no information that I uploaded any file. I'm not sure if there should be any information but I see in database that the filename is there and also in web folder there is uploaded file. When I change anything in Task and save of file is cleared and when I try to launch edit page I see:
The file "" does not exis
What is clear for me, because file column for this Task was cleared. So, how to keep file during editing when I don't want to upload new file?
This is my TaskType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Ivory\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class TaskType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name')->add('datetime')->add('categories')
->add('description', 'Ivory\CKEditorBundle\Form\Type\CKEditorType', array())
->add('brochure', FileType::class, array('label' => 'Broszurka (PDF)', 'required' => false));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Task'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_task';
}
}
and this is my TaskController (only edit action)
/**
* Displays a form to edit an existing task entity.
*
* #Route("/{id}/edit", name="task_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Task $task)
{
$deleteForm = $this->createDeleteForm($task);
$editForm = $this->createForm('AppBundle\Form\TaskType', $task);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('task_edit', array('id' => $task->getId()));
}
return $this->render('task/edit.html.twig', array(
'task' => $task,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
Task Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
/**
* Task
*
* #ORM\Table(name="task")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TaskRepository")
*/
class Task
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \DateTime
*
* #ORM\Column(name="datetime", type="datetime")
*/
private $datetime;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories_tasks")
*/
private $categories;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\Column(type="string")
*
* #Assert\File(mimeTypes={ "application/pdf" })
*/
private $brochure;
public function __construct() {
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Task
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set datetime
*
* #param \DateTime $datetime
*
* #return Task
*/
public function setDatetime($datetime)
{
$this->datetime = $datetime;
return $this;
}
/**
* Get datetime
*
* #return \DateTime
*/
public function getDatetime()
{
return $this->datetime;
}
public function getCategories()
{
return $this->categories;
}
public function setCategories(Category $categories)
{
$this->categories = $categories;
}
public function getDescription()
{
return $this->description;
}
public function setDescription($description)
{
$this->description = $description;
}
public function getBrochure()
{
//return $this->brochure;
return new File($this->brochure);
}
public function setBrochure($brochure)
{
$this->brochure = $brochure;
return $this;
}
public function __toString() {
return $this->name;
}
}
?>
You should check the file and then,If the user did not select the file,Select the file name from the database
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$form->handleRequest($request);
$TaskRepo=$em->getRepository('AppBundle:Task');
$Taskdata = $TaskRepo->find($id);///id task
$Taskdata->setName($form->get('name')->getData());
$Taskdata->setDescription($form->get('description(')->getData());
$Taskdata->setDatetime(new \DateTime('now'));
if($form->get('brochure')->getData() != ""){////Check the file selection status
$file2 = $form->get('brochure')->getData();
$fileName2 = md5(uniqid()).'.'.$file2->guessExtension();
$file2->move(
$this->getParameter('brochures_directory'), $fileName2);
$Taskdata->setBrochure($fileName2);
}
$em->flush();
}
OK I found the problem few seconds after I wrote comment and added Task entity code. In getBrochure method I tried to create File object for every Task instance even it hasn't any brochure so the solution is to use:
public function getBrochure()
{
return $this->brochure;
//return new File($this->brochure);
}