symfony3 image is not uploaded - image-uploading

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.

Related

Cannot insert multiple values with entity form when multiple is true

It throws an error when I submit the form with multiple=true: When is false everything works as expected and one value is inserted to the table.
Catchable Fatal Error: Argument 1 passed to AppBundle\Entity\CustomersProducts::setProducts() must be an instance of AppBundle\Entity\Products, instance of Doctrine\Common\Collections\ArrayCollection given, called in /var/www/html/app/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 556 and defined
Products.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\Products;
/**
* Products
*
* #ORM\Table(name="products")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProductsRepository")
*/
class Products
{
/**
* #ORM\OneToMany(targetEntity="CustomersProducts", mappedBy="products")
*/
private $products;
public function __toString() {
return $this->name;
}
public function addProducts(Products $request)
{
$this->products->add($request);
return $this;
}
public function removeProducts(Products $request)
{
$this->products->removeElement($request);
return $this;
}
public function __construct() {
$this->products= new ArrayCollection();
}
/**
* #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;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Products
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
CustomersProducts.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\Customers;
use AppBundle\Entity\Products;
/**
* CustomersProducts
*
* #ORM\Table(name="customers_products")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CustomersProductsRepository")
*/
class CustomersProducts
{
/**
* #ORM\ManyToOne(targetEntity="Customers", inversedBy="customers")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customers;
public function getCustomers()
{
return $this->customers;
}
public function setCustomers(Customers $customer) // Please add a Use statement on top of your document
{
$this->customers = $customer;
return $this;
}
/**
* #ORM\ManyToOne(targetEntity="Products", inversedBy="products")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
private $products;
public function getProducts()
{
return $this->products;
}
public function setProducts(Products $products) // Please add a Use statement on top of your document
{
var_dump($products->getName()); die();
$this->products = $products;
return $this;
}
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="version", type="string", length=255)
*/
private $version;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set version
*
* #param string $version
* #return CustomersProducts
*/
public function setVersion($version)
{
$this->version = $version;
return $this;
}
/**
* Get version
*
* #return string
*/
public function getVersion()
{
return $this->version;
}
}
CustomersProductsType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CustomersProductsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('version')
->add('customers', 'entity', array(
'class' => 'AppBundle:Customers',
'multiple' =>false,
'property' => 'name',
))
->add('products', 'entity', array(
'class' => 'AppBundle:Products',
'multiple' =>true,
'property' => 'name',
))
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\CustomersProducts'
));
}
}
UPDATE:
After the change I'made from the suggestion now I get the following error:
Found entity of type Doctrine\Common\Collections\ArrayCollection on association AppBundle\Entity\CustomersProducts#products, but expecting AppBundle\Entity\Product
You have to rename entity Products to Product, because class that representing one database row (an entity) should have singular name.
Grammatically incorrect method name addProducts:
public function addProducts(Products $request)
refactor it to:
public function addProduct(Product $product) {
if ($this->products->contains($product)) {
return;
}
$this->products->add($product);
}
The same with remove method:
public function removeProducts(Products $request)
refactor to:
public function removeProduct(Product $product) {
if (!$this->products->contains($product)) {
return;
}
$this->products->removeElement($product);
}
Changes to CustomersProducts
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="products")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
private $product;
public function getProduct()
{
return $this->product;
}
public function setProduct(Product $product)
{
$this->product = $product;
}
You can find similar example and explanation in the article

Embedding collection of forms and adding multiple files in Symfony 2

I'm following the tutorial here: embed collection of forms symfony2
The example works, but when I try to add filetype field, I got the following error:
Error: Call to a member function move() on a non-object
and don't know why. I can add as many fieldType fields as I want dynamically, but the problem is with the above error.
Here is my code:
TagType.php
namespace Bundle\MyBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//$builder->add('name');
$builder->add('file','file',array('label' => 'Load file'));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bundle\MyBundle\Entity\Tag',
));
}
public function getName()
{
return 'tag';
}
}
TaskType.php
namespace Bundle\MyBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description');
$builder->add('file', 'collection', array(
'type' => new TagType(),
'allow_add' => true,
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bundle\MyBundle\Entity\Task',
));
}
public function getName()
{
return 'task';
}
}
Task.php
/**
* Task
*/
class Task
{
/**
* #var string
*/
protected $description;
/**
* #var string
*/
protected $tags;
/**
* #var integer
*/
/**
* #var string
*/
protected $file;
/**
* #var string
*/
protected $path;
protected $id;
public function __construct()
{
$this->tags = new ArrayCollection();
}
/**
* Set description
*
* #param string $description
* #return Task
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set tags
*
* #param string $tags
* #return Task
*/
public function setTags($tags)
{
$this->tags = $tags;
}
/**
* Get tags
*
* #return string
*/
public function getTags()
{
return $this->tags;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set file
*
* #param string $file
* #return Task
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
$user_folder = $this->getId();
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/task/';
}
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move(
$this->getUploadRootDir(),
$this->getFile()->getClientOriginalName()
);
// set the path property to the filename where you've saved the file
return $this->path = $this->getFile()->getClientOriginalName();
// clean up the file property as you won't need it anymore
$this->file = null;
}
}
Tag.php
class Tag
{
/**
* #var string
*/
private $file;
/**
* #var string
*/
private $path;
/**
* #var string
*/
public $name;
/**
* Set name
*
* #param string $name
* #return Task
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set file
*
* #param string $file
* #return Task
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
/**
* Set path
*
* #param string $path
* #return Task
*/
public function setPath($path)
{
$this->path = $path;
return $this;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
$user_folder = $this->getId();
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/task/';
}
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move(
$this->getUploadRootDir(),
$this->getFile()->getClientOriginalName()
);
// set the path property to the filename where you've saved the file
return $this->path = $this->getFile()->getClientOriginalName();
// clean up the file property as you won't need it anymore
$this->file = null;
}
}
Controller:
$task = new Task();
$form = $this->createForm(new TaskType(), $task);
$form->add('submit', 'submit', array('label' => 'Create'));
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$task->upload();
//$task->setTags($val);
$em->persist($task);
$em->flush();
$em->clear();
}

Doctrine2 inverse persistance not working in nested forms

I am creating a MotorsAds entity to which I am linking with MotorsAdsFile entity. For each MotorsAds, we could attach many MotorsAdsFile.
My objective is creating a form for MotorsAds which allows adding MotorsAdsFile just through a click on a button. Here, I am trying to implement the embeded forms.
My problem is that I got that error:
An exception occurred while executing 'INSERT INTO MotorsAdsFile (filename, motors_id) VALUES (?, ?)' with params ["5493b613839d7_2012-07-02 22.06.00.jpg", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'motors_id' cannot be null
Probably, the MotorsAds object is not persisted yet: that's why the Column 'motors_id' is null. Could you help in this issue?
Have I missed something?
1. Definition of the entities
MotorsAdsFile
<?php
namespace Minn\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity
* #Vich\Uploadable
*/
class MotorsAdsFile {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #Assert\File(
* maxSize="5M",
* mimeTypes={"image/png", "image/jpeg"}
* )
* #Vich\UploadableField(mapping="motors_files", fileNameProperty="filename")
*/
protected $file;
/**
* #ORM\Column(type="string", length=255, name="filename")
* #var string $filename
*/
protected $filename;
/**
* #ORM\ManyToOne(targetEntity="Minn\AdsBundle\Entity\MotorsAds", inversedBy="files")
* #ORM\JoinColumn(nullable=false,onDelete="CASCADE")
*/
private $motors;
/**
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $file
*/
public function setFile(File $file) {
$this->file = $file;
}
/**
* #return File
*/
public function getFile() {
return $this->file;
}
/**
* #param string $filename
*/
public function setFilename($filename) {
$this->filename = $filename;
}
/**
* #return string
*/
public function getFilename() {
return $this->filename;
}
/**
* Set motors
*
* #param \Minn\AdsBundle\Entity\MotorsAds $motors
* #return MotorsAds
*/
public function setMotors(\Minn\AdsBundle\Entity\MotorsAds $motors) {
$this->motors = $motors;
return $this;
}
/**
* Get motors
*
* #return \Minn\AdsBundle\Entity\MotorsAds
*/
public function getMotors() {
return $this->motors;
}
}
MotorsAds
<?php
namespace Minn\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* MotorsAds
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Minn\AdsBundle\Entity\MotorsAdsRepository")
* #ORM\HasLifecycleCallbacks()
*/
class MotorsAds {
// ...
/**
* #ORM\OneToMany(targetEntity="Minn\AdsBundle\Entity\MotorsAdsFile",
* mappedBy="motors",
* cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=true)
*/
private $files;
public function __construct() {
$this->files = new \Doctrine\Common\Collections\ArrayCollection();
$this->favorites = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getFiles() {
return $this->files;
}
public function addFile(MotorsAdsFile $file) {
$this->files[] = $file;
return $this;
}
public function removeFile(MotorsAdsFile $file) {
$this->files->removeElement($file);
}
// ...
}
2. The forms
MotorsAdsFileType
class MotorsAdsFileType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('file', 'file',array('required' => false));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Minn\AdsBundle\Entity\MotorsAdsFile'
));
}
public function getName() {
return 'MotorsAdsFiletype';
}
}
MotorsAdsType
class MotorsAdsType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
// ...some code here
$builder->add('files','collection',array('type'=> new MotorsAdsFileType(),
'allow_add'=> true,
'allow_delete' => true,
'by_reference' => true));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Minn\AdsBundle\Entity\MotorsAds'
));
}
public function getName() {
return 'MotorsAdstype';
}
}
I
I found the solution...
Two things have to be done:
(1)
public function buildForm(FormBuilderInterface $builder, array $options) {
// ...some code here
$builder->add('files','collection',array('type'=> new MotorsAdsFileType(),
'allow_add'=> true,
'allow_delete' => true,
'by_reference' => false)); // it has to be set to false and not true
}
(2)
public function addFile(MotorsAdsFile $file) {
$file->setMotors($this); // you have to add this line too
$this->files[] = $file;
return $this;
}

How to edit embedded form with file upload in symfony2 and doctrine 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();
}
}

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.