How to render a choice field in a template - forms

I use Symfony2 and twig as template engine.
In my controller I have the following form:
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = array($usr->getMissions());
$form = $this->createFormBuilder($product)
->add('mission', 'choice', array(
'choices' => $associatedmission,
'multiple' => false,
'expanded' => true, ))
But when I call the page, appears an error:
Catchable Fatal Error: Object of class Doctrine\ORM\PersistentCollection could not be
converted to string in
C:\BitNami\wampstack-5.4.23-
0\frameworks\symfony\vendor\symfony\symfony\src\Symfony\Component\Translation\
IdentityTranslator.php line 65
In the profiler I can see the error:
CRITICAL - Uncaught PHP Exception Twig_Error_Runtime: "An exception has been thrown
during the rendering of a template ("") in "form_div_layout.html.twig" at line 99." at
C:\BitNami\wampstack-5.4.23-0\frameworks\symfony\app\cache\dev\classes.php line 4372
Context: {"exception":"Object(Twig_Error_Runtime)"}
What happened?
It's strange because with it works properly
->add('mission', 'entity')
-UPDATE--
Here my controller:
public function createAction(Request $request)
{
$product = new Product();
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = array($usr->getMissions());
$form = $this->createFormBuilder($product)
->add('name', 'text')
->add('mission', 'choice', array(
'choices' => $associatedmissions,
'multiple' => false,
'expanded' => false, ))
->add('save', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('AcmeGroundStationBundle:Product:tasksuccess.html.twig', array('product' => $product));
}
return $this->render('AcmeGroundStationBundle:Product:formupload.html.twig', array(
'form' => $form->createView()
));
}

aYou have this in your controller:
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = array($usr->getMissions());
$usr->getMissions() is returning ArrayCollection (based on relations in your Entity). This way $associatedmissions is an array with one element - [1] = ArrayCollection of related Mission Objects.
In my opinion you must add to your User entity method:
public function getMissionsArray()
{
$missionArray = array();
foreach ($this->missions as $key => $val)
{
$missionArray[$key] = $val->__toString();
}
return $missionArray;
}
And use array as choices param in your createFormBuilder statement.
When you validate your Form you have to create Mission object for every selection before persist product.
$this->getDoctrine()
->getRepository('AcmeGroundStationBundle:Mission')
->find($product->mission);
EDIT
// User Entity
// add this function - will return array of ( id => mission.name, )
public function getMissionsArray()
{
$missionArray = array();
foreach ($this->missions as $key => $val)
{
// change this to whatever human readable getter
$missionArray[$key] = $val->__toString();
}
return $missionArray;
}
// Controller
public function createAction(Request $request)
{
$product = new Product();
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = $usr->getMissionsArray();
$form = $this->createFormBuilder($product)
->add('name', 'text')
->add('mission', 'choice', array(
'choices' => $associatedmissions,
'multiple' => false,
'expanded' => false, ))
->add('save', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
// save selected array item as a Mission object related to Product
$product->setMission($this->getDoctrine()
// check if Mission Entity is placed in good bundle ;)
->getRepository('AcmeGroundStationBundle:Mission')
->find($form->get('mission')->getData()));
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('AcmeGroundStationBundle:Product:tasksuccess.html.twig', array('product' => $product));
}
return $this->render('AcmeGroundStationBundle:Product:formupload.html.twig', array(
'form' => $form->createView()
));
}
Good Luck!

Try to use redirect. Is it work?
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirect($this->generatePath('current_route_name'));
}
return $this->render('AcmeGroundStationBundle:Product:formupload.html.twig', array(
'form' => $form->createView()
));
Where current_route_name is replace by your route name of current page.

Related

Symfony2 Form Events without entity

I want to make a search form that acts independently from the entity, so there's no entity, and a choice field is dynamically loaded from other using FormEvents but no matter what always getting $formE->getData() NULL
this is my code of the controller
public function indexAction(Request $request)
{
$form = $this->createFormBuilder()
->add('Numero', TextType::class,array('required' => false,))
->add('FechaIngresoRango',TextType::class,array('required' => false,))
->add('Criterio', ChoiceType::class, array(
'choices' => array(
'' => '-Seleccione Opcion-',
'form_Numero' => 'NUMERO',
'form_Sector' => 'AREA',
'inputGroupsTema' => 'TEMA',
'form_FechaIngresoRango' => 'FECHA INGRESO',
),'required' => true))
->add('Sector','entity', array(
'class' => 'AppBundle\Entity\Sector',
'property' => 'nombre',
'required' => false
))
->add('Tema','entity', array(
'class' => 'AppBundle\Entity\TipoTemaExpediente',
'property' => 'tipoTemaExpediente',
'required' => false
))->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$formE = $event->getForm();
$data = $event->getData();
var_dump($data);
{
$em = $this->getDoctrine()->getManager();
$tiposSubTema = $em->getRepository('AppBundle:TipoSubTemaExpediente')->findAll();
//$tipoTema = $data->getTipoTemaExpediente();
$formE->add('tipoSubTemaExpediente',EntityType::class,array(
'class' => 'AppBundle:TipoSubTemaExpediente',
'property' => 'subTemaExpediente',
'choices' => $tiposSubTema,
));
}
//else
{
//$formE->add('tipoSubTemaExpediente',ChoiceType::class, array('attr' => array('disabled' => true),));
}
})
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$data = $form->getData();
// switch ($data['Criterio']){
// case "form_Numero" :
// var_dump($data['Numero']);
// break;
// case "form_Sector" :
// var_dump($data['Sector']->getId());
// break;
// case "inputGroupsTema" :
// var_dump($data['Tema']->getTipoTemaExpediente());
// break;
// case "form_FechaIngresoRango" :
// var_dump($data['FechaIngresoRango']);
// break;
// }
}
the comments are from several test that I did, on post works flawlessly the problem is the event, I'm starting to think that if no entity is related on the form creation there's no way that this going to work, is that so?

Cant set default data for choice field when using EventListener on Form field

I have a form with dynamic choice field "languages". The languages can be diffrent for diffrent categories. I want them tho be all checked by default, so I use 'data' option for this. But it only works if I dont use Events. If I try to use it in my $formModifier function to add languages dynamically it will not work, and all languages are unchecked... Any idea how to fix it ?
Here is my buildForm function from ProjectType class
public function buildForm(FormBuilderInterface $builder, array $options)
{
(...)
$builder
->add('category', 'choice', array(
'choices' => Category::$NAMES,
'multiple' => false,
'placeholder' => '',
))
->add('name', 'text')
->add('description', 'textarea', array(
'attr' => array('rows' => '10', 'class' => 'tinymce'),
))
->add('save', 'submit', array('label' => 'form.save'));
$formModifier = function (FormInterface $form, User $user, $category = null) {
$languages = null === $category ? array() : $this->userReputation->getAllowedLanguages($user, $category);
$form->add('languages', 'choice', array(
'multiple' => true,
'expanded' => true,
'choices' => $languages,
'data' => array_keys($languages),
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier, $user) {
$project = $event->getData();
$formModifier($event->getForm(), $user, $project->getCategory());
}
);
$builder->get('category')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier, $user) {
$category = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $user, $category);
}
);
}
I have this script in view to make ajax calls when category is changed by the user:
<script>
function requireReadyFunction() {
var $category = $('#project_category');
// When category gets selected ...
$category.change(function() {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected category value.
var data = {};
data[$category.attr('name')] = $category.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current languages field ...
$('#project_languages').replaceWith(
$(html).find('#project_languages')
);
}
});
});
}
</script>

symfony2 neither property nor method exists in class

One route on click on button is for this controller:
public function addAction(Request $request){
$em = $this->getDoctrine()->getManager();
$spotEntity = $this->getCurrentSpot();
$permitsidrand = rand(0, 1000000000000);
$currentDate = new DateTime();
$permitsrepo = new Permits();
$permitsrepo->setCreatedat($currentDate);
$permitsrepo->setPermitid($permitsidrand);
$permitsrepo->setPermitsSpot($spotEntity);
$em->persist($permitsrepo);
$em->flush();
return $this->redirect($this->generateUrl('permits_add', array('id' => $permitsrepo->getId())));
}
So I want to make new Object and fill it with couple variables and after it I want to redirect to screen with form that will be updating my record from database which I just added.
Here is second function (this one that I am redirecting to after click in button)
public function addfullAction(Request $request, $id){
$permitsidrand = rand(0, 1000000000000);
$currentDate = new DateTime();
$permitsrepo = $this->getDoctrine()->getRepository('MainCoreBundle:Permits');
$perm= $permitsrepo->find($id);
$form = $this->createForm(new PermitsType(), $permitsrepo);
$permitsrepo->setCreatedat($currentDate);
$permitsrepo->setPermitid($permitsidrand);
$permitsrepo->setPermitsSpot($spotEntity);
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($permitsrepo);
$em->flush();
return $this->redirect($this->generateUrl('permits_show'));
}
}
return $this->render('MainAdminBundle:Permits:add.html.twig', $this->getViewConstants(array(
'form' => $form->createView(),
'rand' =>$permitsidrand
)));
}
And when I click that Button that I mantion I have this error message:
Neither property "PermitsContractor" nor method "getPermitsContractor()" nor method "isPermitsContractor()" exists in class "Main\CoreBundle\Entity\PermitsRepository"
Here is my form
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('PermitsContractor', 'entity', array(
'class' => 'MainCoreBundle:Generalcontractor',
'multiple' => false,
'expanded' => false,
'property'=>'name',
'label'=> 'Generalny wykonawca',
));
$builder->add('PermitsCompany', 'entity', array(
'class' => 'MainCoreBundle:Company',
'multiple' => false,
'expanded' => false,
'property'=>'name',
'label'=> 'Firma',
));
$builder->add('Permitname', 'text',array('label'=> "Imię", 'required'=>false));
$builder->add('Permitsurname', 'text',array('label'=> "Nazwisko", 'required'=>false));
$builder->add('expirationdate', 'date', array(
'widget' => 'single_text',
'label'=> 'Data ważności',
));
$builder->add('file', 'file', array('required'=>false, 'label'=>'Przeglądaj'));
}
public function getName() {
return 'main_admin_permits_type';
}
I checkout and I got getters and setters in Entities
The error is here
$perm = $permitsrepo->find($id);
$permitsrepo->setCreatedat($currentDate);
$permitsrepo->setPermitid($permitsidrand);
$permitsrepo->setPermitsSpot($spotEntity);
Use
$perm = $permitsrepo->find($id);
$perm->setCreatedat($currentDate);
$perm->setPermitid($permitsidrand);
$perm->setPermitsSpot($spotEntity);

ManyToMany, duplicate entry, table empty

Soo :
I have my two tables/entities texts and groups which are linked by a manytomany relationship.
I have a form where the users fill checkboxes to assign a text into one or several groups.
I have a problem though it's getting me this error
An exception occurred while executing 'INSERT INTO texte_groupe
(texte_id, groupe_id) VALUES (?, ?)' with params [2, 1]:
Here is the core of the problem ( i think?)
public function AcceptMediaAction($id) {
$em = $this->getDoctrine()->getManager();
$texte = new Texte();
$securityContext = $this->container->get('security.context');
$texte = $em->getRepository('EVeilleurDefuntBundle:Texte')->find($id);
$form = $this->createForm( new ChooseGroupeType($securityContext), $texte );
$request = $this->get('request');
$form->bind($request);
if ($request->getMethod() == 'POST') {
$groupes = $texte->getGroupes();
$statut = $texte->getStatut();
foreach ($groupes->toArray() as $groupe)
{
$texte->addGroupe($groupe);
}
$em->persist($groupe);
$em->flush();
return $this->redirect($this->generateUrl('e_veilleur_defunt_gerer_medias',
Groupe.php
/**
* #ORM\ManyToMany(targetEntity="EVeilleur\DefuntBundle\Entity\Texte",mappedBy="groupes")
*/
private $textes;
Texte.php
/**
* #ORM\ManyToMany(targetEntity="EVeilleur\DefuntBundle\Entity\Groupe",inversedBy="textes")
*/
private $groupes;
formtype
public function buildForm(FormBuilderInterface $builder, array
$options)
{
// $builder->add('statut','choice', array('choices'=> array('nonValide'=>'non Valide',
// 'Valilde'=>'suchValidation'),
// 'required'=>'true'
// )
// ) ; // , array("attr" => array("multiple" => "multiple", ))
$user = $this->securityContext->getToken()->getUser();
if (!$user) {
throw new \LogicException(
'This cannot be used without an authenticated user!'
);
}
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($user) {
$form = $event->getForm();
$formOptions = array(
'multiple' => true, //several choices
'expanded' => true, // activate checkbox instead of list
'by_reference' => false,
'required' => true|false,
'class' => 'EVeilleur\DefuntBundle\Entity\Groupe',
'query_builder' => function (EntityRepository $er) use ($user) {
// build a custom query
return $er->createQueryBuilder('u')->add('select', 'u')
->add('from', 'EVeilleurDefuntBundle:Groupe u');
// ->add('where', 'u.id = ?1')
// ->add('orderBy', 'u.name ASC');
},
);
// create the field, = $builder->add()
// field name, field type, data, options
$form->add('groupes', 'entity', $formOptions);
}
);
}
Thanks
Try with:
foreach ($groupes->toArray() as $groupe) {
if (!in_array($groupe, $texte->getGroupe()->toArray()) {
$texte->addGroupe($groupe);
}
}

$form->isValid says it is invalid, but my form does not show any error message - Zend Framework 2

Im having a problem with the addAction in my CRUD application. On the controller the logic does not pass the $form->isValid() verification but the form does not show any error message.
I tried with this (Thanks Sam):
foreach($form->get('product')->getElements() as $el)
{
echo $el->getName()." = ".$el->getValue()." > ".$el->getMessages()." <br/>";
}
That only show the name and value of the field, but not the error message.
I've tried letting the form totally blank and it fire "Value is required and can't be empty" error messages, but then, i fill each field one by one until i don't get more error messages but the form still invalid.
My form has a Product Fieldset as a base fieldset and a submit button. Inside Product Fieldset i have an ID field, a name field, a price field and a Brand Fieldset. Inside my Brand Fieldset i have a id field. Like this:
ProductForm:
class ProductForm extends Form
{
public function init()
{
// we want to ignore the name passed
parent::__construct('product');
$this->setName('product');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'product',
'type' => 'Administrador\Form\ProductFieldset',
'options' => array(
'use_as_base_fieldset' => true
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Add',
'id' => 'submitbutton',
),
));
}
}
ProductFieldset:
class ProductFieldset extends Fieldset implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
function __construct($name = null)
{
parent::__construct('product_fieldset');
$this->setHydrator(new ArraySerializableHydrator());
$this->setObject(new Product());
}
public function init()
{
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'name',
'type' => 'Text',
'options' => array(
'label' => 'Name',
),
));
$this->add(array(
'name' => 'price',
'type' => 'Text',
'options' => array(
'label' => 'Price',
),
));
$this->add(array(
'name' => 'brand',
'type' => 'BrandFieldset',
));
}
public function setServiceLocator(ServiceLocatorInterface $sl)
{
$this->serviceLocator = $sl;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
BrandFieldset:
class BrandFieldset extends Fieldset
{
function __construct(BrandTable $brandTable)
{
parent::__construct('brand_fieldset');
//$this->setHydrator(new ClassMethodsHydrator(false))->setObject(new Brand());
$this->setHydrator(new ArraySerializableHydrator());
$this->setObject(new Brand());
$brandSelectOptionsArray = $brandTable->populateSelectBrand();
$this->add(array(
'name' => 'id',
'type' => 'Select',
'options' => array(
'label' => 'Brand',
'empty_option' => 'Please select a brand',
'value_options' => $brandSelectOptionsArray,
),
));
}
}
This is my new Form statement in the addAction:
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
Inside my model 'Product' i have the inputFilters, required filter for 'id' field, required filter for 'name' field. And for the Brand field i created other inputFilter and added it to the main inputFilter:
$brandFilter->add($factory->createInput(array(
'name' => 'id',
'required' => true,
'filters' => array(
array('name' => 'Int'),
),
)));
$inputFilter->add($brandFilter, 'brand');
The weird behavior is that my editAction works fine and has the same logic.
Is it there any form of echoing an internal error message from the form, something that helps me to understand WHY the form is not valid.
EDIT 2013-06-01
Here is my full Controller:
class ProductController extends AbstractActionController
{
protected $productTable;
protected $brandTable;
public function indexAction()
{
return new ViewModel(array(
'products' => $this->getProductTable()->fetchAll(),
));
}
public function addAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$product = new Product();
$product->brand = new Brand();
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$product->exchangeArray($form->getData());
$this->getProductTable()->saveProduct($product);
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return new ViewModel(array(
'form' => $form,
));
}
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('product', array(
'action' => 'add'
));
}
// Get the Product with the specified id. An exception is thrown
// if it cannot be found, in which case go to the index page.
try {
$product = $this->getProductTable()->getProduct($id);
}
catch (\Exception $ex) {
return $this->redirect()->toRoute('product', array(
'action' => 'index'
));
}
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$brand = $this->getBrandTable()->getBrand($product->brand);
$product->brand = $brand;
$form->bind($product);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getProductTable()->saveProduct($form->getData());
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
public function deleteAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('product');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->getPost('del', 'No');
if ($del == 'Yes') {
$id = (int) $request->getPost('id');
$this->getProductTable()->deleteProduct($id);
}
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
return array(
'id' => $id,
'product' => $this->getProductTable()->getProduct($id)
);
}
public function getProductTable()
{
if (!$this->productTable) {
$sm = $this->getServiceLocator();
$this->productTable = $sm->get('Administrador\Model\ProductTable');
}
return $this->productTable;
}
public function getBrandTable()
{
if (!$this->brandTable) {
$sm = $this->getServiceLocator();
$this->brandTable = $sm->get('Administrador\Model\BrandTable');
}
return $this->brandTable;
}
}
My case was I passed wrong input filter. isValid returns false, but $form->getMessages() is empty. Form OrderForm had the following:
$form->setInputFilter(new \Application\Form\UserInputFilter($er));
When I changed UserInputFilter to OrderInputFilter it works.
Well, I got the answer :D
This is how the addAction should be:
public function addAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$form->get('submit')->setValue('Add');
$product = new Product();
$product->brand = new Brand();
$form->bind($product); // I need to bind the product to the form to pass the isValid() validation
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$product = $form->getData();
$this->getProductTable()->saveProduct($product);
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return new ViewModel(array(
'form' => $form,
));
}
Apparently i needed to bind and empty product object to the form to be able to pass the isValid() validation. After that i retrieve a product object from the $form->getData().
You can also do: $form->setBindOnValidate(false);