Data from input form to controller - forms

To generate form I use
{{ form_rest(form) }}
It generates me a html:
<label class="required" for="findclient_client_number">Client number</label>
<input id="findclient_client_number" type="text" required="required" name="findclient[client][number]">
At controller I am trying to access data by:
$form = $this->createForm(new FindClientType(), new FindClient());
$form->bind($this->getRequest());
$clientnumber = $form->get('number')->getData();
return $this->render(
'MyDefaultBundle:Default:client.html.twig', array('clientnumber' => $clientnumber)
);
And get error:
Child "[number]" does not exist.
How to get submitted data from that field ?
Thanks for any help...

You need to bind the request to the form first. There is a Form::bind() method that will do this for you.
$form = $this->createForm(new ClientType());
if ($request->isMethod('POST')) {
$form->bind($this->get('request'));
$form->getData(); // Will return bound data
}
You can also get data directly from the request in your controller.
$this->get('request')->request->get('name')
See http://symfony.com/doc/master/book/forms.html#using-a-form-without-a-class

In addition to Ryans answer you are using an object (FindClient). So simply bind your form, get data and handle with your FindClient object to get your number.
$form = $this->createForm(new FindClientType(), new FindClient());
if ($request->isMethod('POST')) {
$form->bind($this->getRequest());
$data = $form->getData(); // Will return bound data
$clientnumber = $data->getNumber() // assuming your getter for the number
}

Related

Symfony 2 This form should not contain extra fields

I created a form using formBuilder in Symfony. I add some basic styling to the form inputs using an external stylesheet and referencing the tag id. The form renders correctly and processes information correctly.
However, it outputs an unwanted unordered list with a list item containing the following text: This form should not contain extra fields.
I am having a really hard time getting rid of this notice. I was wondering if someone can help me understand why it being rendered with my form and how to remove it?
Many thanks in advance!
Controller
$form = $this->createFormBuilder($search)
->add('searchinput', 'text', array('label'=>false, 'required' =>false))
->add('search', 'submit')
->getForm();
$form->handleRequest($request);
Twig Output (form is outputted and processed correctly
This form should not contain extra fields.
Rendered HTML
<form method="post" action="">
<div id="form">
<ul>
<li>This form should not contain extra fields.</li>
</ul>
<div>
<input type="text" id="form_searchinput" name="form[searchinput]" />
</div>
<div>
<button type="submit" id="form_search" name="form[search]">Search</button>
</div>
<input type="hidden" id="form__token" name="form[_token]" value="bb342d7ef928e984713d8cf3eda9a63440f973f2" />
</div>
</form>
It seems to me that you have the problem because of the token field. If it is so, try to add options to createFormBuilder():
$this->createFormBuilder($search, array(
'csrf_protection' => true,
'csrf_field_name' => '_token',
))
->add('searchinput', 'text', array('label'=>false, 'required' =>false))
->add('search', 'submit')
->getForm();
To find out the extra field use this code in controller, where you get the request:
$data = $request->request->all();
print("REQUEST DATA<br/>");
foreach ($data as $k => $d) {
print("$k: <pre>"); print_r($d); print("</pre>");
}
$children = $form->all();
print("<br/>FORM CHILDREN<br/>");
foreach ($children as $ch) {
print($ch->getName() . "<br/>");
}
$data = array_diff_key($data, $children);
//$data contains now extra fields
print("<br/>DIFF DATA<br/>");
foreach ($data as $k => $d) {
print("$k: <pre>"); print_r($d); print("</pre>");
}
$form->bind($data);
This message is also possible if you added/changed fields in your createFormBuilder() and press refresh in your browser...
In this case it's ok after sending the form again ;-)
I got the same message while having multiple forms on the same page. Turns out, symfony defaults to the name 'form' for all of them. Instead of using createFormBuilder, you can change the name of the form to avoid conflicts using
public FormBuilderInterface createNamedBuilder(string $name, string|FormTypeInterface $type = 'form', mixed $data = null, array $options = array(), FormBuilderInterface $parent = null)
See https://stackoverflow.com/a/13366086/1025437 for an example.
I ran into this error when creating a multi-step form.
When the step 1 form is submitted, $request->request contains acme_mybundle_myform array. This created a validation error and stopped the back, forward and form fields from populating correctly. Not to mention "this-form-should-not-contain-extra-fields"
I discovered this thanks to the code by nni6.
The solution in my case was inside the controller:
if ($form->isValid())
{
if($form->has('nextStep') && $form->get('nextStep')->isClicked())
{
$session->getFlashBag()->set('notice', 'Next clicked');
$registerType->incrementStep();
$request->request->remove('acme_mybundle_myform');
return $this->forward("AcmeMyBundle:Default:register", array($request));
}
....
}
I had the same error.
It was because I had a form which, by mistake, had a NULL name.
In the HTML, the name attribute would look like this:
<form name href="..." action"..."></form>
As simple as that.
Might not be the case for everyone, but worth to check.

CodeIgniter form_open() action not working correctly

I have have a view in which there's a form that manages products (either add new product or -if an id passed- editing an existing one). If an id is passed then the form action should be eg 'admin/product/manage/5', if no id passed then it should be like this 'admin/product/manage'.
<?php echo form_open('admin/product/manage/{optional product id}', array('class' => 'ajax-form')); ?>
I have also created and this route:
$route['admin/product/manage'] = "admin/product/manage";
$route['admin/product/manage/(:num)'] = "admin/product/manage/$1";
How can I make my form action work correctly? is it possible to put inside the action the route somehow??
This is my Controller:
public function manage($id = NULL){
//fetch a single product to edit or create a new one
if (isset($id) === true) {
$data['prod'] = $this->product_model->get($id);
$data['vers'] = $this->product_version_model->get_by('product_id',$id);
} else {
$data['prod'] = $this->product_model->make_new();// this returns $product->product_name = ''; in order to be empty the input field and not throughing errors
}
$this->product_model->save_product();
$this->product_version_model->save_version();
// load the view
$this->layout->view('admin/products/manage', $data);
}
This is my view:
<?php echo form_open('admin/product/manage', array('class' => 'ajax-form')); ?>
<p>
<label for="product_name">Product *</label>
<input type="text" name="product_name" value="<?php echo set_value('product_name', $prod->product_name); ?>" />
<?php echo form_error('product_name'); ?>
</p>
<?php echo form_close() . PHP_EOL; ?>
You need to declare both possible routes in order of importance, so:
$route['admin/product'] = "admin/product/manage";
$route['admin/product/(:num)'] = "admin/product/manage/$1";
From the Codeigniter Docs:
Routes will run in the order they are defined. Higher routes will always take precedence over lower ones.
Edit:
According to the changes you have made to your question I can say the following:
First of all isset() returns boolean only, so you don't need the type check "=== true". isset($id) is sufficient.
In order to have your form action set to the id you need to include it either in a hidden field or in the action itself.
So for example:
$action_id = (isset($id) ? '/'.$id : ''); // Using ternary operators here
echo form_open('admin/product/manage'.$action_id, array('class' => 'ajax-form'));
and add the id to the view data in your controller:
$data['id'] = $id;
As a side note: In order to comply with SoC (Separation of Concerns) you'd prepare all data in your controller (with e.g. models all having their own task) and pass the processed data to the view instead of partially generating data in the view itself.

Joomla 2.5 - component development - using form

I am trying to add some form to my component, but I am not shure what naming conventions must be applied to work it correctly.
Currently I have a working form - it displays fields stored in XML file and loads data from database to it. However, when i try to submit this form (edit or add new records), it doesn't work. After pressing submit (save() method) it just redirects me and displays that record was edited successfuly but it wasn't. When I try to edit existing record, after pressing submit nothing happens and when I try to add new record, it just adds empty/blank record.
So I was doing a little debug and discovered, that problem is in the JController::checkEditId() method. It always returns false which means that JControllerForm::save() returns false as well and that's why it doesn't save it correctly. HTML code of form is correct and I can access the data by using global array $_POST.
I suspect that this problem is because of naming conventions in methods loadFormData, getForm of JModelAdmin class. I am not sure how to name that form.
So here is my code related to this problem:
Subcontroller for displaying the form - controllers/slideshowform.php
class SlideshowModelSlideshowForm extends JModelAdmin{
public function getForm($data = array(), $loadData = true){
return $this->loadForm('com_slideshow.slideshowform', 'editform', array('load_data' => $loadData, 'control' => 'jform'));
}
protected function loadFormData(){
$data = JFactory::getApplication()->getUserState('com_slideshow.edit.slideshowform.data', array());
if (empty($data))
{
$data = $this->getItem();
}
return $data;
}
public function getTable($table = "biometricslideshow"){
return parent::getTable($table);
}
}
views/slideshowform/view.html.php
class SlideshowViewSlideshowForm extends JView{
public function display($tmpl = null){
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
$this->form = $this->get('form');
$this->item = $this->get('item');
JToolBarHelper::save('slideshowform.save');
parent::display();
}
}
views/slideshowform/tmpl/default.php
<?php
defined('_JEXEC') or die('Restricted access');
JHtml::_('behavior.tooltip');
?>
<form method="post" action="<?php echo JRoute::_("index.php?option=com_slideshow&id=".(int) $this->item->id)?>" name="adminForm" id="slideshow-form">
<fieldset class="adminform">
<legend>Edit slide</legend>
<table>
<input type="hidden" name="task" value="">
<?php echo JHtml::_('form.token'); ?>
<?php
foreach($this->form->getFieldset() as $field){
?>
<tr><td><?php echo $field->label ?></td><td><?php echo $field->input ?></td></tr>
<?php
}
?>
</table>
</fieldset>
</form>
Can someone take o look, please?
you have to add controller SlideshowControllerSlideshowForm and code save method. In there you have to validate the form data and call SlideshowModelSlideshowForm->save event, then redirect with success/failure message.

How can I show a form with the old values so that you can edit?

in controller I find the id
$oggetto = $this->getDoctrine()
->getRepository('AcmeTryBundle:Try')
->find($id);
after I passed this $values into form(just?)
$form = $this->createForm(new TryType(), $oggetto);
and in FormType? what I put?
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name','text') ?
Your approach is good.
1) Get your $oggetto object in DB
2) Pass it to your FormType $form = $this->createForm(new TryType(), $oggetto);
3) Add the fields you want in your form type
4) Send your form to your view 'form' => $form->createView()
5) In your view, call your form
<form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" />
</form>
Your fields (you defined in 3) ) will be automaticaly populated by your object data. You can then change them and edit them.
See the doc for more info: http://symfony.com/doc/current/book/forms.html
Your Form seems fine
class TryFormType extends AbstractType {
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name','text') ;
}
public function getName() {
return 'tryform';
}
}
The function getName gives the form a name, which in this case is tryform.
In the controller you can add a return statement like this.
return $this->render('AcmeTryBundle:Default:TryForm.html.twig', array(
'TryForm' => $form->createView()
));
And in twig file access it as follows.
{{ form_widget(TryForm.name) }}
The value will automatically be passed there. You can then edit it
For example in Symfony 4.2.3, you filled and submitted a form and some form values are invalid.
<input type="text" name="name" value="{{ form.vars.value.name }}">
In this way, you will be set old form input as a default value if the value is valid.

calling echo $this->action('panLogin','user') and $this->action('panRegister','user') on same script

I have a problem, i'm trying to render 2 forms (login and register) on one layout scrpt (header.phtml), every time i submit on one of the forms both actions for the controller are getting fired and i'm unsure how to fix it.
The forms are getting rendered fine within the layout, however when you click 'Login' or 'Register' on the forms the code fires in both the 'login' and 'register actions.
the header layout script snippet:-
<div class="left">
<h1>Already a member? <br>Then Login!</h1>
<?php
echo $this->action('panlogin', 'user');
?>
</div>
<div class="left right">
<h1>Not a member yet? <br>Get Registered!</h1>
<?php
echo $this->action('panregister', 'user');
?>
</div>
the action scripts (phtmls)
panregister.phtml
<div id="pan-register">
<?php
$this->registerForm->setAction($this->url);
echo $this->registerForm;
?>
</div>
panlogin.phtml
<div id="pan-login">
<?php
$this->loginForm->setAction($this->url);
?>
</div>
the user controller actions:-
class Ajfit_UserController extends Zend_Controller_Action
{
protected $_loginForm;
protected $_registerForm;
public function init()
{
$this->_loginForm = new Ajfit_Form_User_Login(array(
'action' => '/user/login',
'method' => 'post',
));
$this->_registerForm = new \Ajfit\Form\User\Registration(array(
'action' => '/user/register',
'method' => 'post'
));
}
//REGISTER ACTIONS
public function panregisterAction(){
$this->registerAction();
}
public function registerAction(){
$request = $this->_request;
if ($this->_request->isPost()){
$formData = $this->_request->getPost();
}
$this->view->registerForm = $this->_registerForm;
}
//LOGIN ACTIONS
public function panloginAction(){
$this->loginAction();
}
public function loginAction(){
$request = $this->_request;
if(!$auth->hasIdentity()){
if ($this->_request->isPost()){
$formData = $this->_request->getPost();
}
}
$this->view->loginForm = $this->_loginForm;
}
}
Please can someone with a little more knowlegde with the action('act','cont'); ?> code with in a layout script help me out with this problem.
Thanks
Andrew
While David is correct where best practices are concerned, I have on occasion just added another if() statement. Kinda like this:
if ($this->getRequest()->isPost()) {
if ($this->getRequest()->getPost('submit') == 'OK') {
just make sure your submit label is unique.
Eventually I'll get around to refactoring all those actions I built early in the learning process, for now though, they work.
Now to be nosy :)
I noticed: $formData = $this->_request->getPost(); while this works, if you put any filters on your forms retrieving the data in this manner bypasses your filters. To retrieve filtered values use $formData = $this->getValues();
from the ZF manual
The Request Object
GET and POST Data
Be cautious when accessing data from the request object as it is not filtered in any way. The router and
dispatcher validate and filter data for use with their tasks, but
leave the data untouched in the request object.
From Zend_Form Quickstart
Assuming your validations have passed, you can now fetch the filtered
values:
$values = $form->getValues();
Don't render the actions in your layout. Just render the forms:
<div class="left">
<h1>Already a member? <br>Then Login!</h1>
<?php
echo new \Ajfit\Form\User\Login(array(
'action' => '/user/login',
'method' => 'post'
));
?>
</div>
<div class="left right">
<h1>Not a member yet? <br>Get Registered!</h1>
<?php
echo new \Ajfit\Form\User\Registration(array(
'action' => '/user/register',
'method' => 'post'
));
?>
</div>
Then, whichever form gets used will post to its own action.