symfony2 neither property nor method exists in class - forms

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);

Related

Render radio button form from a collectionType [Symfony]

I'm trying to create a quiz for my application with Symfony.
At this point I have 3 class, Qcm, QcmQuestion and QcmAnswer.
I have multiple questions which contains multiple answers, and I want to display answers as radio button.
I only achieve to display them as input. How can I display them as radio button ?
BaseController.php
$em = $this->getDoctrine()->getManager()>getRepository('QcmBundle:QcmQuestion');
$qcmQuestions = $em->findBy(array('qcm' => $id));
$formBuilderQuestionnaire = $this->createFormBuilder();
$i = 0;
foreach ($qcmQuestions as $qcmQuestion) {
$formBuilder = $this->get('form.factory')->createNamedBuilder($i, FormType::class, $qcmQuestion);
$formBuilder
->add('question')
->add('qcmAnswers', CollectionType::class, [
'entry_type' => QcmAnswerType::class
])
;
$formBuilderQuestionnaire->add($formBuilder);
$i++;
}
$form = $formBuilderQuestionnaire->getForm();
$form->add('save', SubmitType::class, array('label' => 'Envoyer',
"attr" => array("class" => "btn btn-primary")));
return $this->render('QcmBundle:qcm:qcmQuestions.html.twig', ["qcmQuestions" => $qcmQuestions, "form" => $form->createView()]);
QcmAnswerType
class QcmAnswerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('response');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'QcmBundle\Entity\QcmAnswer'
));
}
public function getBlockPrefix()
{
return 'qcmbundle_qcmanswer';
}
You do not want CollectionType + QcmAnswerType but you want just EntityType with options multiple: false and expanded: true.
So instead of
->add('qcmAnswers', CollectionType::class, [
'entry_type' => QcmAnswerType::class
])
try with something like:
->add('qcmAnswers', EntityType::class, [
'multiple' => false,
'expanded' => true,
])
More info about EnttiyType can be found in Symfony Docs.
I managed to solved my problems, I used EntityType with a query inside it.
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?"
I had this error because I needed to pass to createNamedBuilder the entire array of questions like this :
$formBuilder = $this->get('form.factory')->createNamedBuilder($i, FormType::class, $qcmQuestions);
The final result :
$em = $this->getDoctrine()->getManager()->getRepository('QcmBundle:QcmQuestion');
$qcmQuestions = $em->findBy(array('qcm' => $id));
$formBuilderQuestionnaire = $this->createFormBuilder();
$i = 0;
foreach ($qcmQuestions as $qcmQuestion) {
/* #var $qcmQuestion QcmQuestion */
$formBuilder = $this->get('form.factory')->createNamedBuilder($i, FormType::class, $qcmQuestions);
$formBuilder
->add('qcmAnswers', EntityType::class, [
'class' => 'QcmBundle\Entity\QcmAnswer',
'expanded' => true,
'label' => $qcmQuestion->getQuestion(),
'query_builder' => function (EntityRepository $er) use ($qcmQuestion) {
return $er->createQueryBuilder('qcmAnswer')
->join('qcmAnswer.qcmQuestion', 'qcmQuestion')
->where('qcmAnswer.qcmQuestion = :qcmQuestionId')
->setParameter('qcmQuestionId', $qcmQuestion->getId());
},
]);
$formBuilderQuestionnaire->add($formBuilder);
$i++;
}
$form = $formBuilderQuestionnaire->getForm();

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 - User specific form based on role access

I have a form that has a category field drop down that has a (OneToMany/ManyToOne) to a post entity.
Situation: Right now the client has to select category in the drop down and they can make the mistake of selecting the wrong category and this will go to another blog (if they select the wrong one) and they will not have access to change this back to the proper category.
To alleviate this potential problem I'd like to do one of the two as a solution:
1) Set the category automatically based on the category they have access to
2) Or restrict the user to only select the category they have access to (e.g., if the user has a specific role they only get this category for the drop down)
The user has a ROLE_USER restriction that allows them to only CRUD what they have access to.
e.g.,
ROLEUSER1 only has access to /category1 (and can use CRUD on this)
ROLEUSER2 only has access to /category2 (and can use CRUD on this)
ROLEUSER3 only has access to /category3 (and can use CRUD on this)
How can I set this up so the client cannot make the mistake of selecting the wrong category?
Form
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('body')
->add('author')
->add('category')
->add('file', 'file', array(
'label' => 'Image',
'required' => false
))
->add('created');
}
Controller
public function job1CreateAction(Request $request)
{
$entity = new Post();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('job1_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
private function createCreateForm(Post $entity)
{
$form = $this->createForm(new PostType(), $entity, array(
'action' => $this->generateUrl('job1_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
how about this? :
remove 'category' field from form builder and manually set it in controller action:
if ($this->get('security.context')->isGranted('ROLEUSER1') {
$entity->setCategory(CATEGORY1);
}
EDIT:
controller action:
public function job1CreateAction(Request $request)
{
$entity = new Post();
if ($this->get('security.context')->isGranted('ROLEUSER1') {
$category1 = $this->getDoctrine()->getManager()->getRepository('MYBUNDLE:POST')->find(1); // we are getting category object. this is just an example cade, may be this will be different in your case
$entity->setCategory($category1);
}
$form = $this->createCreateForm($entity);
....
}
and form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('body')
->add('author')
//->add('category')
->add('file', 'file', array(
'label' => 'Image',
'required' => false
))
->add('created');
}

How to render a choice field in a template

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.

$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);