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.
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.
I have an Entity containing Self-Referenced mapping. I would like to add new categories and subcategories to the systems but I do not know how to build the add form correctly. Gets are generated and setters are generated in Entity. I'm getting an error:
Neither the property "parent" nor one of the methods
"addParent()"/"removeParent()", "setParent()", "parent()", "__set()"
or "__call()" exist and have public access in class
"Adevo\ClassifiedsBundle\Entity\ClassifiedsCategory".
namespace XXX\ClassifiedsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="XXX\ClassifiedsBundle\Repository\ClassifiedsCategoryRepository")
* #ORM\Table(name="classifieds_categories")
*/
class ClassifiedsCategory extends ClassifiedsAbstractTaxonomy {
/**
* #ORM\OneToMany(
* targetEntity = "Classifieds",
* mappedBy = "category"
* )
*/
protected $classifieds;
/**
* #ORM\ManyToMany(targetEntity="ClassifiedsCategory", mappedBy="parent")
*/
private $children;
/**
*
* #ORM\ManyToMany(targetEntity="ClassifiedsCategory", inversedBy="children")
* #ORM\JoinTable(name="subCategory",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="parent_id", referencedColumnName="id")}
* )
*/
private $parent;
/**
* Constructor
*/
public function __construct() {
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
$this->parent = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add classified
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classified
*
* #return ClassifiedsCategory
*/
public function addClassified(\XXX\ClassifiedsBundle\Entity\Classifieds $classified) {
$this->classifieds[] = $classified;
return $this;
}
/**
* Remove classified
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classified
*/
public function removeClassified(\XXX\ClassifiedsBundle\Entity\Classifieds $classified) {
$this->classifieds->removeElement($classified);
}
/**
* Get classifieds
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getClassifieds() {
return $this->classifieds;
}
/**
* Add child
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child
*
* #return ClassifiedsCategory
*/
public function addChild(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child) {
$this->children[] = $child;
return $this;
}
/**
* Remove child
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child
*/
public function removeChild(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child) {
$this->children->removeElement($child);
}
/**
* Get children
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getChildren() {
return $this->children;
}
/**
* Add parent
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent
*
* #return ClassifiedsCategory
*/
public function addParent(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent) {
$this->parent[] = $parent;
return $this;
}
/**
* Remove parent
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent
*/
public function removeParent(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent) {
$this->parent->removeElement($parent);
}
/**
* Get parent
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getParent() {
return $this->parent;
}
}
<pre>
namespace XXX\ClassifiedsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
* #ORM\HasLifecycleCallbacks
*/
abstract class ClassifiedsAbstractTaxonomy {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=120, unique=true)
*/
private $name;
/**
* #ORM\Column(type="string", length=120, unique=true)
*/
private $slug;
protected $classifieds;
/**
* Constructor
*/
public function __construct()
{
$this->classifieds = new \Doctrine\Common\Collections\ArrayCollection();
// $this->children = new \Doctrine\Common\Collections\ArrayCollection();
// $this->parent = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add classifieds
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classifieds
* #return ClassifiedsCategory
*/
public function addClassifieds(\XXX\ClassifiedsBundle\Entity\Classifieds $classifieds)
{
$this->classifieds[] = $classifieds;
return $this;
}
/**
* Remove classifieds
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classifieds
*/
public function removeClassifieds(\XXX\ClassifiedsBundle\Entity\Classifieds $classifieds)
{
$this->classifieds->removeElement($classifieds);
}
/**
* Get classifieds
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCompanies()
{
return $this->classifieds;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return AbstractTaxonomy
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* #param string $slug
* #return AbstractTaxonomy
*/
public function setSlug($slug)
{
$this->slug = \XXX\ClassifiedsBundle\Libs\Utils::sluggify($slug);
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function preSave(){
if(null === $this->slug){
$this->setSlug($this->getName());
}
}
}
namespace XXX\AdminBundle\Form\Type;
use XXX\AdminBundle\Form\Type\ClassifiedsTaxonomyType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ClassifiedsCategoryType extends ClassifiedsTaxonomyType {
public function getName() {
return 'taxonomy';
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', 'text', array(
'label' => 'Tytuł'
))
->add('slug', 'text', array(
'label' => 'Alias'
))
->add('parent', 'entity', array(
'class' => 'XXX\ClassifiedsBundle\Entity\ClassifiedsCategory',
'property' => 'name',
'empty_value' => 'Choose a parent category',
'required' => false,
))
->add('save', 'submit', array(
'label' => 'Zapisz'
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'XXX\ClassifiedsBundle\Entity\ClassifiedsCategory'
));
}
}
Your FormType ClassifiedsCategoryType is expecting an instance of ClassifiedsCategory and this need the attribute parent so far so good. But when you handle the request from your form to the controller, the formbuilder component tries to set the entered value to the attribute via the set method on the entity. This set method (setParent) is missing in your entity class.
So you have to implement it like this:
public function setParent($parent)
{
$this->parent = $parent;
return $this;
}
I have 2 entities, Exercise and Product, they have a One to One relationship (the owning side is Product), and I have an ExerciseFormType and a ProductFormType.
What I want I to be able to create an exercise, and the product associated with it at the same time.
My idea was to add the the builder of exerciseFormType, 'product' and its type would be a ProductFormType. The problem is that the product needs the exercise_id, and the exercise isn't persisted yet so it doesn't have one. Here's what I have so far (it works only for creating a product when the exercise exists).
class ExerciseType extends AbstractType {
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('name')
->add('content')
->add('language')
->add('level')
->add('skillsRequired')
->add('skillsTargetted')
->add('tags')
->add('product', ProductType::class, array(
'required' => false,
'exercise'=> $builder->getData()
)
);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => 'SchoolBundle\Entity\Exercise'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(){
return 'schoolbundle_exercise';
}
class ProductType extends AbstractType {
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('visibility')->add('price', MoneyType::class);
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$product = $event->getData();
$form = $event->getForm();
$field = (!$product || null === $product->getId()) ? 'publicationDate' : 'updateDate';
$form->add($field, DateTimeType::class, array('data' => new \DateTime()));
});
$data = array(
'data' => $options['exercise'],
'class' => Exercise::class,
'choice_label' => 'getName'
);
$builder->add('exercise', EntityType::class, $data);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => 'MarketBundle\Entity\Product'
));
$resolver->setRequired(array(
'exercise'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(){
return 'marketbundle_product';
}
}
In exercise I have that
<?php
/**
* exercise
*
* #ORM\Table(name="exercise")
* #ORM\Entity(repositoryClass="SchoolBundle\Repository\ExerciseRepository")
*/
class Exercise {
/**
* #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 string
* #ORM\Column(name="content", type="string", length=255)
*/
private $content;
/**
* #var string
* #ORM\Column(name="language", type="string", length=255)
*/
private $language;
/**
* #var int
* #ORM\Column(name="level", type="integer")
*/
private $level;
/**
* #var string
* #ORM\Column(name="skills_required", type="string", length=255)
*/
private $skillsRequired;
/**
* #var string
* #ORM\Column(name="skills_targetted", type="string", length=255)
*/
private $skillsTargetted;
/**
* #var string
* #ORM\Column(name="tags", type="string", length=255)
*/
private $tags;
/**
* #ORM\OneToMany(targetEntity="Session", mappedBy="exercise")
*/
private $sessions;
/**
* #ORM\OneToMany(targetEntity="ExerciseIO", mappedBy="exercise")
*/
private $exerciseIOs;
/**
* #ORM\OneToOne(targetEntity="MarketBundle\Entity\Product", mappedBy="exercise", cascade={"persist"}))
*/
private $product;
/**
* #ORM\ManyToOne(targetEntity="Professor", inversedBy="createdExercises")
* #ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=false)
*/
private $creator;
/**
* #ORM\ManyToMany(targetEntity="Professor", mappedBy="boughtExercises")
*/
private $owners;
public function __construct(){
$this->sessions = new ArrayCollection();
$this->exerciseIOs = new ArrayCollection();
$this->owners = new ArrayCollection();
}
/**
* Get creator
* #return Professor
*/
public function getCreator(){
return $this->creator;
}
/**
* Set creator
* #param Professor $creator
* #return Exercise
*/
public function setCreator($creator){
$this->creator = $creator;
return $this;
}
/**
* Get owner
* #return ArrayCollection
*/
public function getOwners(){
return $this->owners;
}
/**
* Get product
* #return Product
*/
public function getProduct(){
return $this->product;
}
/**
* #param Product $product
* #return Exercise
*/
public function setProduct($product){
$this->product = $product;
return $this;
}
/**
* Get exerciseIOs
* #return ArrayCollection
*/
public function getExerciseIOs(){
return $this->exerciseIOs;
}
/**
* Get sessions
* #return ArrayCollection
*/
public function getSessions(){
return $this->sessions;
}
/**
* Get id
* #return int
*/
public function getId(){
return $this->id;
}
/**
* Set name
* #param string $name
* #return Exercise
*/
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 Exercise
*/
public function setContent($content){
$this->content = $content;
return $this;
}
/**
* Get content
* #return string
*/
public function getContent(){
return $this->content;
}
/**
* Set language
* #param string $language
* #return Exercise
*/
public function setLanguage($language){
$this->language = $language;
return $this;
}
/**
* Get language
* #return string
*/
public function getLanguage(){
return $this->language;
}
/**
* Set level
* #param string $level
* #return Exercise
*/
public function setLevel($level){
$this->level = $level;
return $this;
}
/**
* Get level
* #return string
*/
public function getLevel(){
return $this->level;
}
/**
* Set skillsRequired
* #param string $skillsRequired
* #return Exercise
*/
public function setSkillsRequired($skillsRequired){
$this->skillsRequired = $skillsRequired;
return $this;
}
/**
* Get skillsRequired
* #return string
*/
public function getSkillsRequired(){
return $this->skillsRequired;
}
/**
* Set skillsTargetted
* #param string $skillsTargetted
* #return Exercise
*/
public function setSkillsTargetted($skillsTargetted){
$this->skillsTargetted = $skillsTargetted;
return $this;
}
/**
* Get skillsTargetted
* #return string
*/
public function getSkillsTargetted(){
return $this->skillsTargetted;
}
/**
* Set tags
* #param string $tags
* #return Exercise
*/
public function setTags($tags){
$this->tags = $tags;
return $this;
}
/**
* Get tags
* #return string
*/
public function getTags(){
return $this->tags;
}
}
And in Product
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="\MarketBundle\Repository\ProductRepository")
*/
class Product {
/**
* #var int
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var bool
* #ORM\Column(name="visibility", type="boolean")
*/
private $visibility;
/**
* #var float
* #ORM\Column(name="price", type="float")
*/
private $price;
/**
* #var \DateTime
* #ORM\Column(name="publication_date", type="datetimetz")
*/
private $publicationDate;
/**
* #var \DateTime
* #ORM\Column(name="update_date", type="datetimetz", nullable=true)
*/
private $updateDate;
/**
* #ORM\OneToMany(targetEntity="ProductComment", mappedBy="product")
*/
private $productComments;
/**
* #ORM\OneToOne(targetEntity="\SchoolBundle\Entity\Exercise", inversedBy="product")
* #ORM\JoinColumn(name="exercise_id", referencedColumnName="id", nullable=false)
*/
private $exercise;
public function __construct(){
$this->productComments = new ArrayCollection();
}
/**
* Get exercise
* #return Exercise
*/
public function getExercise(){
return $this->exercise;
}
/**
* Set exercise
* #param Exercise $exercise
* #return Product
*/
public function setExercise($exercise){
$this->exercise = $exercise;
return $this;
}
/**
* Get productComments
* #return ArrayCollection
*/
public function getProductComments(){
return $this->productComments;
}
/**
* Get id
* #return int
*/
public function getId(){
return $this->id;
}
/**
* Set visibility
* #param boolean $visibility
* #return Product
*/
public function setVisibility($visibility){
$this->visibility = $visibility;
return $this;
}
/**
* Get visibility
* #return bool
*/
public function getVisibility(){
return $this->visibility;
}
/**
* Set price
* #param float $price
* #return Product
*/
public function setPrice($price){
$this->price = $price;
return $this;
}
/**
* Get price
* #return float
*/
public function getPrice(){
return $this->price;
}
/**
* Set publicationDate
* #param \DateTime $publicationDate
* #return Product
*/
public function setPublicationDate($publicationDate){
$this->publicationDate = $publicationDate;
return $this;
}
/**
* Get publicationDate
* #return \DateTime
*/
public function getPublicationDate(){
return $this->publicationDate;
}
/**
* Set updateDate
* #param \DateTime $updateDate
* #return Product
*/
public function setUpdateDate($updateDate){
$this->updateDate = $updateDate;
return $this;
}
/**
* Get updateDate
* #return \DateTime
*/
public function getUpdateDate(){
return $this->updateDate;
}
}
I've said it works for an existing exercise (and no product).
When I try to create both at the same time I get
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
It's probably from the $builder->getData(), because in that case I only passed to the form a "new Exercice()". Here's the controller action
public function newAction(Request $request){
$exercise = new Exercise();
$form = $this->createForm(ExerciseType::class, $exercise);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$exercise->setCreator($this->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($exercise);
$em->flush();
return $this->redirectToRoute('exercise_show', array('id' => $exercise->getId()));
}
(Also this is another question but when I disable a formType, it is rendered, and the value appears but it's not submitted. I would actually prefer a hiddenFormType but I need the formatting of the DateTimeFormType)
Ok, this is the solution I've made once with Symfony2.8, I hope it can helps you.
/**
* #ORM\Entity
* #ORM\Table(name="picture")
*/
class Picture
{
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Host",
* inversedBy="pictureId"
* )
* #ORM\JoinColumn(name="avatar_host_id", referencedColumnName="id", nullable=true)
*/
private $avatarHostId;
}
/**
* #ORM\Entity
* #ORM\Table(name="host")
*/
class Host
{
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Picture",
* mappedBy="avatarHostId", cascade={"persist", "remove", "merge"}
* )
*/
private $pictureId;
}
class HostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('pictureId', PictureFileType::class);
}
}
class PictureFileType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('assetFile', FileType::class, array(
'label' => 'Picture File',
'required' => false,
'validation_groups' => array('creation')
));
}
}
First, I recommend moving away from using integers as IDs. There are some issues around them, including that you can't really generate one at will in this kind of scenario. I would recommend Uuids along with ramsey/uuid, which also has a Doctrine mapping.
When you've got a situation where you need an ID before it's been persisted and the Uuid generated, generate the Uuid yourself. For instance, in a contrived example
class Order
{
/**
* #var UuidInterface
*
* #ORM\Id
* #ORM\Column(type="uuid")
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
private $id;
...
/**
* Constructor.
*
* #param UuidInterface $id
*/
public function __construct(?UuidInterface $id = null)
{
$this->id = $id ?? Uuid::uuid4();
}
...
}
class OrderController
{
...
public function orderProductAction(): JsonResponse
{
...
// We need this ahead of time, because
// maybe this is Async and we need to
// return the order id. This happens a
// lot with commands.
$generatedId = Uuid::uuid4();
// Here it's going to use the given ID,
// if not given, the Order class will
// generate it.
$order = new Order($generatedId, ...);
// Stuff happens, persisted... maybe we
// don't have the persisted Order object...
return $this->json([
'order' => [
'id' => $generatedId->toString(),
],
]);
}
...
}
The meat of it is providing the generated Uuid in the constructor (which alternately generates it if null). Do not add a setter. Here's a more involved example:
public function createAction(Request $request): JsonResponse
{
$request_data = \json_decode($request->getContent(), true);
$tenant_data = $request_data['data'];
// Pre-generate our Uuid for the Tenant.
$generated_id = Uuid::uuid4();
/** #var CreateTenant $create_tenant_cmd */
$create_tenant_cmd = new CreateTenant($generated_id);
$create_tenant_cmd->setName($tenant_data['name']);
$create_tenant_cmd->setDomainName($tenant_data['domain_name']);
$create_tenant_cmd->setOwnerUsername($tenant_data['owner_username']);
$create_tenant_cmd->setOwnerPassword($tenant_data['owner_password']);
$create_tenant_cmd->setOwnerFirstName($tenant_data['owner_first_name']);
$create_tenant_cmd->setOwnerLastName($tenant_data['owner_last_name']);
$create_tenant_cmd->setOwnerEmail($tenant_data['owner_email']);
if (!$this->isGranted('perform', $create_tenant_cmd)) {
throw new AccessDeniedException('Access denied to create tenant.');
}
// Here, we should expect NO side-effects, the command
// can't return anything. So no Tenant object with
// generated Uuid...
$this->get('command_bus')->handle($create_tenant_cmd);
/* #var Serializer $serializer */
$serializer = $this->get('jms_serializer');
$serializer_context = SerializationContext::create()->setGroups([
'tenant_meta',
]);
$tenant = $this->get('app.repository.tenant')->find($generated_id);
return $this->json(\json_decode($serializer->serialize(
$tenant,
'json',
$serializer_context
)));
}
That's the ID question; the second part of your question is now easily resolved, that being giving the Uuid to the FormType instead:
$form = $this->createForm(OrderProductType::class, $product, [
'product' => $product,
'generatedId' => $generatedId,
]);
class OrderProductType extends AbstractType implements DataMapperInterface
{
/** #var UuidInterface */
protected $generatedId;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->generatedId = $options['generatedId'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'data_class' => OrderProduct::class,
])
->setRequired(['generatedId'])
;
}
public function mapFormsToData($forms, &$data)
{
$forms = iterator_to_array($forms);
$data = new OrderProduct($this->generatedId);
...
}
}
Of course, if you need it as a field, use it with the field type of your choice instead of storing it as a variable, and then get it from that field:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product_id', HiddenType::class, [
'product_id' => $options['generatedId']->toString(),
])
...
;
}
public function mapFormsToData($forms, &$data)
{
$forms = iterator_to_array($forms);
// Note use of Uuid::fromString().
$data = new OrderProduct(Uuid::fromString(
$forms['productId']->getData()
));
...
}
This is one of the downsides of not delegating the process of interaction to a delegate object like a command, instead of generating an entity; you're stuck constructing your object before you need it, in whole, or perverting the design to make it fit. It also makes working with assertions harder as well (you only get one set, the entity's).
I have this problem when i execute my project, I use FormEvent in FormType
entity Departement.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Departement
*
* #ORM\Table(name="departement")
* #ORM\Entity(repositoryClass="AppBundle\Repository\DepartementRepository")
*/
class Departement
{
/**
* #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 int
*
* #ORM\Column(name="code", type="integer")
*/
private $code;
/**
*#ORM\ManyToOne(targetEntity="AppBundle\Entity\Region")
*/
private $region;
/**
*#ORM\OneToMany(targetEntity="AppBundle\Entity\Ville", mappedBy="departement")
*/
private $villes;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Departement
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set code
*
* #param integer $code
* #return Departement
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return integer
*/
public function getCode()
{
return $this->code;
}
/**
* Constructor
*/
public function __construct()
{
$this->villes = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set region
*
* #param \AppBundle\Entity\Region $region
* #return Departement
*/
public function setRegion(\AppBundle\Entity\Region $region = null)
{
$this->region = $region;
return $this;
}
/**
* Get region
*
* #return \AppBundle\Entity\Region
*/
public function getRegion()
{
return $this->region;
}
/**
* Add villes
*
* #param \AppBundle\Entity\Ville $villes
* #return Departement
*/
public function addVille(\AppBundle\Entity\Ville $villes)
{
$this->villes[] = $villes;
return $this;
}
/**
* Remove villes
*
* #param \AppBundle\Entity\Ville $villes
*/
public function removeVille(\AppBundle\Entity\Ville $villes)
{
$this->villes->removeElement($villes);
}
/**
* Get villes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVilles()
{
return $this->villes;
}
public function __toString(){
return $this->name;
}
}
entity ville.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Ville
*
* #ORM\Table(name="ville")
* #ORM\Entity(repositoryClass="AppBundle\Repository\VilleRepository")
*/
class Ville
{
/**
* #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 int
*
* #ORM\Column(name="code", type="integer")
*/
private $code;
/**
*#ORM\ManyToOne(targetEntity="AppBundle\Entity\Departement")
*/
private $departement;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Ville
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set code
*
* #param integer $code
* #return Ville
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return integer
*/
public function getCode()
{
return $this->code;
}
/**
* Set departement
*
* #param \AppBundle\Entity\Departement $departement
* #return Ville
*/
public function setDepartement(\AppBundle\Entity\Departement $departement = null)
{
$this->departement = $departement;
return $this;
}
/**
* Get departement
*
* #return \AppBundle\Entity\Departement
*/
public function getDepartement()
{
return $this->departement;
}
public function __toString(){
return $this->name;
}
}
Form MedecinType.php:
<?php
namespace AppBundle\Form;
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\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormInterface;
use AppBundle\Entity\Region;
use AppBundle\Entity\Departement;
use AppBundle\Entity\Ville;
class MedecinType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('region', EntityType::class, [
'class' => 'AppBundle\Entity\Region',
'placeholder' => 'Sélectionnez votre région',
'mapped' => false,
'required' => false
]);
$builder->get('region')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$this->addDepartementField($form->getParent(), $form->getData());
}
);
}
private function addDepartementField(FormInterface $form, Region $region)
{
$builder = $form->getConfig()->getFormFactory()->createNamedBuilder(
'departement',
EntityType::class,
null,
[
'class' => 'AppBundle\Entity\Departement',
'placeholder' => 'Sélectionnez votre département',
'mapped' => false,
'required' => false,
'auto_initialize' => false,
'choices' => $region->getDepartements()
]);
$builder->addEventListener(
FormEvents::POST_SUBMIT,
function(FormEvent $event) {
$form= $event->getForm();
$this->addVilleField($form->getParent(), $form->getData());
}
);
$form->add($builder->getForm());
}
private function addVilleField(FormInterface $form, Departement $departement)
{
$form->add('ville', EntityType::class, [
'class' => 'AppBundle\Entity\Ville',
'placeholder' => 'Sélectionnez votre ville',
'choices' => $departement->getVilles()
]);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Medecin'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_medecin';
}
}
help me please for resolve this problem and thank you advanced
Since you've set departement field as nullable with 'required' => false,, the method $form->getData() in event listener may be either an instance of Departement entity or null if no departement was chosen.
You have to check if $form->getData() returns instance of your entity and
handle if it's not.
That would be something like:
$builder->addEventListener(
FormEvents::POST_SUBMIT,
function(FormEvent $event) {
$form= $event->getForm();
$formData = $form->getData();
if(! $formData instanceof Departement) {
//handle this case or just do nothing and return from the listener
return;
}
// here's the default case
$this->addVilleField($form->getParent(), $form->getData());
}
);
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