I would like to add a placeholder to my date input to show visitors using firefox which format the date must have.
Using Zend Framework 2, I want to be able to generate an input equivalent to :
<input type="date" placeholder="yyyy-mm-dd">
inside my Form class.
Here is the Form class I have right now :
<?php
namespace MyModule\Form;
use Zend\Form\Form;
class MyModuleForm extends Form {
public function __construct($name = null) {
parent::__construct('myModule');
$this->add(array(
'name' => 'TheDate',
'type' => 'date',
'attributes' => array(
'placeholder' => 'yyyy-mm-dd',
'class' => 'form-control',
)
));
}
}
?>
But Zend seems to skip the "placeholder" attribute and generates only :
<input class="form-control" type="date" value="" name="TheDate">
In the worst case scenario, I know I can also definse the "value" attribute instead (though I would like not to, just in case the user doesn't pay attention and doesn't change it), or add the placeholder manually using javascript. But is there a more elegant way to do what I want to achieve through the Form class of Zend ?
Edit : I found the answer I was looking for since the beginning thank to this post.
The solution is to go into the AbstractHelper.php present in the namespace Zend\Form\View\Helper.
There, there is a protected array of attributes that should be valid globally.
Adding
'placeholder' => true,
to $validGlobalAttributes fixed everything and was what I was a good enough answer to me.
An even better way would be to change this variable by inheritance instead of modifying it into the framework, but I don't have enough time for it right now.
You can't have placeholder on your date input due to the UI, which is triggered onfocus. Therefore you have to hack/fake it.
Change the 'type' => 'date', to 'type' => 'text',. You will see the placeholder now. This Javascript will help you triggering the date field on focus, and keep the placeholder.
$('.form-control').on('focus', function() {
$(this).attr('type', 'date') }
).on('blur', function() {
$(this).attr('type'), 'text') }
)
I guess, Zend FormDate does not support placeholder. You can check this on repo. For example,
Every form element has a Helper in (Zend\Form\View\Helper) and some of them has validTagAttributes as a class element. You can check FormEmail view helper class for this.
But, FormDate dont have a validTagAttributes. So, your invalid attributes ignored in prepareAttributes() method.
I think, if you want to palceholder on your date form element, you can create a custom FormDate element view helper and use it.
Related
I'm looking for a way to bind entity to a form, but I need a specific field of it to be mapped (displayed), but not modified by the user submitting the form.
What I have checked so far:
Using disabled attribute - it's not being submitted and entity's field is set to null
Using HTML readonly attribute - it can still be modified by manipulating HTML
Using read_only field option - same as above
My field is a checkbox, but I'd prefer a generic solution for that kind of fields, because I'll have more of them in the future.
I would also like to avoid additional query.
Any ideas?
The 1st & 3th solutions are not good.
I had the same issue a while ago. This is what I did to solve it:
I used the 2nd solution, and since you have the entity in the application, you can simply override any value the user had changed by manipulating the HTML (whitch is a risk that should be handled).
or, you could draw a HTML checkbox that is not mapped (with random id and name), and it will be not mapped to you entity.
I think I have found the right solution to that problem. It's not very flexible, but converting it to extension should make it fairly easy to deal with. The basic version I created just now can be found here. A little explanation:
Make the field with option mapped set to false
create event handler function (setUnmappedField)
attach EventListener to both PRE_SET_DATA and SUBMIT events.
PRE_SET_DATA makes sure the field has a correct value when initially rendering the form.
SUBMIT makes sure the field's value is reverted back to the initial value even if user changed it before submitting the form.
Disabled and readonly attributes are here for UI/UX, it will work without these attributes as well.
Feel free to use it to build a form extension if you need one. I will probably build an extension to make it more flexible later, once I need it.
#EDIT
I just realised this can be done easier - leaving the field mapped! updated gist here. No need for PRE_SET_DATA listener and mapped=false
I suggest you do a combination of 1 and 2 . See below for sample
->add('trainings', 'entity', array(
'label'=> 'Upcoming training(s)',
'choice_label' => 'CompleteTitle',
'multiple' => 'true',
'expanded' => 'true',
'by_reference'=>false,
'class' => 'TrainingBundle:Trainings' ,
'query_builder' => function (EntityRepository $er) use ($options) {
return $er->getTrainingByParentId($options['parent_id']);
},
)
)
->add('PastTrainings', 'entity', array(
'label'=> 'Past trainings',
'choice_label' => 'CompleteTitle',
'multiple' => 'true','expanded' => 'false',
'disabled' => 'true',
'class' => 'TrainingBundle:Training' ,'mapped'=>false,
'query_builder' => function (EntityRepository $er) use ($options) {
return $er->getTrainingByParentId($options['parent_id']);
},
)
I got stuck with this stupid error messages in Zend Framework 2. Spent two hours and nothing, I still got two different error messages with NotEmpty validator.
$nameNotEmptyMessage = 'Pole wymagane';
$inputFilter->add(array(
'name' => 'name',
'required' => true,
'filters' => array(
new Filter\StringTrim()
),
'validators' => array(
new Validator\NotEmpty(array(
'messages' => array(
Validator\NotEmpty::INVALID => $nameNotEmptyMessage,
Validator\NotEmpty::IS_EMPTY => $nameNotEmptyMessage
)
))
)
));
And what? It works pretty cool when I send form with "name" element inside it. When it's empty, I've got my message. But, when I send form without the "name" element inside it, the message is still "Value is required and can't be empty"! Why?
I need to have in both cases the same message because sometimes the form won't have "name" element.
Thank you guys very much!
Thanks for replying to the comment to clarify the problem. First I must say, I feel your pain on this one. After having not used ZF2 for over a year and spending some time figuring this out, it highlights yet another painful thing in ZF2.
That said, here is my simple solution. Not necessary correct, or the best way to go about it but it solves your problem with the least amount of code. In your controller where you instantiate and validate the form, add this code before you call new Form:
if (!isset($_POST['name'])) {
$this->getRequest()
->setPost(
new \Zend\Stdlib\Parameters(
array('name' => '')
)
);
}
This seemed the simplest route rather than setting up a default validation translator and adding a duplicate message. It is just checking to see if the name field was not present, and if so sets it with any empty value.
Now the reason why we have to do this:
This happens because of how \Zend\InputFilter\Input works. When the InputFilter runs, it sees the element is missing. It then checks the required property, sees it's true but the input has no value. No value being different than empty.
When the filter is required but has no input, \Zend\InputFilter\Input::prepareRequiredValidationFailureMessage is called. If you look at the source of that function, you'll see:
protected function prepareRequiredValidationFailureMessage()
{
$notEmpty = new NotEmpty();
$templates = $notEmpty->getOption('messageTemplates');
return [
NotEmpty::IS_EMPTY => $templates[NotEmpty::IS_EMPTY],
];
}
Notice how it creates a new NotEmpty validator and fetches its default message, thus bypassing the translation you set within the InputFilter.
The alternative:
One alternative, which may be more correct, but also requires more code and could arguably be more confusing looking back later would be to create a new class implementing \Zend\Validator\Translator\TranslatorInterface and set an array with the translation for that message and then calling \Zend\Validator\AbstractValidator::setDefaultTranslator passing that so the default translator will be used on that message.
This is just difficult because there is no short way of setting up that object because of how the classes are inherited and I wasn't able to find a quick solution to set up the default translator with just that message. Also, if you have another translator in place, it might interfere with it.
So it seems the simplest thing is to just check for the absence of that form field and populate it with any empty value if it's missing.
Hope that helps!
Other more simple way to fix this is to overwrite the Form setData($data) and to check if $data['name'] is set. Something like this:
public function setData($data)
{
if(!isset($data['name'])){
$data['name'] = '';
}
return parent::setData($data);
}
To generate a checkboxlist within Yii framework 2.0 I use the following line of code.
Html::checkboxList($model->choises, null, $arrayOption, ['separator' => '<br />',]);
I would like to have the last checkbox option with an input text field like others. Does Yii framework 2.0 provide any view helper to generate that?
Since I needed to approach this goal I have tried different solution and came up with an ideal solution which I would like to share here since no one yet could answer this question. The solution is for both radionList and checkboxList.
Just inject the $arrayOption with the following code snippet.
$arrayOption[0] = 'Others <input type="text" class="my-class-name" name="MyModel[my_other_option]">';
Add the following code into the rules function inside of the model class.
[
['my_other_option',], 'required' , 'when' => function($model) {
return $model->choises == '0';
},
],
By doing so, the validation will be failed when you selected the Other option but didn't fill in the input text field, named my_other_option.
I'm trying to use Symfony 2 forms to easily use Doctrine findBy API in my Controllers.
Actually, I would like to write this code in my Controller:
$repository->findBy(
$request->get('filters'),
$request->get('orderBy'),
$request->get('limit'),
$request->get('offset')
);
For that, my URL should look like this!
/session?filters[user]=4
/session?filters[user]=4&filters[year]=2014&orderBy=date&limit=10
To be able to give this functionality to my user, a solution I would love to use forms :
Solution n°1
$this->createFormBuilder()
->add('filters', 'array')
->add('user', 'integer')
->add('year', 'integer')
->add('orderBy')
->add('limit')
->add('offset')
;
But this solution or equivalent does not exist. (the type array does not exist)
Solution n°2
$this->createFormBuilder()
->add('filters[user]', 'integer')
->add('filters[year]', 'integer')
->add('orderBy')
->add('limit')
->add('offset')
;
The usage of '[' and ']' chars are not allowed and produce error.
An other solution is to use custom field name, actually the first solution (without the unexistant type "array") will produce this HTML:
<input type="text" id="form_filters" name="form[filters]" required="required" class="form-control">
Which will not suits the URL requirements. Do someone knows how to use custom name attribute?
It would also work If I had the opportunity to change the attribute name to form[filters][something] or even better filters[something] .
I'm not sure as I never did that, but, why don't you try with collection type ?
$this->createFormBuilder()
->add('filters', 'collection', array(
'choices' => array(
'user',
'year',
)
))
[...]
However I'm not sure you want pass parameters via get: if you have a form and url isn't callable from "outside" of your application, POST is far better
I am new to PHP and I have a lots of forms in PHP. The forms make use of the standard HTML Input fields and need to be validated on the serverside. How can I implement this, so that I do not have to write lots of boilerplate HTML over and over again, rather only write the minimal amount of code that generate the "full forms". What is the recommended approach to implement this? Thanks.
If you prefer to do it all yourself, you should at least do it PHP-Classes which will save you from re-writing (if done right ;-)). Handle attributes of the fields through an assoc array, e.g. like this:
<?php
$form = new Form("MyInput", array ("submit" => "myform.php") );
$form->AddField("input_text", array ("label" => "Your name") );
?>
To handle validation, you could use attributes such as
$form->AddField("input_text", array (
"label" => "Your name" ,
"validate" => "required"
) );
(Only examples, there's a lot of code releated to this which you'd need to write once...)
That should be useful for learning purposes...
Next, you could use JS to validate. Pls. note that JS does client-side validation only and you cannot rely on it being executed (user might have turned of JS in his browser), so you still MUST validate in PHP when receiving the data. (And you could use JS-Libraries for that - I've used Parsley and was quite happy with it...)
If you want to skip that experience, use Frameworks or Templating Engines.
I would suggest to create a form template. Consider using a method (of class View):
private static function capture($view_filename, array $view_data)
{
extract($view_data, EXTR_SKIP);
ob_start();
require $view_filename;
return ob_get_clean();
}
And call the static function capture (caution: consider using of __toString() to print objects) Pseudo-code:
echo View::capture('template', array('id' => '1', 'class' => 'userForm', 'inputs' => array(0 => array('label' => 'Name', 'type' => 'text'), 1 => array('label' => 'Password', 'type' => 'password')));