I'm searching for informations if there is some kind of flag/option that force symfony2 validation stop on first error in validation chain. For example I have three validators on my email field:
email:
- NotBlank: { groups: [ send_activation_email ] }
- Length: { min: 6, max: 80, charset: UTF-8, groups: [ send_activation_email ] }
- Email: { groups: [ send_activation_email ] }
I want to stop validation after first error. How can I achieve that? I read similar questions:
Symfony2 : Validation Halt on First Error
How to stop validation on constraint failure in Symfony2
Symfony-2 gives more than one validation error message
Last one is quite good but is there any way to do this without using validation groups every time, when there are more than one validator? I read somewhere that in Symfony 2.2 there will be a flag or option for this, but I have 2.2.1 version and can't find such option.
You can use the Chain validator for that purpose: https://gist.github.com/rybakit/4705749
Here's an example in plain PHP:
<?php
use Symfony\Component\Validator\Constraints\Date;
use Symfony\Component\Validator\Constraints\Type;
use Acme\Validator\Constraints\Chain;
$constraint = new Chain([new Type('string'), new Date()]);
In XML:
<!-- src/Acme/DemoBundle/Resources/config/validation.xml -->
<class name="Acme\DemoBundle\Entity\AcmeEntity">
<property name="date">
<constraint name="Acme\Validator\Constraints\Chain">
<option name="constraints">
<constraint name="Type">
<option name="type">string</option>
</constraint>
<constraint name="Date" />
</option>
</constraint>
</property>
</class>
But be aware that if you want to have nested Chain constraints, like:
<?php
$constraint = new Chain([
new Callback(...),
new Chain([new Type('string'), new Date()]),
]);
you have to override the validator.validator_factory symfony service to fix the issue with handling nested constraints in the current implementation: https://github.com/symfony/Validator/blob/fc0650c1825c842f9dcc4819a2eaff9922a07e7c/ConstraintValidatorFactory.php#L48.
See the NoCacheConstraintValidatorFactory.php file from the gist to get an idea how it could be solved.
As of Symfony 2.3 you can do this using Group Sequences (though form support for group sequences might be spotty).
Related
Say I have a validation rules for some Model, for example validation for a person model will be:
'first_name' => ['required', 'string'],
'last_name' => ['required', 'string'],
'birthday' => ['before:today', 'date'],
'salary' => ['min:0', 'max:2000', numeric],
....
So if I wrote that rules, it feels wrong to write the same rules manually but for the HTML form fields like:
<input type="text" name="first_name" required />
<input type="text" name="last_name" required />
<input type="date" name="birthday" max="2016-06-09"/>
<input type="number" name="salary" min="0" max="2000"/>
So if the product owner ask me for change the rules like changing the mandatory fields, or even change the maximum salary from 2000 to 5000, I have to change it manually in the validation rules and the form itself.
So it makes me wonder, is there any automatic way to convert Laravel validation rules to the HTML form fields?
You have to parse your rules, then loop on the parsed datas for building a form. And then, I suggest you to use partial views for doing the trick.
I already did this for building automatic forms and documentations. So i wrote a Laravel package here : https://github.com/Ifnot/ValidationParser.
In the example of my package you just have to create two files :
A form blade view (contains the code for parsing the validation)
A field blade view (used for display a form item)
To have the validation rules be in one place, set the rules to variables. Then, pass the variables into the laravel validation page and in your blade template (html).
So, where you are setting the variable:
$MaxSalary = 2000;
Next, pass in your variable to the Laravel form validation rules:
'salary' => ['min:0', "max:$MaxSalary", numeric],
Then, pass it into your blade template form:
return view('form', ['MaxSalary' => $MaxSalary]);
Then, in your blade template, use the variable:
<input type="number" name="salary" min="0" max="{{ MaxSalary }}"/>
I had problems finding some one else thinking about this same idea. I must have not been using the right terms for the search. I implemented this same concept today 2023 in the following project: https://github.com/arielenter/ValidationRulesToInputAttributes
In it, I'm using laravel's Illuminate\Validation\ValidationRuleParser to explode and parse the rules, and later I used a 'translator' that convert applicable rules to input attributes.
My concern is why it seems nobody has made a laravel package that can do this on 2023. I'm not sure if I'm up to the task, but if nobody has done it I'll try. I just think it'll be very odd if nobody more capable has done it. The most difficult part I think would be to make an extend dictionary for every possible attribute that could be apply depending of the rule. I might end up leaving to the user to provide its own dictionary or something, but some cases are conditional so I'm not sure if that could work. For now I'll just keep adding translation every time I need it.
I am using Liferay 6.2 and built-in form validators using AUI taglib, ie:
<aui:input ... >
...
<aui:validator name="number" errorMessage="Enter number" />
</aui:input>
Is there any way to disable and re-enable the validation at runtime (after portlet is displayed) via JavaScript?
The only solution I thought of was to re-implement all validators as custom validators with same functionality and on/off switch - this looks like a lot of work.
I did use the suggested method to reimplement the validators as custom validators, it's not a too big work but it would be really great not to have to do it.
Looking deeper in some liferay component I found that the Liferay.auto_field did remove validators and add it back when required. The code doing it look like this: (https://github.com/liferay/liferay-portal/blob/master/portal-web/docroot/html/js/liferay/auto_fields.js#L219)
var errors = formValidator.errors;
rules = formValidator.get('rules');
node.all('input, select, textarea').each(function(item, index) {
var name = item.attr('name') || item.attr('id');
if (rules && rules[name]) {
deletedRules[name] = rules[name];
delete rules[name];
}
if (errors && errors[name]) {
delete errors[name];
}
});
I didn't try to do it myself, but this should work. Important to note, to get the formValidator you need to (can see on https://github.com/liferay/liferay-portal/blob/master/portal-web/docroot/html/js/liferay/auto_fields.js#L501)
Liferay.Form.get(formId).formValidator
I am using joomla 2.5, i am working on joomla module, i want to perform server side custom form validation at backend setting page in module. I have checked joomla forums , but they all explained according to component , i strictly need to do it in module . I am new in joomla . Please explain the method.
Try this,
First of all you can't do a wide variety of validations like components forms in module params without hacking the core.
the available options are limiting INT,RAW data string only.
you can use the last option of module params called filter. Details take a look at this.
<field name="myintvalue" type="text" default="8" label="Enter some text" description="Enter some description" filter="integer" />
<field name="myhtmlvalue" type="text" default="" label="Enter some text" description="Enter some description" filter="raw" />
Alternate Options.
You can create a custom rule for validation. For example your module name is mod_mymodule:
Add addrulepath attribute to the fieldset in the .xml file:
addrulepath="modules/mod_mymodule"
This will be the path to the custom rule folder.
Add validate attribute to the field with the name of the rule file:
validate="testint"
This will give us the file testint.php.
Create the rule file testint.php and put it to the path specified in the addrulepath attribute. So the full path will be:
administrator/modules/mod_mymodule/testint.php
Here is a simple validation rule class:
class JFormRuleTestint extends JFormRule
{
public function test(&$element, $value, $group = null, &$input = null, &$form = null)
{
return ((int)$value > 0 && (int)$value < 2);
}
}
it should extend JFormRule class and you will need only one method, called test. $value will contain the input from the field. Here we are testing it to be integer between 0 and 2.
Hope its helps..
I am adding a whole bunch of Jquery validation rules dynamically. I am getting error because some of the textboxes are hidden based on user selection on the page before and therefore do not exist on the page. How do I check if the textbox exists before adding the validation rules?
Here are the validation rules being added:
$('[id$="txtLastName"]').rules('add', {
isSpecialChar: true,
maxlength: 13,
oneOrBothEntered: "txtFacility",
messages: {
oneOrBothEntered: "Either Provider Name or Facility Name must be entered"
}
});
$('[id$="txtFirstName"]').rules('add', {
isSpecialChar: true,
maxlength: 11,
conditionallyRequired: "txtLastName",
messages: {
conditionallyRequired: "This field is required."
}
});
...and a whole bunch more. So say txtLastName was hidden, this code breaks. How do I check first if txtlastname exists before adding the rules?
EDIT:
Per #sparky's comment, adding HTML for fields:
<div class="container1">
<span class="span150Padded">Last</span>
<asp:TextBox ID="txtLastName" runat="server" CssClass="textBoxMedium"></asp:TextBox>
</div>
<div class="container1">
<span class="span150Padded">First</span>
<asp:TextBox ID="txtFirstName" runat="server" CssClass="textBoxMedium"></asp:TextBox>
</div>
The reason I am adding the rules dynamically is because I am using master pages so my fields are renamed. I couldn't use the <%=textbox.ClientID%> method because my validation is in a separate js file which is referenced and called from my aspx page, and a js file won't recongnize something like that. After alot of back and forth, I have found that the cleanest solution was to add the validation rules dynamically.
If you have another suggestion for me, please let me know.
When using the jQuery Validate plugin or any of its methods, the plugin will not target all elements if your selector targets more than one element.
Use the jQuery .each() method to target all elements.
$('[id$="txtLastName"]').each(function() {
$(this).rules('add', {
...
});
});
EDIT:
If you want to avoid using .each(), then target the one element.
$('#justOneField').rules('add', {
...
});
Per the documentation
$("#myform").validate({
ignore: ":hidden"
});
My index.html says:
<script type="text/x-handlebars" data-template-name="loggedout">
<label>Username: </label>{{view Ember.TextField placeholder="your username" valueBinding="App.LoggedoutController.username"}}<br />
<label>Password: </label>{{view Ember.TextField placeholder="your password" valueBinding="App.LoggedoutController.password" type="password"}}<br />
<br /><button {{action login}}>Login</button>
</script>
The action goes to my router which redirects to my controller
App.LoggedoutController = Ember.Controller.extend({
username: '',
password: '',
isError: false,
tryLogin: function() {
console.log("InController: launched");
var username = this.get("username");
console.log("Check:" + username);
....
but Check is empty.
Fiddle
If you call "connectOutlet" in your router then you don't have to worry about the App.loggedOutController bit (from an MVC point of view it's better to keep the "App." out of templates as much as possible).
loggedOut: Ember.Route.extend
route: '/signin'
connectOutlets: (router) ->
router.get("applicationController").connectOutlet 'loggedOut'
Then in your template you can simply have:
{{view Ember.TextField placeholder="your username" valueBinding="username"}}
The path App.LoggedoutController.username in your valueBinding is wrong. With App.LoggedoutController you are referencing the class you have defined by using Ember.Controller.extend(). Probably somewhere in your code you have used App.intialize(). This causes the Controller to be instantiated by the framework. Then you can retrieve it by using the path App.router.loggedoutController.
Remember: Names of instances start always with a small letter. Classes alway with a big one.
So the solution is: Use valueBindung="App.router.loggedoutController.username"
Edit: Your fiddle is not working, since you did not link the required ember libraries. Look at the left in 'Add Resources'. There you have to specify the right URLs for Ember and Handlebars JS files.
The issue was with the camelCasing & using the router keyword, you did not have router int he binding...
You used
App.outController.username
instead of App.router.outController.username
This is the working fiddle