Pass the current querystring parameters through symfony forms - forms

Our application uses several webforms and some of them only should add or change several parameters in the querystring. As example there are a filter form and a form for the list order (just a dropdown).
Both are indipendant, but if I change one, I have to pass the current querystring parameters with the new request. How can I manage it?

This is just one of the possible solutions, it will depend on your implementation if it would help you.
<?php
$allowedQueryParams = array('param1', 'param2', 'param3');
// I'll fake a request here
$request = new Request(array('param2' => 'foo', 'param3' => 'bar', 'param4' => 'dummy'));
$formFactory = Forms::createFormFactoryBuilder()->getFormFactory();
$formBuilder = $formFactory->createBuilder();
$formBuilder->add('param1', 'text');
$data = array();
foreach ($allowedQueryParams as $param) {
if ($request->query->has($param)) {
// Add the query param as hidden field to you form
$formBuilder->add($param, 'hidden');
$data[$param] = $request->query->get($param);
}
}
$formBuilder->setData($data);
$form = $formBuilder->getForm();
So basically you add hidden fields with the current query parameters.
Edit:
But if you would have many forms, you might want to do this with an EventSubscriber

An alternative approach would be to combine the two forms into one master form.
From your controller:
$formData = array(
'filterParams' => array(), // Default filter parameters
'listOrderParams' => array(), // Default list order parameters
);
$form = $this->createFormBuilder($task)
->add('filterParams', new FilterFormType())
->add('listOrderParams', new ListOrderFormType())
->add('update', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$formData = $form->getData();

Related

understanding Zend\Form\Element\Date

I have two issues while using the Zend-Form date element.
First: field binding
The edit action within my controller doesn't fillin an existing date. For example birthday. The field is just empty. (with an element type text, there is no problem).
Here how I instanciated the field:
$this->add([
'name' => 'geburtstag',
'type' => 'date',
'options' => [
'label' => 'Geburtstag:',
'format' => 'dd/mm/yyyy',
],
]);
And here my controller action.
public function addAction()
{
$form = new AnsprechpartnerForm(NULL, $this->db);
$form->get('submit')->setValue('save');
$request = $this->getRequest();
if (! $request->isPost()) {
return ['form' => $form];
}
$ansprechpartner = new Ansprechpartner();
$form->setInputFilter($ansprechpartner->getInputFilter());
$form->setData($request->getPost());
if (! $form->isValid()) {
return ['form' => $form];
}
$ansprechpartner->exchangeArray($form->getData());
$this->ansprechpartnerTable->saveAnsprechpartner($ansprechpartner);
return $this->redirect()->toRoute('ansprechpartner');
}
No inputFilter at the moment, I tried with and without.
Second: validation
I have trouble filling in dates. While I don't use any filters for this field, I would expect, I could fill any date in.
Interesting I get the message double.
I solved it.
The date element expects the format y-m-d. Now I gave it directly to the field after binding the form. The format in the field is now also korrekt.
$form->bind($notizen);
$form->get('submit')->setAttribute('value', 'edit');
$filter = new \Zend\Filter\DateTimeFormatter();
$filter->setFormat('Y-m-d');
$dat = $filter->filter($notizen->datum);
$form->get('datum')->setValue($dat);
Could be more convenient I guess.

Symfony2 autocomplete form bundle

I use this bundle: GenemuFormBundle
I install it due to all information on this site.
But it still dont work.
Here is my type form:
$builder
->add('PermitsCompany', 'genemu_jqueryautocompleter_entity', array(
'route_name' => 'ajax_company',
'class' => 'MainCoreBundle:Company',
'property'=>'name'
))
;
Here is my routing:
ajax_company:
defaults: { _controller: MainAdminBundle:Permits:ajaxCompany}
pattern: /ajax_company/
type: annotation
And here is my controller:
/**
* #Route("/ajax_company", name="ajax_company")
*/
public function ajaxCompanyAction(Request $request)
{
$permits = $this->getDoctrine()->getRepository('MainCoreBundle:Company')->findAll();
$json = array();
foreach ($permits as $permit) {
$json[] = array(
'label' => $permit->getName(),
'value' => $permit->getId()
);
}
$response = new Response(json_encode($json));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
I have no idea what I am doing wrong. I have no error. But autocomplete did not work.
When i go to route /ajax_company/ i can see values from data base like here:
[{"property":"Company 1","value":1},{"property":"Company 2","value":2},{"Company":"Company 3","value":3},{"property":"Company 4","value":4}]
Did I add forget something in twig? I have only form_widget
Try including form_javascript or form_stylesheet, in your twig template.
From https://github.com/genemu/GenemuFormBundle#template:
Template
You use GenemuFormBundle and you seen that it does not work! Maybe you
have forgotten form_javascript or form_stylesheet.
The principle is to separate the javascript, stylesheet and html. This
allows better integration of web pages.

How to set as a default value in a Symfony 2 form field the authentified username from the FOSUserBundle

i find this snippet useful indeed to put a default value in my form while creating it
$builder
->add('myfield', 'text', array(
'label' => 'Field',
'data' => 'Default value'))
;
what if i want to replace 'default value' with an authentified person from the FOSUser bundle? ( that return true to is_granted("IS_AUTHENTICATED_REMEMBERED"))
i can retrieve that name on a twig file with
{{ app.user.username }}
i have also done it in a controller method with
$username=$this->container->get('security.context')->getToken()->getUser()->getUsername()
but i can't manage to make this working in my form!
i am not sure i understand that container thing well ...neither how to transfer variables betweenn classes and controller...
something around this maybe??
->add('myfield', 'text', array(
'label' => 'Field',
'data' => FOS\UserBundle\Model::$this->getUsername()))
You can passe variable from your controller to your form :
in your controller :
$username=$this->container->get('security.context')->getToken()->getUser()->getUsername()
$form = $this->createForm(new MyFormType($username), $entity);
in your form :
protected $username;
public function __construct (array $username = null)
{
$this->username = $username ;
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('myfield', 'text', array(
'label' => 'Field',
'data' => $this->username))
}
Another way to set default values into a form is to set them on the underlying data object for the form, as in this example from the Symfony documentation on building a form:
public function newAction()
{
// create a task and give it some dummy data for this example
$task = new Task();
$task->setTask('Write a blog post');
$task->setDueDate(new \DateTime('tomorrow'));
$form = $this->createFormBuilder($task)
->add('task', 'text')
->add('dueDate', 'date')
->getForm();
return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
'form' => $form->createView(),
));
}
In this example, the form's underlying data object is a Task and the values set on the task are the default values to be displayed in the form. The task object is not persistent. This approach works just as well with a form class and assuming the underlying object for your form is a User would look something like this:
$username = $this->container->get('security.context')->getToken()->getUser()->getUsername();
$user = new User();
$user->setUsername($username);
// could set any other default values on user here
$form = $this->createForm(new MyFormClass(), $user);
The disadvantage of this approach is if the form is used in many places requiring the same defaults the code would be repeated. This is not a situation I've come across so far - my User forms are re-used for create/edit but edit doesn't require the defaults.

How to add validators on the fly in Symfony2?

I've a password form field (not mapped to User password) to be used in a change password form, along with two other (mapped) fields, first and last.
I've to add validators on the fly: if value for password is blank then no validation should occur. Otherwise a new MinLength and MaxLength validators should be added.
Here is what i've done so far: create the repeated password field, add a CallbackValidator and return if $form->getData() is null.
Then, how can i add validators for minimum and maximum length to $field?
$builder = $this->createFormBuilder($user);
$field = $builder->create('new_password', 'repeated', array(
'type' => 'password',
'first_name' => 'Password',
'second_name' => 'Confirm password',
'required' => false,
'property_path' => false // Not mapped to the entity password
));
// Add a callback validator the the password field
$field->addValidator(new Form\CallbackValidator(function($form) {
$data = $form->getData();
if(is_null($data)) return; // Field is blank
// Here password is provided and match confirm, check min = 3 max = 10
}));
// Add fields to the form
$form = $builder
->add('first', 'text', array('required' => false)) // Mapped
->add('last', 'text', array('required' => false)) // Mapped
->add($field) // Not mapped
->getForm();
Oh well, found a solution myself after a few experiments.
I'm going to leave this question unanswered for a couple of days as one can post a better solution, that would be really really welcome :)
In particular, i found the new FormError part redundat, don't know if there is a better way to add the error to the form. And honestly, don't know why new Form\CallbackValidator works while new CallbackValidator won't.
So, don't forget to add use statements like these:
use Symfony\Component\Form as Form, // Mendatory
Symfony\Component\Form\FormInterface,
Symfony\Component\Validator\Constraints\MinLength,
Symfony\Component\Validator\Constraints\MinLengthValidator;
And the callback is:
$validation = function(FormInterface $form) {
// If $data is null then the field was blank, do nothing more
if(is_null($data = $form->getData())) return;
// Create a new MinLengthValidator
$validator = new MinLengthValidator();
// If $data is invalid against the MinLength constraint add the error
if(!$validator->isValid($data, new MinLength(array('limit' => 3)))) :
$template = $validator->getMessageTemplate(); // Default error msg
$parameters = $validator->getMessageParameters(); // Default parameters
// Add the error to the form (to the field "password")
$form->addError(new Form\FormError($template, $parameters));
endif;
};
Well, and this is the part i can't understand (why i'm forced to prefix with Form), but it's fine:
$builder->get('password')->addValidator(new Form\CallbackValidator($validation));
addValidator was deprecated and completly removed since Symfony 2.3.
You can do that by listening to the POST_SUBMIT event
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
if ("Your logic here") {
$form->get('new_password')->addError(new FormError());
}
});

Validate a set of fields / group of fields in Zend Form

Is there any good solution for the following requirements:
A form with one field for zip code and default validators like number, length, etc.
After submission, the form is checked against a database.
If the zip code is not unique we have to ask for an city.
Examples:
Case 1: Submited zip code is unique in database. Everything is okay. Process form
Case 2: Submited zip code is not unique. Add a second field for city to the form. Go back to form.
We want to handle this in an generic way (not inside an controller). We need this logic for
a lot of forms. First thought was to add it to isValid() to every form or write a
validator with logic to add fields to the form. Subforms are not possible for us, because we need this for different fields (e.g. name and street).
Currently I'm using isValid method inside my forms for an User Form to verify the password and confirm password field. Also, when the form is displayed in a New Action, there are no modifications, but when displayed in an Edit Action, a new field is added to the form.
I think that is a good option work on the isValid method and add the field when the validation return false, and if you want something more maintainable, you should write your own validatator for that purpose.
Take a look at my code:
class Admin_Form_User extends Zf_Form
{
public function __construct($options = NULL)
{
parent::__construct($options);
$this->setName('user');
$id = new Zend_Form_Element_Hidden('id');
$user = new Zend_Form_Element_Text('user');
$user->setLabel('User:')
->addFilter('stripTags')
->addFilter('StringTrim')
->setAllowEmpty(false)
->setRequired(true);
$passwordChange = new Zend_Form_Element_Radio('changePassword');
$passwordChange->setLabel('Would you like to change the password?')
->addMultiOptions(array(1 => 'Sim', 2 => 'Não'))
->setValue(2)
->setSeparator('');
$password = new Zend_Form_Element_Password('password');
$password->setLabel('Password:')
->addFilter('stripTags')
->addFilter('StringTrim')
->setRequired(true);
$confirm_password = new Zend_Form_Element_Password('confirm_password');
$confirm_password->setLabel('Confirm the password:')
->addFilter('stripTags')
->addFilter('StringTrim')
->addValidator('Identical')
->setRequired(true);
$submit = new Zend_Form_Element_Submit('submit');
$submit->setLabel('Save');
$this->addElements(array($id,$name,$lastname,$group,$user,$passwordChange,$password,$confirm_password,$submit));
$this->addDisplayGroup(array('password','confirm_password'),'passwordGroup');
$this->submit->setOrder(8);
$this->setDisplayGroupDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'div','id' => 'div-password'))
)
);
$passwordChange->clearDecorators();
}
public function addPasswordOption()
{
$this->changePassword->loadDefaultDecorators();
$this->getDisplayGroup('passwordGroup')
->addDecorators(array(
array('HtmlTag', array('tag' => 'div','id' => 'div-password'))
)
);
$this->password->setRequired(false);
$this->confirm_password->setRequired(false);
}
public function setPasswordRequired($flag = true)
{
$this->password->setRequired($flag);
$this->confirm_password->setRequired($flag);
}
public function isValid($data)
{
$confirm = $this->getElement('confirm_password');
$confirm->getValidator('Identical')->setToken($data['password']);
return parent::isValid($data);
}
}
So, in my controller:
public function newAction()
{
$this->view->title = "New user";
$this->view->headTitle($this->view->title, 'PREPEND');
$form = $this->getForm();
if($this->getRequest()->isPost())
{
$formData = $this->_request->getPost();
if($form->isValid($formData))
{
$Model = $this->getModel();
$id = $Model->insert($formData);
$this->_helper->flashMessenger('The user data has beed updated.');
$this->_helper->redirector('list');
}
}
$this->view->form = $form;
}
public function editAction()
{
$this->view->title = "Edit user";
$this->view->headTitle($this->view->title, 'PREPEND');
$id = $this->getRequest()->getParam('id');
$form = $this->getForm();
// Add yes or no password change option
$form->addPasswordOption();
$Model = $this->getModel();
if($this->getRequest()->isPost())
{
$formData = $this->getRequest()->getPost();
// Change password?
if($formData['changePassword'] == 2) $form->setPasswordRequired(false);
if($form->isValid($formData))
{
$Model->update($formData);
$this->_helper->flashMessenger('The user data has beed updated.');
$this->_helper->redirector('list');
}
}
$data = $Model->getById($id)->toArray();
$form->populate($data);
$this->view->form = $form;
}
You will probably need a Javascript form validator for that. In the submit function perform an AJAX call to check if the zipcode is unique. If not, show an extra city field.
But you still have to perform the validation server side: never trust user input, even if it's validated on the client side.