Prevent ZF2 formHelper escaping attributes - zend-framework2

Hi I have a form with a number field. I use regex to validate the field. For that reason I added the pattern attribute the element. However when I use formText it html escapes the regex pattern.
//inside the form _construct
$this->add(array(
'name' => 'number',
'type' => 'text',
'options' => array(
'label' => 'Number',
),
'attributes' => array(
'pattern' => '/^(\+)?((\d)+(-|\s)?)+$/',
'maxLength' => '20',
'id' => 'number',
),
));
And in the form
<?php echo $this->formText($form->get('number')); ?>
The result is then
<input type="text" name="number" pattern="/^(\+)?((\d)+(-|\s)?)+$/" id="number" value="" maxlength="20">
How can I add the number field to my form without escaping the regex pattern?

Form view helpers are supposed to work that way, providing some baseline security features and automating stuff. So if you don't won't that don't use them:
<input type="<?php echo $form->get('number')->getType(); ?>" pattern="type="<?php echo $form->get('number')->getAttribute('pattern'); ?>" value="<?php echo $form->get('number')->geValue(); ?>">
Not sure what you need displayed, but it should give you a general idea of "my" approach. You can also manually escape stuff like value:
$this->escape($form->get('number')->geValue())
If you find this tedious, you can always write a helper that does this. You can also make PR with an option to turn of the escaping for attributes, but having them on by default is a sensible.

Related

ZF2 convert empty posted fields to Null

I'm using fieldsets in order to fill forms in ZF2. If an empty field is postedm, the field is also empty in the db. How do I force a Null in the db for empty fields?
In ZF2 I think you need to use Zend\Filter\Null or Zend\Filter\ToNull depending on which version of ZF2 you are using, Zend\Filter\Null became deprecated in ZF2.4.
In your fieldset, assuming you are using the Zend\InputFilter\InputFilterProviderInterface use:
public function getInputFilterSpecification()
{
return array(
'your_field' => array(
'filters' => array(
array('name' => 'ToNull'),
),
),
);
}

where do addElement method defined zend 2?

$form = new Zend_Form();
$form->addElement('text', 'fname', array('belongsTo' => 'user'));
I need to know where is addElement method defined? I have searched \vendor\ZF2\library\Zend([\Form]) directory but could not find this method!. If there is no such method then please help me to understand how this above two line work and what are other array conf & parameter of this method.
Edit: thanks Crisp. Actually I am trying to make an input array in zf2 like
<input name="val[one]" type="text" />
<input name="val[two]" type="text" />
<input name="val[three]" type="text" />
Or at least... like this
<input name="val[0]" type="text" />
<input name="val[1]" type="text" />
<input name="val[2]" type="text" />
I have found a example with above code and its not working as it is zf1.
In ZF2, programmatic form creation has changed from ZF1. There is no more addElement function, instead you add an element using $form->add($element);
The basic steps to create a form in ZF2 are:
Create a form element
Create a form
Add element to the form
Create a form element:
use Zend\Form\Element;
use Zend\Form\Form;
$name = new Element('name');
$name->setLabel('Your name');
$name->setAttributes(array(
'type' => 'text'
));
$send = new Element('send');
$send->setValue('Submit');
$send->setAttributes(array(
'type' => 'submit'
));
Create a form:
$form = new Form('contact');
Add element to the form:
$form->add($name);
$form->add($send);
However in ZF2, another way would be to use a Factory to generate the form from an array configuration:
use Zend\Form\Factory;
$factory = new Factory();
$form = $factory->createForm(array(
'hydrator' => 'Zend\Stdlib\Hydrator\ArraySerializable',
'elements' => array(
array(
'spec' => array(
'name' => 'name',
'options' => array(
'label' => 'Your name',
),
'type' => 'Text',
)
),
array(
'spec' => array(
'name' => 'send',
'type' => 'Submit',
'attributes' => array(
'value' => 'Submit',
),
),
),
),
));
The form is then referenced from the view and is rendered using form view helpers.
References:
http://framework.zend.com/manual/2.3/en/modules/zend.form.quick-start.html
https://zf2.readthedocs.org/en/develop/modules/zend.form.advanced-use-of-forms.html
http://akrabat.com/category/zend-framework-2/

ZF2 Form\Element\MultiCheckbox: how to get each item on a new line?

I've been Googling this to no avail. I have a multi-checkbox form element in one of my forms. Here's the code I used to create it:
$this->add(array (
'name' => 'thingyId',
'type' => 'MultiCheckbox',
'options' => array (
'value_options' => $thingyArray,
)
));
In my view script, I have this:
<?= $this->formRow($form->get('thingyId')); ?>
The form element shows up fine, but all of the checkboxes are on a single line. How do I get it so that each checkbox is on a new line?
If you view this link, you can see that the fourth argument is partial. So, you can use many ways to accomplish the task.
Method 1:
echo $this->formRow($element, null, null, 'template-file');
Now, create a template file named as template-file.phtml to render the element however you like.
//template-file.phtml
<span><?php echo $label; ?></span><br/>
<?php foreach ($element->getValueOptions() as $key => $value): ?>
<input type="checkbox" name="<?php echo $element->getName() ?>[]" value="<?php echo $value; ?>">
<span><?php echo $key; ?></span><br/>
<?php endforeach; ?>
Method 2
Create your own view helper by extending the default helper.
namespace Application\View\Helper;
class MyFormRow extends \Zend\Form\View\Helper\FormRow
{
/**
* #var string
*/
protected $partial = 'template-file';
}
Now, inform our application about our new helper in your module,
namespace Application;
class Module
{
public function getViewHelperConfig()
{
return array(
'invokables' => array(
'myFormRow' => 'Application\View\Helper\MyFormRow'
)
);
}
}
Lastly use the helper:
echo $this->myFormRow($element);
I came across this question when I was having this issue myself. The code that was being used was the following:
<?php
$oMultiCheckboxField = $oForm->get('multicheckboxelement');
echo $this->formMultiCheckbox($oMultiCheckboxField);
?>
The only additional parameter you could pass to the formMultiCheckbox view helper was whether to append or prepend the label.
How I eventually chose to solve this is with the following code:
<?php
$oMultiCheckboxField = $oForm->get('multicheckboxelement');
$oMultiCheckboxViewHelper = new \Zend\Form\View\Helper\FormMultiCheckbox();
$oMultiCheckboxViewHelper->setSeparator('<hr>');
echo $oMultiCheckboxViewHelper->render($oMultiCheckboxField);
?>
From what I recall, ZF1 had the option to set the separator (I clearly remember this at least for radio buttons). Why there isn't a clearer way to do this in ZF2 is a bit puzzling. If there are better ways to do this, I would certainly like to know about it.

ZF2 - Retain query from form using url helper in pagination

I'm new to ZF2 and I'm willing to share how I do to retain parameter from form using url helper especially during pagination. I modify the answer from How can you add query parameters in the ZF2 url view helper
This is what I do:
AlbumController.php
// get all the query from url
$input = $form->getData();
$paginator = $this->getAlbumTable()->fetchAll();
$paginator->setCurrentPageNumber((int)$this->params()->fromQuery('page', 1));
$paginator->setItemCountPerPage(30);
// unset the 'page' query if necessary
unset($input['page']);
return array(
'form' => $form,
'paginator' => $paginator,
'routeParams' => array_filter($input) // filter empty value
);
index.phtml
echo $this->paginationControl(
$this->paginator,
'sliding',
array('partial/paginator.phtml', 'Album'),
array(
'route' => 'album',
'routeParams' => $routeParams
)
);
paginator.phtml
<a href="<?php echo $this->url(
$this->route, // your route name
array(), // any url options, e.g action
array('query' => $this->routeParams) // your query params
);
echo (empty($this->routeParams))? '?' : '&'; ?>
page=<?php echo $this->next; ?>">Next Page</a>
Please provide any better solution and correct me if I'm wrong.
Thank you
I don't have a much better solution than yours - I don't see a proper way to retain existing query params while adding some new ones. But the following is neater than manually appending & and = characters:
paginator.phtml
<a href="<?php echo $this->url(
$this->route, // your route name
array(), // any url options, e.g action
// Merge the array with your new value(s)
array('query' => array('page' => $this->next) + $this->routeParams)
); ?>">Next Page</a>
This will also ensure that if you already have a page param, it will be overwritten by the new one.
(Technically you could also use $_GET or $_POST directly and avoid passing it from the controller at all, but that doesn't seem very neat)

putting jquery buttons in clistview widget in yii

I am trying to put a button which will be displayed along with some data in the view file I specified in "itemView" field of the CListView widget, but instead of the styled button for every list item, I am just getting it or the first list item. My code in the _view file is:
<div id="listView">
<div class="thedata">
...some data
</div>
<div id="buttons">
<?php
$this->widget('zii.widgets.jui.CJuiButton', array(
'buttonType'=>'button',
'name'=>'btnJobs',
'caption'=>'Manage Jobs',
'options'=>array('icons'=>'js:{primary:"ui-icon-wrench"}'),
'onclick'=>'js:function(){alert("Manage Jobs clicked."); this.blur(); return false;}',
));
?>
</div>
</div>
and the code for CListView widget is just the bare minimum:
$this->widget('zii.widgets.CListView', array(
'dataProvider' => $dataProvider,
'itemView' => '_view'
));
any suggestions?
Try passing in a unique ID to the CJuiButton, like so:
<?php
$this->widget('zii.widgets.jui.CJuiButton', array(
'id'=>'button'.$data->id, // add a unique ID here (could use $index instead of $data->id)
'buttonType'=>'button',
'name'=>'btnJobs',
'caption'=>'Manage Jobs',
'options'=>array('icons'=>'js:{primary:"ui-icon-wrench"}'),
'onclick'=>'js:function(){alert("Manage Jobs clicked."); this.blur(); return false;}',
));
?>
The problem is that since all of your buttons have the same 'name' (and therefore 'id') jQuery is only binding to the first one. Making sure each button has a unique ID should fix this, so jQuery will bind correctly.

Resources