I have 3 form types (SearchForm - SearchField - SearchFieldType), each one including next like this:
SearchFormType:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SearchFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('fields', 'collection', array('type' => new SearchFieldType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false))
->add('submit', 'submit', array('label' => "Buscar"))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\SearchForm',
'allow_extra_fields' => true,
'csrf_protection' => false,
'validation_groups' => false,
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_searchform';
}
}
SearchFieldType:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SearchFieldType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'hidden')
->add('slug', 'hidden')
->add('value')
->add('choices')
->add('type', new SearchFieldTypeType())
->add('actionFilter')
->add('actionHighlight')
->add('actionShow')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\SearchField'
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_searchfield';
}
}
SearchFieldTypeType:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use AppBundle\Entity\SearchOperator;
class SearchFieldTypeType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$entity = $builder->getData();
$builder
->add('name', 'hidden')
->add('operators', 'entity', array('class' => 'AppBundle:SearchOperator',
'multiple' => false,
'expanded' => false))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\SearchFieldType'
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_searchfieldtype';
}
}
The form renders properly, but when I submit and try to do $form->handleRequest($request) I get an exception:
Neither the property "operators" nor one of the methods "addOperator()"/"removeOperator()", "setOperators()", "operators()", "__set()" or "__call()" exist and have public access in class "AppBundle\Entity\SearchFieldType"
That's not true actually, as those methods exist and work correctly:
AppBundle\Entity\SearchFieldType:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\SearchOperator;
/**
* SearchField
*
* #ORM\Table()
* #ORM\Entity
*/
class SearchFieldType
{
/**
* #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=100, nullable=true)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="SearchOperator", cascade={"persist", "remove"})
* #ORM\JoinTable(
* joinColumns={#ORM\JoinColumn(name="type_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="operator_id", referencedColumnName="id")}
* )
**/
private $operators;
/**
* Constructor
*/
public function __construct()
{
$this->operators = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return SearchFieldType
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add operator
*
* #param SearchOperator $operator
*
* #return SearchFieldType
*/
public function addOperator(SearchOperator $operator)
{
$this->operators[] = $operator;
return $this;
}
/**
* Remove operator
*
* #param SearchOperator $operator
*/
public function removeOperator(SearchOperator $operator)
{
$this->operators->removeElement($operator);
}
/**
* Get operator
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getOperators()
{
return $this->operators;
}
public function __toString()
{
return $this->name;
}
}
Stack trace:
in vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php at line 460 +
at PropertyAccessor ->writeProperty (object(SearchFieldType), 'operators', object(SearchOperator))
in vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php at line 104 +
at PropertyAccessor ->setValue (object(SearchFieldType), object(PropertyPath), object(SearchOperator))
in vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php at line 93 +
at PropertyPathMapper ->mapFormsToData (object(RecursiveIteratorIterator), object(SearchFieldType))
in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 633 +
at Form ->submit (array('operators' => '156', 'name' => 'string'), true)
in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 577 +
at Form ->submit (array('type' => array('operators' => '156', 'name' => 'string'), 'value' => 'felipe', 'name' => 'Nombre', 'slug' => 'nombre'), true)
in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 577
EDIT:
Controller Code :
$searchFormEntity = new SearchForm();
$searchFormWithValues = $this->createForm(new SearchFormType(), $searchFormEntity, array(
'action' => $this->generateUrl('candidato'),
'method' => 'POST'
));
$searchFormWithValues->add('submit', 'submit', array('label' => 'Buscar'));
$searchFormWithValues->handleRequest($request);
Well you have a ManyToMany relation, so it would make sense to have the operators field be a collection. However you defined it as an entity, so now the form expects to have the setOperators and getOperators methods as entity implies a ManyToOne or OneToOne relationship.
I think you need to change the statement in the class SearchFieldTypeType where adding the operators attribute to be the same as what you did before for fields in SearchFormType if you want to keep the ManyToMany relationship.
Related
Summary
I have three entities:
User, Organisation and OrganistionUser.
I created an Organisation form with an embedded collection of OrganisationUsers. This is working. What i can't get to work is that only Users without an assocciation (to an organisation) are 'queried' and show up in the selectbox in the OrganisationForm.
Details
Entitie 1: Organisation
class Organisation
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(type="string", nullable=true)
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="OrganisationUser", mappedBy="organisation_id", cascade={"persist", "remove"}, orphanRemoval=true)
*
* #Expose
*/
private $users;
Entitie 2: User
(I extended the FOSUserBundle)
<?php
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*/
protected $username;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="OrganisationUser", mappedBy="user_id", cascade={"ALL"}, orphanRemoval=true)
*/
protected $organisationusers;
I have succesfully embedded a collection of forms. In my 'create-new-organisation-form' i can add many users, and they are persisted to the database.
They are persisted in the OrganisationUser table (because i only want to associate EXISTING users to an organisation).
The OrganisationUser entity (so actually i have three entities) looks as:
Entitie 3: OrganisationUser
<?php
class OrganisationUser
{
protected $id;
/**
* #var ProjectId
* #ORM\ManyToOne(targetEntity="Organisation", inversedBy="organisationusers")
* #ORM\JoinColumn(name="organisation_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $organisation_id;
/**
* #var ProjectId
* #ORM\ManyToOne(targetEntity="User", inversedBy="organisationusers")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $user_id;
NOW, in my form (OrganisionType) i embedded a collection of OrganisationUser. But i want to manipulate the data (i do not want to show all users. Only the user that are NOT associated to an organisation). How can i achieve this. I already looked here and here but it's no solution for this question so i created a new question.
The OrganistionType:
<?php
class OrganisationType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('address')
->add('postal')
->add('city')
->add('phone')
->add('email')
->add('role');
$builder->add('users', 'collection', array(
'entry_type' => new OrganisationUserType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required' => false,
));
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Organisation',
));
}
}
And the OrganisationUserType:
<?php
class OrganisationUserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user_id', null ,array(
'label' => 'User'
))
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\OrganisationUser'
));
}
}
The controller
<?php
/**
* Organisation controller.
*
* #Route("/organisation")
*/
class OrganisationController extends Controller
{
/**
* Creates a new Organisation entity.
*
* #Route("/new", name="organisation_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$organisation = new Organisation();
$form = $this->createForm('AppBundle\Form\OrganisationType', $organisation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($organisation);
$em->flush();
return $this->redirectToRoute('organisation_show', array('id' => $organisation->getId()));
}
return $this->render('organisation/new.html.twig', array(
'organisation' => $organisation,
'form' => $form->createView(),
));
}
This is how it looks like when its rendered:
And, let's say if testuser3 is already associated with an organisation i dont want him to show up in the dropdown :)
Ok, i found it. In my OrganisationType i use the OrganisationUserType to embed the collection of users. So in the OrganisationUserType i had to query for the result:
Off course this is not the right query but i know now where to manipulate the data. Now i can go and search for the right query :)
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Doctrine\ORM\EntityRepository;
class OrganisationUserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user_id', 'entity', array(
'class' => 'AppBundle:User',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.id > :id')
->setParameter('id', '1')
->orderBy('u.username', 'ASC');
},
'choice_label' => 'username',
'required' => false,
));
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\OrganisationUser',
));
}
}
I already have to ask a question about a similar assert problem with FosUserBundle configuation.
But now I'm trying to run a simple form, but even with a esiest form => nothing is happening.
when i click on submit :
1) isValid() stay to false
2) No Assert message appears when input name is blank/empty
UserTmp.php (entity)
<?php
namespace BISSAP\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* BISSAP\UserBundle\Entity\User
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="BISSAP\UserBundle\Entity\UserRepository")
*/
class Usertmp
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="name", type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"})
* #Assert\Length(
* min=3,
* max=255,
* minMessage="The name is too short.",
* maxMessage="The name is too long.",
* groups={"Registration", "Profile"}
* )
*/
private $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Usertmp
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
UserType.php
<?php
namespace BISSAP\ForumBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text', array('required' => false))
->add('Envoyer', 'submit', array(
'attr' => array(
'class' => 'btn right-flt'
)));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BISSAP\UserBundle\Entity\Usertmp'
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array( 'data_class' => $this->class, 'intention' => 'Registration', ));
}
/**
* #return string
*/
public function getName()
{
return 'bissap_forumbundle_user';
}
}
TController.php
<?php
namespace BISSAP\ForumBundle\Controller;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use BISSAP\ForumBundle\Form\UserType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use BISSAP\UserBundle\Entity\Usertmp;
class TController extends Controller
{
public function indexAction()
{
$entity = new Usertmp();
$form = $this->createForm(new UserType(), $entity);
if ($form->isValid())
{
return $this->redirectToRoute('bissap_forum_index');
}
return $this->render('BISSAPForumBundle:T:index.html.twig', array('form'=> $form->createView(), 'errors_tmp' => $this->getErrorMessages($form)));
}
private function getErrorMessages(\Symfony\Component\Form\Form $form)
{
$errors = array();
foreach ($form->getErrors(true, false) as $error) {
// My personnal need was to get translatable messages
// $errors[] = $this->trans($error->current()->getMessage());
$errors[] = $error->current()->getMessage();
}
return $errors;
}
}
?>
index.html.twig
----> {{form( form )}}
{% for error in errors_tmp %}
<div>error : {{ error }}</div>
{% endfor %}
So, form didn't work cause : $form->handleRequest($request); missed in TController.php
In your UserType.php, try:
$resolver->setDefaults(array( 'data_class' => $this->class, 'intention' => 'Registration', 'validation_groups' => array('registration'),));
You can also set the validation group in your TController.php instead of hard-coding it on your UserType:
$form = $this->createForm(new UserType(), $entity, array('validation_groups' => 'registration'));
Source: Validation Groups
Also in your UserType.php you are saying that the name is not required, but at the same time you want to assert if it is not blank:
->add('name', 'text', array('required' => false))
Try removing that option too.
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
)
);
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';
}
}
I have the following relations:
[entity]SesiuneUtilitati-|one_to_one|->[entity]UtilitatiElectricitateCoeficient-|one_to_many|->[entity]UtilitatiElectricitate
I want to create a form that includes all 3 entities
And the code:
<?php
namespace Mnv\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* UtilitatiElectricitateCoeficient
*
* #ORM\Table(name="utilitati_electricitate_coeficient")
* #ORM\Entity(repositoryClass="Mnv\CoreBundle\Entity\Repository\UtilitatiElectricitateCoeficientRepository")
* #ORM\HasLifecycleCallbacks()
*/
class UtilitatiElectricitateCoeficient
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var decimal
*
* #ORM\Column(name="kwh", type="decimal", precision=20, scale=2, nullable=true)
*/
private $kwh;
/**
* #var decimal
*
* #ORM\Column(name="lei", type="decimal", precision=20, scale=2, nullable=true)
*/
private $lei;
/**
* #var decimal
*
* #ORM\Column(name="leikw", type="decimal", precision=20, scale=2, nullable=true)
*/
private $leikw;
/**
* #var decimal
*
* #ORM\Column(name="coeficient", type="decimal", precision=20, scale=2, nullable=true)
*/
private $coeficient;
/**
* #var string
*
* #ORM\Column(name="data_modificat", type="datetime", nullable=true)
*/
private $dataModificat;
/**
* #var string
*
* #ORM\Column(name="editat_de", type="string", length=50, nullable=true)
*/
private $editatDe;
/**
* #ORM\OneToOne(targetEntity="SesiuneUtilitati", inversedBy="utilitatiElectricitateCoeficient")
* #ORM\JoinColumn(name="id_sesiune", referencedColumnName="id_sesiune", onDelete="CASCADE")
*/
protected $sesiuneUtilitati;
/**
* #ORM\ManyToOne(targetEntity="Clienti", inversedBy="utilitatiElectricitateCoeficient")
* #ORM\JoinColumn(name="id_client", referencedColumnName="id_client")
*/
protected $clienti;
/**
* #ORM\OneToMany(targetEntity="UtilitatiElectricitate", mappedBy="utilitatiElectricitateCoeficient", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $utilitatiElectricitate;
public function __construct() {
$this->utilitatiElectricitate = new ArrayCollection();
}
...
}
<?php
namespace Mnv\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* UtilitatiElectricitate
*
* #ORM\Table(name="utilitati_electricitate")
* #ORM\Entity(repositoryClass="Mnv\CoreBundle\Entity\Repository\UtilitatiElectricitateRepository")
* #ORM\HasLifecycleCallbacks()
*/
class UtilitatiElectricitate
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var decimal
*
* #ORM\Column(name="kwh", type="decimal", precision=20, scale=2, nullable=true)
*/
private $kwh;
/**
* #var decimal
*
* #ORM\Column(name="pret", type="decimal", precision=20, scale=2, nullable=true)
*/
private $pret;
/**
* #var decimal
*
* #ORM\Column(name="total", type="decimal", precision=20, scale=2, nullable=true)
*/
private $total;
/**
* #var string
*
* #ORM\Column(name="data_modificat", type="datetime", nullable=true)
*/
private $dataModificat;
/**
* #var string
*
* #ORM\Column(name="editat_de", type="string", length=50, nullable=true)
*/
private $editatDe;
/**
* #ORM\ManyToOne(targetEntity="UtilitatiElectricitateCoeficient", inversedBy="utilitatiElectricitate")
* #ORM\JoinColumn(name="id_coeficient", referencedColumnName="id")
*/
protected $utilitatiElectricitateCoeficient;
/**
* #ORM\ManyToOne(targetEntity="dateClienti", inversedBy="utilitatiElectricitate")
* #ORM\JoinColumn(name="id_contract", referencedColumnName="id")
*/
protected $dateClienti;
...
}
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UtilitatiElectricitateCoeficientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('lei','text', array('required' => false));
$builder->add('coeficient','text', array('required' => false));
$builder->add('kwh','text', array('required' => false));
$builder->add('leikw','text', array('required' => false));
$builder->add('utilitatiElectricitate', 'collection', array(
'type' => new UtilitatiElectricitateType(),
'allow_add' => true,
'prototype' => false,
'by_reference' => false
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\UtilitatiElectricitateCoeficient',
'cascade_validation' => true,
));
}
public function getName()
{
return 'utilitati_electricitate_coeficient';
}
}
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UtilitatiElectricitateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('kwh','text', array('required' => false));
$builder->add('pret','text', array('required' => false));
$builder->add('total','text', array('required' => false));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\UtilitatiElectricitate',
'cascade_validation' => true,
));
}
public function getName()
{
return 'utilitati_electricitate';
}
}
public function indexAction(Request $request, $idSocietate)
{
$societate = $this->getSocietate($idSocietate);
$clienti = $this->getClienti($idSocietate);
$sesiuneUtilitati = new SesiuneUtilitati();
$dateClienti = new DateClienti();
$utilitatiElectricitateCoeficient = new UtilitatiElectricitateCoeficient();
$utilitatiElectricitate = new UtilitatiElectricitate();
$utilitatiElectricitateCoeficient->getUtilitatiElectricitate()->add($utilitatiElectricitate);
...
$form = $this->createForm(new SesiuneUtilitatiType(), $sesiuneUtilitati);
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
// Persist objects to database
$usr = $this->get('security.context')->getToken()->getUser();
$now = new \DateTime();
$date = $now->format("d-m-Y");
$dt = explode('-', $date);
$em = $this->getDoctrine()->getManager();
$sesiuneUtilitati->setSocietati($societate);
$sesiuneUtilitati->setAdaugataDe($usr->getUsername());
$sesiuneUtilitati->setZiua($dt[0]);
$sesiuneUtilitati->setLuna($dt[1]);
$sesiuneUtilitati->setAnul($dt[2]);
$em->persist($sesiuneUtilitati);
$em->flush();
$this->get('session')->getFlashBag()->set('tabel-util-notice', 'Datele au fost salvate cu succes.');
// Redirect - This is important to prevent users re-posting
// the form if they refresh the page
return $this->redirect($this->generateUrl('tabel_utilitati',array('idSocietate' => $idSocietate)));
}
}
return $this->render('MnvCoreBundle:Page:utilitati.html.twig', array(
'societate' => $societate,
'form' => $form->createView(),
'clienti' => $clienti,
));
}
What am i doing wrong here? The fields for the collection field utilitatiElectricitate are not available in twig.
For example if i try form.utilitatiElectricitateCoeficient.utilitatiElectricitate[0].kwh i get an error with key 0 does not exist.
SesiuneUtilitatiType is created to include all other forms like this:
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SesiuneUtilitatiType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('utilitatiTotal', new UtilitatiTotalType());
$builder->add('utilitatiElectricitateCoeficient', new UtilitatiElectricitateCoeficientType());
.
.
.
$builder->add('Salveaza datele si genereaza facturi', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\SesiuneUtilitati',
'cascade_validation' => true,
));
}
public function getName()
{
return 'sesiune_utilitati';
}
}
And UtilitatiElectricitateCoeficientType:
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UtilitatiElectricitateCoeficientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('lei','text', array('required' => false));
$builder->add('coeficient','text', array('required' => false));
$builder->add('kwh','text', array('required' => false));
$builder->add('leikw','text', array('required' => false));
$builder->add('utilitatiElectricitate', 'collection', array(
'type' => new UtilitatiElectricitateType(),
'allow_add' => true,
'prototype' => true,
'by_reference' => false
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\UtilitatiElectricitateCoeficient',
'cascade_validation' => true,
));
}
public function getName()
{
return 'utilitati_electricitate_coeficient';
}
}
And UtilitatiElectricitateType:
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UtilitatiElectricitateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('kwh','text', array('required' => false));
$builder->add('pret','text', array('required' => false));
$builder->add('total','text', array('required' => false));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\UtilitatiElectricitate',
'cascade_validation' => true,
));
}
public function getName()
{
return 'utilitati_electricitate';
}
}
You have to create a SesiuneUtilitatiType which you will embed into the UtilitatiElectricitateCoeficientType, now this last one will be embedded into UtilitatiElectricitateType. You should read the docs for embedded forms to have a clear view of what rules to follow