Customizing model-stored validation rules in Laravel - php

Let's say, I have a User model in Laravel like this:
class User extends Eloquent implements UserInterface, RemindableInterface {
public static $rules = array(
'email' => 'required|email',
'password' => 'required|min:8|confirmed',
'password_confirmation' => 'required|min:8'
);
...
}
Rules, stored in model, will be reused both for login and register forms but problem occurs when there's no need for password confirmation (e.g. login form). And there could be many such situations where the rules should be changed.
So, is there any pure method how to modify model-stored validation rules for different cases in Laravel?
Do I have to reorganize my rule storage approach at all?
Thanks!

You can add rules dynamically when you need them.
For example:
If I am right, you only need the password_confirmation rule when registering a user and when updating a password. So, in your model, do not add the password_confirmation rule .
public static $rules = array(
'email' => 'required|email',
'password' => 'required|min:8|confirmed'
}
How to add the rule dynamically:
To register a user, the password_confirmation field is required. So, from your controller, you can always add rules like the following:
$rules = User::$rules;
$rules['password_confirmation'] = 'required|min:8';
and sometimes you may need to add rules based on user input.
For example:
If a user selects Australia as country, they must also select a state.
$v = Validator::make($data, $rules ));
$v->sometimes('state', 'required', function($input)
{
return $input->country == 'Australia';
});

Late to the game but per Laravel docs you can use a 'sometimes' rule.
http://laravel.com/docs/validation
In brief:
In some situations, you may wish to run validation checks against a field only if that field is present in the input array. To quickly accomplish this, add the sometimes rule to your rule list:
'password_confirmation' => 'sometimes|required|min:8|confirmed'

I do something like this.
In the Model:
public static $rules = [
'create' => [
'first_name' => 'min:3',
'last_name' => 'min:3',
'email' => 'required|email|unique:users',
'password' => 'required|min:5|confirmed'
],
'edit' => [
'first_name' => 'other',
'last_name' => 'other',
'email' => 'other',
'password' => 'other|min:5'
]
];
In the Controller:
$validator = Validator::make( $input, User::$rules['edit'] ); # Or User::$rules['create']
if ( $validator->fails() ) { code }

As far as i can see the Ardent Package handles model validation well for Laravel > 5.0. It appears to supoort all of the built-in validation features (such as the use of 'sometimes' when you only want to validate a field if it's passed) as well as extending them.
http://packalyst.com/packages/package/laravelbook/ardent

Related

Block registration if form input doesn't match accepted values using Laravel's auth (5.3)

I have this reference_id variable that I want to use to bar registration on my site. Basically, if you don't input a reference_id that matches correctly one value among a list (~5-10) values then I want to turn them away. Similarly to how if you only put TEST in the email field it stops you and says "Hey that's not a valid email!'.
Where would I put that logic in? I've pasted my RegisterController below as I think it should go there along with the email logic. I could easily make a variable and do something like
$rfid=reference_id
$list=array(list)
if ($rfid==$list) {
allow
}
else {
reject
}
But as you can tell even with that I'm not sure how it would work exactly or where to put it among the rest of the code. Any direction would be appreciated!
RegisterController:
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
'reference_id' => 'max:255',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'reference_id' => $data['reference_id'],
]);
}
If the reference_id is present in the table you can use
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
'reference_id' => 'max:255|exists:table_name',
]);
}
If there is an array
use in_array:$array_name for validation
For Proper Understanding of available Laravel Validation rule Refer:
https://laravel.com/docs/5.3/validation#rule-exists
Hope This Helps you..
Lets me know in case of any Query..
Use in validation rule. Advantage of this rule is it's source independent and format independent:
$allowedValues = implode(',', config('my.allowedKeys'));
// Or:
$allowedValues = implode(',', Reference::pluck('id')->toArray());
....
'reference_id' => 'max:255|in:'.$allowedValues,
If you want you can also add custom validation message for this rule.

Laravel custom validation on registration form

I'm currently struggling with a bit of validation on a registration form.
Basically when a user registers it will check if the unique code they have entered is valid and if not doesn't let them sign up.
But in my codes table which this reads from I also have an expiry date on the code.
I need to do another check after it is deemed valid that the expiry date hasn't passed, in other words it is not greater than now.
I think you can do this in the validator but I'm struggling a bit with the syntax and not sure where it should go. Here is my code:
protected function validator(array $data)
{
return Validator::make($data, [
'code' => 'required|exists:codes',
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'date_of_birth' => 'required|date',
'password' => 'required|min:6|confirmed',
'accept_terms' => 'required|accepted',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
Code::where('code', $data['code'])->increment('uses');
$data['code_id'] = Code::where('code', $data['code'])->value('id');
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'date_of_birth' => $data['date_of_birth'],
'accept_terms' => $data['accept_terms'],
'code' => $data['code'],
'code_id' => $data['code_id'],
'password' => bcrypt($data['password']),
]);
}
Thanks in advance :)
As long as you're using Laravel v5.3.18 (or higher) you can use the Rule Class to save you having to define a custom rule.
This:
'code' => 'required|exists:codes',
Can be replaced with:
'code' => [
'required',
Rule::exists('codes')->where(function ($query) {
$query->where('expiry_date', '>=', Carbon::now());
}),
],
(the above is assuming expiry_date is the actual name of the column in your db table).
Documentation: https://laravel.com/docs/5.3/validation#rule-exists
Just make sure you import those facades.
Hope this helps!
You can create custom validation rule. Create service provider and register it. Then add something like this:
Validator::extend('is_code_valid', function($attribute, $value, $parameters, $validator) {
$code = Code::where('code', $value)->where('date', '>', Carbon::now())->first();
return !$code->isEmpty(); // Pass if valid code exists in DB.
});
And then use it:
'code' => 'required|is_code_valid',

How to perform validation when updating a unique field using Http\Request in Laravel

I have a customers table that I use a CustomerRequest to validate the fields, through the use of the rules function. The table has an email field which is required and is unique. This works fine when I create the customer, however when I update the customer info (let's say I got their last name spelled wrong) my request fails because the email address is already in the database.
Here is my CustomerRequest:
public function rules()
{
return [
'givenname' => 'required',
'surname' => 'required',
'email' => 'required|unique:customers,email',
];
}
I would like to reuse the CustomerRequest for all of the customer vaildation, how can I go about doing this?
You need to check here for request type as well as customer id for update and then return rules according to request. Something like this
public function rules(Request $customer_request)
{
return [
'givenname' => 'required',
'surname' => 'required',
'email' => 'required|unique:customers,email,'.$customer_request->get('customer_id'),
];
}

Laravel 5.1 unique email

I'm trying to use the following rule in my code as per the documentation, however it is not working:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|unique:users,email,:email',
];
}
It comes back with The email has already been taken.
I am trying to say if the users email is not unique then throw an error, except for the current user id.
How can I achieve this?
You need to give the unique rule an ID to ignore. Try this:
return [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|unique:users,email,' . Auth::user()->id
];
Note: This assumes you are using Laravel's Auth class.

Is there a way to alias input names in the rules for Laravel 5 validation?

I like the feature in Laravel 5 that let's me throw my validation logic into one of Laravel 5's Form Requests and then Laravel will automatically validate it just before my controller's method is ran. However, one thing that is missing is an easy way to "alias" an input name.
For example (for simplicity sake), say I have a login form with an input field called "username" but it actually accepts an email address. The label on my form says Email. If there's an error, the error will say something like "Username is required". This is confusing since I'm labeling the field as Email on my form.
What's a good solution for aliasing inputs when using Laravel's validator?
So far I've come up with two ideas:
Solution 1: Use Laravel's custom error messages for each rule
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class AuthLoginRequest extends Request {
public function rules()
{
return [
'username' => 'required|email',
'password' => 'required'
];
}
// This is redundant. And may have other pitfalls?
public function messages()
{
return [
'username.required' => 'email is required.',
'username.email' => 'email is invalid.'
];
}
...
}
Solution 2: Use my own custom form class to handle changing the input names to their label/alias (username becomes email for validation purposes), running validation, then changing them back.
`
use App\Http\Requests\Request;
class AuthLoginRequest extends Request {
public function rules()
{
return [
'username' => 'required|email',
'password' => 'required'
];
}
public function messages()
{
return [
'username.required' => ':attribute is required',
'username.email' => ':attribute is invalid'
];
}
public function attributes()
{
return[
'username' => 'email', //This will replace any instance of 'username' in validation messages with 'email'
//'anyinput' => 'Nice Name',
];
}
}`
Updated
I believe anywhere there's an :attribute in your messages will be either default to the name set in your form, or overridden by the method attributes() above. (on :attribute http://laravel.com/docs/5.0/validation#custom-error-messages)
Footnote: I have not explained how I'm doing a dynamic array for my form, as I'm iterating over each form input in a way which may be clumsy. I did notice that I'm using the following line for my form request. I thought I'd mention that here in case:
use Illuminate\Foundation\Http\FormRequest;
Let me know if this is more helpful!
You can customise your validation input names in file resources/lang/en/validation.php, assuming you are using Laravel 5 and using English as locale language by default.
You can find an array called 'custom', simply customise your input names and validation messages there.
For example:
'custom' => array(
'username' => array(
'email' => 'Username is actually an email.'
),
)
where 'username' is your input name, 'email' is the name of built-in rule, and 'Username is actually an email' is whatever you want to tell your user.
Hope this helps!
Open the file resources/lang/en/validation.php, where en is the default language of the app. thars if you are using English. At the bottom of the file, update the attributes array as the following:
'attributes' => array( 'password' => 'Password', 'email' => 'Email Address', ),
Add other attribute names and the corresponding error label. It will do the trick you wanted.
Use this:
$validator = Validator::make($data, [
'username' => 'required|string', // Your field validation
])
->setAttributeNames(
['username' => '"Username"'], // Your field name and alias
);

Categories