Doctrine2 inverse persistance not working in nested forms - 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;
}

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.

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

Call to a member function getRepository() on a non-object

I am new In symfony2 with mongoDB, I am creating one relationship with document relation using ODM. I facing above issue when I creating form type, My file code as below
File path: /src/AppBundle/Form/Type/ProductFormType.php
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ProductFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text', array('label' => 'Product Name'))
->add('description', 'textarea',array('label' => 'Description'))
->add('Category', 'document', array(
'label'=>'Product Category',
'class' => 'AppBundle:Category',
'property' => 'name',
))
->add('save', 'submit');
}
public function getName()
{
return 'product';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Document\Product'
));
}
}
?>
File: src/AppBundle/Document/product.php
<?php
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;
/** #ODM\Document */
class Product
{
/** #ODM\Id */
private $id;
/** #ODM\String */
protected $name;
/** #ODM\String */
protected $description;
/** #ODM\ReferenceOne(targetDocument="Category", cascade="all") */
private $Category;
public function getId() { return $this->id; }
public function getName() { return $this->name; }
public function setName($name) { $this->name = $name; }
/**
* Set category
*
* #param AppBundle\Document\Category $category
* #return self
*/
public function setCategory(\AppBundle\Document\Category $category)
{
$this->Category = $category;
return $this;
}
/**
* Get category
*
* #return AppBundle\Document\Category $category
*/
public function getCategory()
{
return $this->Category;
}
public function getDescription() { return $this->description; }
public function setDescription($description) { $this->description = $description; }
}
File src/Appbundle/Docment/Category.php
<?php
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
//** #ODM\Document */
class Category
{
/** #ODM\Id */
protected $id;
/** #ODM\String */
protected $cat_id;
/** #ODM\String */
protected $categoryname;
/** #ReferenceMany(targetDocument="Product" mappedBy="category") */
private $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
/**
* Add product
*
* #param \AppBundle\Document\Product $product
*
* #return Category
*/
public function addProduct(\AppBundle\Document\Product $product)
{
$this->products[] = $product;
return $this;
}
/**
* Remove product
*
* #param \AppBundle\Document\Product $product
*/
public function removeProduct(\AppBundle\Document\Product $product)
{
$this->products->removeElement($product);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
public function getId()
{
return $this->id;
}
public function getCat_id() { return $this->cat_id; }
public function setCat_id($cat_id) { $this->cat_id = $cat_id; }
public function getDescription() { return $this->categoryname; }
public function setDescription($categoryname) { $this->categoryname = $categoryname; }
}
I also tried Following process :
getter-setter for MongoDB
php app/console doctrine:mongodb:generate:documents AppBundle
Then clear cache and set developer enviroment
can anybody have a solutions, Please help me.
Thanks in Advance

Error using A2lix as an embedded form

I'm using A2lix Translation Form Bundle and Doctrine Behaviors Translatable in a project where I have two entities: company and files. Company has some translatable fields so I have a CompanyTranslations Entity for that. One company can have one file so Company and file are mapped with an OneToOne unidirectional reference. The company file is translatable so the property is in the CompanyTranslation file.
CompanyTranslation:
class CompanyTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #ORM\OneToOne(targetEntity="File", cascade={"persist"})
* #ORM\JoinColumn(name="translatable_file_id", referencedColumnName="id")
* #Assert\Valid()
* #Assert\Type(type="MyApp\CoreBundle\Entity\File")
**/
private $translatableFile;
/**
* Set translatableFile
*
* #param $translatableFile
*/
public function setTranslatableFile(File $translatableFile = null)
{
$this->translatableFile = $translatableFile;
}
/**
* Get translatableFile
*
* #return $translatableFile
*/
public function getTranslatableFile()
{
return $this->translatableFile;
}
}
File:
class File
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $filePath;
/**
* #Assert\File()
*/
private $file;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set filePath
*
* #param string $filePath
*/
public function setFilePath($filePath)
{
$this->filePath = $filePath;
}
/**
* Get filePath
*
* #return string
*/
public function getFilePath()
{
return $this->filePath;
}
/**
* Set file
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
/**
* Get file
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
}
File Form Type:
class FileType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file', array(
'label' => false
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MyApp\CoreBundle\Entity\File'
));
}
public function getName()
{
return 'file_form';
}
}
Company Form Type:
class CompanyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('translations', 'a2lix_translationsForms', array(
'locales' => $this->languages,
'form_type' => new FileType(),
'form_options' => array(
'data_class' => 'MyApp\CoreBundle\Entity\File',
'required' => false,
'validation_groups' => array('file_upload')
)
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
parent::setDefaultOptions($resolver);
$resolver->setDefaults(array(
'data_class' => 'MyApp\CoreBundle\Entity\Company'
));
}
}
The error is this one:
The form's view data is expected to be an instance of class MyApp\CoreBundle\Entity\File, but is an instance of class MyApp\CoreBundle\Entity\CompanyTranslation. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class MyApp\CoreBundle\Entity\CompanyTranslation to an instance of MyApp\CoreBundle\Entity\File.
I already set the data_class of the File Type Form and the data_class of the field to null but also to MyApp\CoreBundle\Entity\File. Both send me errors. I don't know what's happening.
Could anyone help?
Thanks!

Symfony2 (2.7) Form Entity Data Transformer

I'm trying to customize a selection list's text while using the entity's ID. This is because I want the list options to be specific to the authenticated user. The database text values are Full Name, By City and State, and Anonymous, but I want it to actually display the user's full name (John Smith), User in Denver, CO, and Anonymous. I'm attempting to use a view data transformer to achieve this, but with no luck. I'd rather not use Javascript to achieve this if possible.
Here's my main form type:
<?php
namespace Members\MessagesBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\SecurityContext;
class MessageType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('viewability', 'viewability_entity', array(
'class' => 'MessagesBundle:Viewability',
'property' => 'name',
'required' => true,
))
->add('body', new MessageBodyType())
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Members\MessagesBundle\Entity\Message',
));
}
/**
* #return string
*/
public function getName()
{
return 'members_messages_message';
}
}
Here's my custom form type for Viewability (the entity which I would like to transform):
<?php
namespace Members\MessagesBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\SecurityContext;
use Members\MessagesBundle\Form\DataTransformer\MessageNameTransformer;
class ViewabilityType extends AbstractType
{
private $context;
/**
* #param SecurityContext $context
*/
public function __construct(SecurityContext $context)
{
$this->context = $context;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new MessageNameTransformer($this->context);
$builder->addViewTransformer($transformer);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'invalid_message' => 'The selected issue does not exist',
));
}
/**
* #return string
*/
public function getParent()
{
return 'entity';
}
/**
* #return string
*/
public function getName()
{
return 'viewability_entity';
}
}
Here's my service which defines the Viewability Type:
members.messages.form.type.viewability_entity:
class: Members\MessagesBundle\Form\ViewabilityType
tags:
- { name: form.type, alias: viewability_entity }
arguments: [#security.context]
Here's my Viewability Entity:
<?php
namespace Members\MessagesBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class Viewability
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
public function __construct()
{
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
}
Finally, here's my data transformer:
<?php
namespace Members\MessagesBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Members\MessagesBundle\Entity\Viewability;
use Symfony\Component\Security\Core\SecurityContext;
class MessageNameTransformer implements DataTransformerInterface
{
private $user;
/**
* #param SecurityContext $context
*/
public function __construct(SecurityContext $context)
{
$this->user = $context->getToken()->getUser();
}
/**
* #param Viewability|null $viewability
* #return string
*/
public function transform($viewability)
{
if (null === $viewability) {
return '';
}
if($viewability === 'Full Name')
return sprintf('%s %s', $this->user->getInfo()->getFirstName(), $this->user->getInfo()->getLastName());
if($viewability === 2)
return sprintf('Lawyer in %s, %s', $this->user->getInfo()->getAddress()->getCity(), $this->user->getInfo()->getAddress()->getState());
if($viewability === 3)
return 'Anonymous';
}
/**
* #param Viewability $viewability
* #return Viewability
*/
public function reverseTransform($viewability)
{
return $viewability;
}
}
The data passed into transform() always seems to be null or "" (empty string).
Thanks for any help.
So I ended up taking a different approach to solving this. Originally I was trying to transform data coming from an entity. Fortunately this entity didn't really need to be a database entity after all and a simple choice type sufficed. This doesn't solve the specific issue of transforming an entity list, but it allows me to customize the drop down list values.
The viewability entity was removed and the relationship in the Message entity was changed to an integer field.
My main type is now as follows:
class MessageType extends AbstractType
{
private $user;
public function __construct($user)
{
$this->user = $user;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('body', new MessageBodyType())
->add('viewability', 'choice', array(
'choices' => array(
1 => $user->getFirstName(),
2 => $user->getAddress()->getCity(),
3 => 'Anonymous',
),
'multiple' => false,
'label' => 'Send Message As',
'data' => 0,
))
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Members\MessagesBundle\Entity\Message',
));
}
/**
* #return string
*/
public function getName()
{
return 'members_messages_message';
}
}