How to edit embedded form with file upload in symfony2 and doctrine mongodb - mongodb

I have document called aboutMe
and it has another embedded document called projects to add many projects (prototype)
The projects has project name and image for the project.
i created a formType for aboutMe document and i embedded the project form inside the aboutMe form to be able to add many projects prototype.
The problem is updating the project->image when the user didn't change the old project image.
doctrine updating the old embedded project document with a null image.
I Need to keep the old image name if the user didn't upload a new one
/**
* #MongoDB\Document
* #MongoDB\HasLifecycleCallbacks
*/
class AboutMeIndex {
/**
* #var integer
*
* #MongoDB\Id(strategy="INCREMENT")
*/
protected $id;
/**
* #var array
*
* #MongoDB\EmbedMany(targetDocument="AboutMeProjects", strategy="set")
*/
protected $projects = array();
public function __construct()
{
$this->projects = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Remove project
*
* #param TimesSell\CoreBundle\Document\Profile\AboutMe\AboutMeProjects $project
*/
public function removeProject(\TimesSell\CoreBundle\Document\Profile\AboutMe\AboutMeProjects $project)
{
$this->projects->removeElement($project);
}
/**
* Get projects
*
* #return Doctrine\Common\Collections\Collection $projects
*/
public function getProjects()
{
return $this->projects;
}
/**
* Add certification
*
* #param TimesSell\CoreBundle\Document\Profile\AboutMe\AboutMeCertifications $certification
*/
public function addCertification(\TimesSell\CoreBundle\Document\Profile\AboutMe\AboutMeCertifications $certification)
{
$this->certifications[] = $certification;
}
//=================================================================================//
public function fileGetter($file){
if(method_exists($this, 'get' . ucfirst($file))) {
return call_user_func(array($this, 'get' . ucfirst($file)));
}
else {
throw new \Exception("Couldn't Find Method name get" . ucfirst($file));
}
}
protected function getUploadRootDir($uploadDir)
{
return __DIR__.'/../../../../../../web/uploads/'.$this->getUploadDir($uploadDir);
}
protected function getUploadDir($uploadDir)
{
return $uploadDir;
}
public function uploadEmbeddedPhotos($file, $uploadDir)
{
if (null === $this->fileGetter($file)) {
return;
}
foreach ($this->fileGetter($file) as $galleryPhoto){
$pictureName = uniqid().'.'.$galleryPhoto->getImage()->guessExtension();
$galleryPhoto->getImage()->move($this->getUploadRootDir($uploadDir),$pictureName);
$this->path = $galleryPhoto->getImage()->getClientOriginalName();
$galleryPhoto->setImage($pictureName);
}
}
public function deleteImage($image, $uploadDir){
#unlink($this->getUploadRootDir($uploadDir).$image);
}
//=================================================================================//
/**
* #MongoDB\EmbeddedDocument
*
*/
class AboutMeProjects {
/**
* #var integer
*
* #MongoDB\Id(strategy="INCREMENT")
*/
protected $id;
/**
* #var string
*
* #MongoDB\String
*/
protected $projectName;
/**
* #var string
*
* #Assert\Image(
* maxSize = "20000k",
* mimeTypes = {"image/gif", "image/jpeg", "image/png"},
* mimeTypesMessage = "Please upload a valid picture"
* )
* #Assert\Regex(
* pattern="/[a-zA-Z0-9]+/",
* match=true,
* message="Special characters are not allowed"
* )
*
* #MongoDB\String
*/
protected $image;
/**
* #var string
*
* #MongoDB\String
*/
protected $desc;
/**
* Get id
*
* #return int_id $id
*/
public function getId()
{
return $this->id;
}
/**
* Set projectName
*
* #param string $projectName
* #return self
*/
public function setProjectName($projectName)
{
$this->projectName = $projectName;
return $this;
}
/**
* Get projectName
*
* #return string $projectName
*/
public function getProjectName()
{
return $this->projectName;
}
/**
* Set image
*
* #param string $image
* #return self
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string $image
*/
public function getImage()
{
return $this->image;
}
/**
* Set desc
*
* #param string $desc
* #return self
*/
public function setDesc($desc)
{
$this->desc = $desc;
return $this;
}
/**
* Get desc
*
* #return string $desc
*/
public function getDesc()
{
return $this->desc;
}
}
class AboutMeIndexType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName')
->add('projects', 'collection', array(
'type' => new ProjectsType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required' => false
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AboutMeIndex'
));
}
/**
* #return string
*/
public function getName()
{
return 'AbourMe';
}
}
class ProjectsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('projectName','text',array('attr'=> array('class'=>'form-control', 'placeholder' => 'Project name') ))
->add('image','file',array('data_class' => null,'attr'=> array('class'=>'form-control col-lg-2 file-inputs') ))
->add('desc','textarea',array('attr'=> array('class'=>'form-control', 'data-provide' => 'markdown', 'placeholder' => 'Description') ))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AboutMeProjects'
));
}
/**
* #return string
*/
public function getName()
{
return 'ProjectsType';
}
}
And here's the controller that i want to be able to keep the old image
/**
* Edits an existing aboutMeIndex document.
*
* #Route("/profile/about-me/update", name="profile_about_me_update")
* #Method("PUT")
* #Template()
*/
public function updateAction(Request $request)
{
$dm = $this->get('doctrine.odm.mongodb.document_manager');
$user = $this->getUser();
$entity = $dm->getRepository('AboutMeIndex')->findOneBy(array('user.$id' => (int)$user->getId()));
if (!$entity) {
throw $this->createNotFoundException('Unable to find entity Document.');
}
$editForm = $this->createForm(new AboutMeIndexType(), $entity);
$editForm->submit($request);
if ($editForm->isValid()) {
if($entity->getProjects()->getImage() is newImage){
$entity->uploadEmbeddedPhotos('projects', 'profile/aboutMe/');
}else{
// Keep the old Image
}
$dm->persist($entity);
$dm->flush();
}
}

Related

symfony3 image is not uploaded

In AppBundle\Etity\Image I have:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="images")
* #ORM\HasLifecycleCallbacks
*/
class Image
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank
*/
private $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Assert\NotBlank
*/
private $path;
/**
* #Assert\Image(maxSize="10M", mimeTypes="image/jpeg", minWidth = 600, minHeight = 400)
* #Assert\NotBlank
*/
private $file;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank
*/
private $alt;
private $temp;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getPath()
{
return $this->path;
}
/**
* #param mixed $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* #return mixed
*/
public function getAlt()
{
return $this->alt;
}
/**
* #param mixed $alt
*/
public function setAlt($alt)
{
$this->alt = $alt;
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
}
public function getUploadRootDir()
{
return __DIR__ . '/../../../../web/' . $this->getUploadDir();
}
public function getUploadDir()
{
return 'images/full';
}
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
// check if we have an old image path
if (isset($this->path)) {
// store the old name to delete after the update
$this->temp = $this->path;
$this->path = null;
} else {
$this->path = 'initial';
}
}
/**
* #return mixed
*/
public function getFile()
{
return $this->file;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
// do whatever you want to generate a unique name
$filename = sha1(uniqid(mt_rand(), true));
$this->path = $filename.'.'.$this->getFile()->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->getFile()->move($this->getUploadRootDir(), $this->path);
// check if we have an old image
if (isset($this->temp)) {
// delete the old image
unlink($this->getUploadRootDir().'/'.$this->temp);
// clear the temp image path
$this->temp = null;
}
$this->file = null;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
$file = $this->getAbsolutePath();
if ($file) {
unlink($file);
}
}
}
Which is used in AppBundle\Entity\Post.php like this:
/**
* #ORM\ManyToOne(targetEntity="Image", cascade="all")
* #ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
private $teaserImage;
In AppBundle\Form\Type\PostType.php I have this:
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Entity\Post;
/**
* Defines the form used to create and manipulate blog posts.
*/
class PostType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', null, array('label' => 'Title'))
->add('summary', null, array('label' => 'Summary'))
->add('teaserImage', 'AppBundle\Form\Type\ImageType', array('label' => 'Image'))
->add('content', null, array(
'attr' => array('rows' => 20),
'label' => 'Content',
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Post',
));
}
}
For some reason the images are not uploaded to the specified directory (or anywhere else) and I am not sure what I did wrong. I would be grateful for any insights.
Thank you.
The issue is related to
return __DIR__ . '/../../../../web/' . $this->getUploadDir();
In this case I changed the previous line to:
return __DIR__ . '/../../../web/' . $this->getUploadDir();
That is because my entity is located in src/AppBundle/Entity and to go to root directory it needs to hop 3 directories back.
Also it is a bad idea to hard-code paths in entities. I modified my example accordingly.

An exception occurred while executing 'INSERT INTO tag (name, task_id) VALUES (?, ?)' with params ["qw", null]:

Please help me to resolve this error:
I have two entities, Task and Tag, in TaskType pretend add N tags, but when I keep generates the following error:
An exception occurred while executing 'INSERT INTO tag (name, task_id) VALUES (?, ?)' with params ["qw", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'task_id' cannot be null
Task:
class Task
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255)
*/
private $description;
/**
* #ORM\OneToMany(targetEntity="Tag", mappedBy="task", cascade={"persist", "remove"})
*/
private $tags;
public function __construct() {
$this->tags = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set description
*
* #param string $description
*
* #return Task
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set tags
*
* #param string $tags
*
* #return Task
*/
public function setTags($tags)
{
$this->tags = $tags;
return $this;
}
/**
* Get tags
*
* #return string
*/
public function getTags()
{
return $this->tags;
}
/**
* Add tag
*
* #param \AppBundle\Entity\Tag $tag
*
* #return Task
*/
public function addTag(\AppBundle\Entity\Tag $tag)
{
$this->tags[] = $tag;
return $this;
}
// public function addTag(Tag $tag)
// {
// $this->tags->add($tag);
// }
/**
* Remove tag
*
* #param \AppBundle\Entity\Tag $tag
*/
public function removeTag(\AppBundle\Entity\Tag $tag)
{
$this->tags->removeElement($tag);
}
}
Tag:
class Tag
{
/**
* #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;
/**
* #ORM\ManyToOne(targetEntity="Task", inversedBy="tags")
* #ORM\JoinColumn(name="task_id", referencedColumnName="id")
*/
private $task;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set task
*
* #param \AppBundle\Entity\Task $task
*
* #return Tag
*/
public function setTask(\AppBundle\Entity\Task $task = null)
{
$this->task = $task;
return $this;
}
/**
* Get task
*
* #return \AppBundle\Entity\Task
*/
public function getTask()
{
return $this->task;
}
}
TaskType:
class TaskType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description')
->add('tags', 'collection', array(
'type' => new TagType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
))
->add('submit','submit');
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'DeteccionBundle\Entity\Task'
));
}
/**
* #return string
*/
public function getName()
{
return 'task';
}
}
Controller:
public function newAction(Request $request)
{
$task = new Task();
//SE AGREGAN UN NUMERO DE Tags PARA LA task
// $tag1 = new Tag();
// $tag1->setName = 'tag1';
// $task->getTags()->add($tag1);
// $tag2 = new Tag();
// $tag2->setName = 'tag2';
// $task->getTags()->add($tag2);
// end dummy code
$form = $this->createForm(new TaskType(), $task);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($task);
$em->flush();
return $this->redirect($this->generateUrl('cpu_show', array('id' => $entity->getId())));
}
return $this->render('DeteccionBundle:Task:new.html.twig', array(
'task' => $task,
'form' => $form->createView(),
));
}
I appreciate your help
You should auto-set the task in your addTag like...
/**
* Add tag
*
* #param \AppBundle\Entity\Tag $tag
*
* #return Task
*/
public function addTag(\AppBundle\Entity\Tag $tag)
{
$this->tags[] = $tag;
$tag->setTask($this);
return $this;
}

Error when embedding form in Symfony whith collection

I have 2 "simple" entities, and i want to do the classical form embedding
but i have this error : "Neither the property "itemcode" nor one of the methods "getItemcode()", "itemcode()", "isItemcode()", "hasItemcode()", "__get()" exist and have public access in class "NWA\ItemSelectorBundle\Entity\ItemSelector"."
I've seen many posts with this error, but none provided the solution
In the entities i have getItemCode() but why would it be public ?
What is wrong with my construction?
Thank you in advance
Here are my entities (parts relevant to the properties at fault)
class ItemSelector
{
/**
* #var Items[]
*
* #ORM\OneToMany(targetEntity="NWA\ItemSelectorBundle\Entity\Item", mappedBy="itemselector", cascade={"all"})
*/
protected $items;
/**
* Class constructor
*/
public function __construct()
{
$this->items = new ArrayCollection();
}
/**
* Add item
*
* #param \NWA\ItemSelectorBundle\Entity\Item $item
*
* #return ItemSelector
*/
public function addItem(\NWA\ItemSelectorBundle\Entity\Item $item)
{
$this->items[] = $item;
//$item->setItemselector($this);
return $this;
}
/**
* Remove item
*
* #param \NWA\ItemSelectorBundle\Entity\Item $item
*/
public function removeItem(\NWA\ItemSelectorBundle\Entity\Item $item)
{
$this->items->removeElement($item);
}
/**
* Get items
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getItems()
{
return $this->items;
}
}
and
class Item
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="itemcode", type="string", length=255)
*/
protected $itemcode;
/**
* #var ItemSelector
*
* #ORM\ManyToOne(targetEntity="NWA\ItemSelectorBundle\Entity\ItemSelector", inversedBy="items")
* #ORM\JoinColumn(name="itemselector_id", referencedColumnName="id")
*/
protected $itemselector;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set itemcode
*
* #param string $itemcode
*
* #return Item
*/
public function setItemcode($itemcode)
{
$this->itemcode = $itemcode;
return $this;
}
/**
* Get itemcode
*
* #return string
*/
public function getItemcode()
{
return $this->itemcode;
}
/**
* Set itemselector
*
* #param \NWA\ItemSelectorBundle\Entity\ItemSelector $itemselector
*
* #return Item
*/
public function setItemselector(\NWA\ItemSelectorBundle\Entity\ItemSelector $itemselector = null)
{
$this->itemselector = $itemselector;
return $this;
}
/**
* Get itemselector
*
* #return \NWA\ItemSelectorBundle\Entity\ItemSelector
*/
public function getItemselector()
{
return $this->itemselector;
}
}
Then the Form constructors
class ItemSelectorType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'itemcode', 'collection', array(
'type' => new ItemType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true
)
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'NWA\ItemSelectorBundle\Entity\ItemSelector',
'translation_domain' => 'resource'
));
}
/**
* #return string
*/
public function getName()
{
return 'nwa_itemselector';
}
}
and
class ItemType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'itemcode', 'text', array(
'label' => 'Code'
)
);
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'NWA\ItemSelectorBundle\Entity\Item'
));
}
/**
* #return string
*/
public function getName()
{
return 'nwa_itemselectorbundle_item';
}
}
And finally the call in the Controller
public function chooseAction(Request $request, ItemSelector $itemSelector)
{
$form = $this->get('form.factory')
->create(new ItemSelectorType(), $itemSelector);
$form->handleRequest($request);
if ($form->isValid()) {
}
return array(
'_resource' => $itemSelector,
'form' => $form->createView(),
);
}
Maybe you need to rename your field name itemcode to items in ItemSelectorType.
->add(
'items', 'collection', array(
'type' => new ItemType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true
)
);

form symfony 2 many many self reference entity

I would like to create a form with a collection of self reference entity.
I need a form to create new Product ,this form will have a select field (child) with existing products.
I have a product entity and this entity include a child field (child is a product too).
Product entity :
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", length=20)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
protected $title;
/**
* #var string
*
* #ORM\Column(name="manufacturer_reference", type="string", length=255, nullable=true)
*/
protected $manufacturer_reference;
/**
* #var string
*
* #ORM\Column(name="resume", type="text", nullable=true)
*/
protected $resume;
/**
* #var boolean
*
* #ORM\Column(name="is_salable", type="boolean", options={"default" = 1})
*/
protected $is_salable = 1;
/**
* #var boolean
*
* #ORM\Column(name="is_active", type="boolean", options={"default" = 1})
*/
protected $is_active = 1;
/**
* #ORM\ManyToOne(targetEntity="\Hexanet\Common\CatalogBundle\Entity\ProductCategory")
* #ORM\JoinColumn(name="product_category_id", referencedColumnName="id", nullable=true)
*/
protected $product_category;
/**
* #ORM\ManyToOne(targetEntity="\Hexanet\Common\CatalogBundle\Entity\Manufacturer")
* #ORM\JoinColumn(name="manufacturer_id", referencedColumnName="id", nullable=true)
*/
protected $manufacturer;
/**
* #ORM\ManyToMany(targetEntity="\Hexanet\Common\CatalogBundle\Entity\Product", mappedBy="parents" )
*/
protected $children;
/**
* #ORM\ManyToMany(targetEntity="\Hexanet\Common\CatalogBundle\Entity\Product")
* #ORM\JoinTable(name="product_to_product",
* joinColumns={#ORM\JoinColumn(name="child_product_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="parent_product_id", referencedColumnName="id")}
* )
*/
protected $parents;
/**
* #ORM\OneToMany(targetEntity="\Hexanet\Common\CatalogBundle\Entity\ProductPrice", mappedBy="product" )
*/
protected $product_prices;
/**
* #ORM\OneToMany(targetEntity="\Hexanet\Common\CatalogBundle\Entity\ProductPricePurchase", mappedBy="product")
*/
protected $product_prices_purchase;
/**
* #ORM\OneToMany(targetEntity="\Hexanet\Common\CatalogBundle\Entity\ProductPriceCustom", mappedBy="product")
*/
protected $product_prices_custom;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
* #return Product
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set product category
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductCategory $product_category
* #return Product
*/
public function setProductCategory(\Hexanet\Common\CatalogBundle\Entity\ProductCategory $product_category = null)
{
$this->product_category = $product_category;
return $this;
}
/**
* Get product category
*
* #return \Hexanet\Common\CatalogBundle\Entity\ProductCategory
*/
public function getProductCategory()
{
return $this->product_category;
}
/**
* Set resume
*
* #param string $resume
* #return Product
*/
public function setResume($resume)
{
$this->resume = $resume;
return $this;
}
/**
* Get resume
*
* #return string
*/
public function getResume()
{
return $this->resume;
}
/**
* Set manufacturer reference
*
* #param string $title
* #return Product
*/
public function setManufacturerReference($ref)
{
$this->manufacturer_reference = $ref;
return $this;
}
/**
* Get manufacturer reference
*
* #return string
*/
public function getManufacturerReference()
{
return $this->manufacturer_reference;
}
/**
* Set is salable
*
* #param boolean $active
* #return Product
*/
public function setIsSalable($salable)
{
$this->is_salable = $salable;
return $this;
}
/**
* Get is salable
*
* #return boolean
*/
public function getIsSalable()
{
return $this->is_salable;
}
/**
* Set is active
*
* #param boolean $active
* #return Product
*/
public function setIsActive($active)
{
$this->is_active = $active;
return $this;
}
/**
* Get is active
*
* #return boolean
*/
public function getIsActive()
{
return $this->is_active;
}
/**
* Set manufacturer
*
* #param $manufacturer
* #return Product
*/
public function setManufacturer($manufacturer)
{
$this->manufacturer = $manufacturer;
return $this;
}
/**
* Get manufacturer
*
*/
public function getManufacturer()
{
return $this->manufacturer;
}
/**
* Constructor
*/
public function __construct()
{
$this->parents = new \Doctrine\Common\Collections\ArrayCollection();
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
$this->product_prices = new \Doctrine\Common\Collections\ArrayCollection();
$this->product_prices_purchase = new \Doctrine\Common\Collections\ArrayCollection();
$this->product_prices_custom = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add child
*
* #param \Hexanet\Common\CatalogBundle\Entity\Product $product
* #return Product
*/
public function addChild(\Hexanet\Common\CatalogBundle\Entity\Product $product)
{
die(var_dump($product));
$this->children[] = $product;
return $this;
}
/**
* Remove child
*
* #param \Hexanet\Common\CatalogBundle\Entity\Product $product
*/
public function removeChild(\Hexanet\Common\CatalogBundle\Entity\Product $product)
{
$this->children->removeElement($product);
}
/**
* Get children
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getChildren()
{
return $this->children;
}
/**
* Add parent
*
* #param \Hexanet\Common\CatalogBundle\Entity\Product $product
* #return Product
*/
public function addParent(\Hexanet\Common\CatalogBundle\Entity\Product $product)
{
$this->parents[] = $product;
return $this;
}
/**
* Remove parent
*
* #param \Hexanet\Common\CatalogBundle\Entity\Product $price
*/
public function removeParent(\Hexanet\Common\CatalogBundle\Entity\Product $product)
{
$this->parents->removeElement($product);
}
/**
* Get parents
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getParents()
{
return $this->parents;
}
/**
* Add product price
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductPrice $price
* #return Product
*/
public function addProductPrice(\Hexanet\Common\CatalogBundle\Entity\ProductPrice $price)
{
$this->product_prices[] = $price;
return $this;
}
/**
* Remove product price
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductPrice $price
*/
public function removeProductPrice(\Hexanet\Common\CatalogBundle\Entity\ProductPrice $price)
{
$this->product_prices->removeElement($price);
}
/**
* Get product prices
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProductPrices()
{
return $this->product_prices;
}
/**
* Add product price purchase
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductPricePurchase $price
* #return Product
*/
public function addProductPricePurchase(\Hexanet\Common\CatalogBundle\Entity\ProductPricePurchase $price)
{
$this->product_prices_purchase[] = $price;
return $this;
}
/**
* Remove product price purchase
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductPricePurchase $price
*/
public function removeProductPricePurchase(\Hexanet\Common\CatalogBundle\Entity\ProductPricePurchase $price)
{
$this->product_prices_purchase->removeElement($price);
}
/**
* Get product prices purchase
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProductPricesPurchase()
{
return $this->product_prices_purchase;
}
/**
* Add product price custom
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductPriceCustom $price
* #return Product
*/
public function addProductPriceCustom(\Hexanet\Common\CatalogBundle\Entity\ProductPriceCustom $price)
{
$this->product_prices_custom[] = $price;
return $this;
}
/**
* Remove product price custom
*
* #param \Hexanet\Common\CatalogBundle\Entity\ProductPriceCustom $price
*/
public function removeProductPriceCustom(\Hexanet\Common\CatalogBundle\Entity\ProductPriceCustom $price)
{
$this->product_prices_custom->removeElement($price);
}
/**
* Get product prices custom
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProductPricesCustom()
{
return $this->product_prices_custom;
}}
for the form i have this :
class ProductType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('manufacturer_reference')
->add('resume')
->add('product_category', 'entity', array(
'class' => 'HexanetCatalogBundle:ProductCategory',
'property' => 'title',
))
->add('children', 'collection', array(
'type' => new ProductChildrenType,
'allow_add' => true));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Hexanet\Common\CatalogBundle\Entity\Product'
));
}
public function getName()
{
return 'hexanet_common_catalogbundle_producttype';
}}
The problem is there, i dont know how to create the ProductChildrenType builder :
class ProductChildrenType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'entity', array(
'class' => 'HexanetCatalogBundle:Product',
'property' => 'title',
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Hexanet\Common\CatalogBundle\Entity\Product'
));
}
public function getName()
{
return 'hexanet_common_catalogbundle_productchildrentype';
}}
->add('product', 'entity',...) I have the error :
Neither property "product" nor method "getProduct()" nor method "isProduct()" exists in class "Hexanet\Common\CatalogBundle\Entity\Product".
Thx for the Help
I have a similar case for a store, so i can add extra products on the admin area, so i can offer them on checkout...
My partner at work and me solved this problem yesterday, so if you're still interested, here we go....
We are using Symfony 2.6.x , i haven't tested it on older versions of symfony yet.
->add('myExtras', 'collection', array(
'type' => 'entity',
'options' => array(
'class' => 'StoreBundle:Productos',
'placeholder' => '-- Select an extra product --',
'property' => 'name',
'query_builder' => function (EntityRepository $er) use( $options ) {
return $er->createQueryBuilder('p')
->where('p.asociable = :asociable')
->andWhere('p.id != :selfid')
->setParameters( array('adjuntable' => '1', 'selfid' => $options['selfid'] ));
},
'label' => 'Extra Product'
),
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true
))
instead of using a collection of form type for "children", we used a collection of type "entity", and we used a querybuilder to control the conditions we needed to get the right options to show.
using this we stopped having the messages, that you're getting... and for saving and removing the relation, when we add the children, we had to tell the children to set the parent... and for removing the same, first tell the children to remove the parent from the parent's list, and then remove the children from the children list... (in code is easier to see)
in the entity i have to collections myExtras (childrens) and imExtraOf (parents), so when adding a children, i have to tell the children i'm receiving the counterpart ->addImExtraOf (i am your father function) ... then we add the product to our extra list. and for removing, the same, we call first ->removeImExtraOf , if you don't do it this way, the relation will not be saved.
the Entity :
public function addMyExtra(Productos $extra)
{
$extra->addImExtraOf($this);
if( !$this->myExtras->contains($extra) ) {
$this->myExtras[] = $extra;
}
return $this;
}
public function removeMyExtra(Productos $extra)
{
$extra->removeImExtraOf($this);
$this->myExtras->removeElement($extra);
}
the orm mapping (yml): (myExtras = children, imExtraOf = parents )
manyToMany:
myExtras:
targetEntity: Productos
cascade: [ persist ]
mappedBy: imExtraOf
inversedBy: null
joinTable:
name: productos_has_productos
joinColumns:
-
name: extra_id
referencedColumnName: id
inverseJoinColumns:
-
name: base_id
referencedColumnName: id
orderBy: null
imExtraOf:
targetEntity: Productos
cascade: [ persist ]
mappedBy: null
inversedBy: myExtras
joinTable:
name: productos_has_productos
joinColumns:
-
name: base_id
referencedColumnName: id
inverseJoinColumns:
-
name: extra_id
referencedColumnName: id
orderBy: null
hope it helps someone.

Doctrine Mongo document + Embed a Collection of Forms

Project with symfony 2 and mongoDB.
I'm following this tutorial: http://symfony.com/doc/current/cookbook/form/form_collections.html
But once I save the form I get this error:
Cannot create a DBRef, the document is not an object
Line of crash:
https://github.com/doctrine/mongodb-odm/blob/master/lib/Doctrine/ODM/MongoDB/DocumentManager.php#L691
Form code:
namespace Fonts\FontsBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class FamilyType extends AbstractType
{
public function __construct($dm)
{
$this->dm = $dm;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text', array('max_length' => 50, 'error_bubbling' => true));
$builder->add('fonts', 'collection', array(
'type' => new FontType($this->dm),
'allow_add' => true,
'by_reference' => false,
));
}
public function getName()
{
return 'Family';
}
}
Controller code:
namespace Fonts\FontsBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Fonts\FontsBundle\Document\Family;
use Fonts\FontsBundle\Document\Font;
use Fonts\FontsBundle\Form\Type\FamilyType;
class FamilyBackendController extends BaseController
{
public function newAction()
{
try {
$family = new Family();
$form = $this->createForm(new FamilyType($this->getMongoService()), $family);
$request = $this->getRequest();
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid())
{
$this->persist($family);
$this->get('session')->setFlash('notice', 'Item successfully created.');
return ($request->request->get('save') === 'Save') ?
new RedirectResponse($this->generateUrl('backend_familys_list')) :
new RedirectResponse($this->generateUrl('backend_familys_new'));
}
}
return $this->render('FontsBundle:Backend:newFamily.html.twig', array(
'form' => $form->createView(),
));
} catch(\Exception $e) {
return new Response($e->getMessage());
}
}
}
Document:
<?php
namespace Fonts\FontsBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Fonts\FontsBundle\Service\SlugService;
/**
* #MongoDB\Document(repositoryClass="Fonts\FontsBundle\Repository\FamilyRepository")
*/
class Family
{
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\String
* #MongoDB\UniqueIndex(safe=true)
* #Assert\NotBlank(message="FamilyName value should not be blank.")
* #Assert\MinLength(limit=3,message="FamilyName must have at least {{ limit }} characters.")
* #Assert\MaxLength(limit=50,message="FamilyName must have maximum {{ limit }} characters.")
*/
protected $name;
/**
* #MongoDB\ReferenceMany(targetDocument="Font", simple=true)
* #Assert\NotBlank(message="Fonts should not be blank.")
*/
protected $fonts;
/**
* #MongoDB\String
* #MongoDB\UniqueIndex(safe=true)
*/
protected $slug;
/**
* #MongoDB\Int
*/
protected $createdAt;
public function __construct()
{
$this->fonts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return id $id
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Family
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string $name
*/
public function getName()
{
return $this->name;
}
/**
* Add fonts
*
* #param Fonts\FontsBundle\Document\Font $fonts
*/
public function addFonts(\Fonts\FontsBundle\Document\Font $fonts)
{
$this->fonts[] = $fonts;
}
/**
* Set fonts
*
* #param Doctrine\Common\Collections\Collection $fonts
*/
public function setFonts($fonts)
{
$this->fonts = $fonts;
}
/**
* Get fonts
*
* #return Doctrine\Common\Collections\Collection $fonts
*/
public function getFonts()
{
return $this->fonts;
}
/**
* Set slug
*
* #param string $slug
* #return Family
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string $slug
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set createdAt
*
* #param int $createdAt
* #return Family
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return int $createdAt
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* #MongoDB\PrePersist
*/
public function prePersist()
{
$this->setCreatedAt(time());
$slugService = new SlugService();
$this->setSlug($slugService->slug($this->getName()));
}
/**
* #MongoDB\PreUpdate
*/
public function preUpdate()
{
$slugService = new SlugService();
$this->setSlug($slugService->slug($this->getName()));
}
}
The form crash when I try to persist the object in the controller action_
$this->persist($family);
I tried lot of options but no one with good results. If you have some idea, please reply.