I have been following the docs and a couple stackoverflow post but it seems I made a mistake I can't figure out. I get the the error Method[validateOnOrAfter] does not exist.
app/start/global.php
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/custom',
));
app/custom/validation.php
<?php
class CustomValidator extends Illuminate\Validation\Validator
{
public function validateOnOrAfter($attribute, $value, $parameters)
{
$OnOrAfter = strtotime($this->getValue($parameters[0]));
$ToValidateDate = strtotime($value);
return ($OnOrAfter >= $ToValidateDate);
}
}
Validator::resolver(function($translator, $data, $rules, $messages)
{
$messages = array(
'on_or_after' => 'The :attribute must be on of after :value'
);
return new CustomValidator(($translator, $data, $rules, $messages);
}
Edit
In desperation I also tried using the other method in the docs Validator::extend directly in the controller#store method (had to make some changes to code) and that does find the method but it does nothing in my validation despite the return value being false.
app/controller/ProgramSession#store
Validator::extend( 'on_or_after', function($attribute, $value, $parameters)
{
$OnOrAfterThisDate = Input::get($parameters[0]);
$ToValidateDate = ($value);
//dd(strtotime($OnOrAfterThisDate) <= strtotime($ToValidateDate));
return (strtotime($OnOrAfterThisDate) <= strtotime($ToValidateDate));
});
Validator::replacer('on_or_after', function($message, $attribute, $rules, $parameters)
{
$messages = array(
'on_or_after' => 'The :attribute must be on of after :parameter'
);
});
Related
Adding a custom video length validaiton rule but the :max_duration is never replaced in the error message addReplacer method is never called. Is there a livewire way of doing this?
Validator::extend('video_length', function ($attribute, $value, $parameters, $validator) {
$max_seconds = $parameters[0];
// Replace dynamic variable
$validator->addReplacer('video_length_duration', function ($message, $attribute, $rule, $parameters) use ($max_seconds) {
return trim(str_replace(':max_duration', gmdate("H:i:s", $max_seconds), $message));
});
return false;
}, 'Video duration must be less then :max_duration');
$this->validate([
'file' => 'required|file|max:102400|video_length:86400',
]);
In my input form, I have two fields; momentFrom & momentTo. I need to put a validation which gives error message if any of the following criteria fails.
momentFrom is greater than or equal to momentTo.
momentFrom is less than now.
My code for storing the data:
public function store(Request $request, Requisition $requisitionObj) {
$momentFrom = strtotime($request->txtTravelDate . " " . $request->txtTimeFrom);
$momentTo = strtotime($request->txtTravelDate . " " . $request->txtTimeTo);
$timeValidation = $requisitionObj->validateTiming($momentFrom, $momentTo);
if ($timeValidation['error']) {
echo 'ERROR: ' . $timeValidation['message'];
return view('requisitions.create');
} else {
/* store form data into requisition object */
$requisitionObj->travel_date = $request->txtTravelDate;
$requisitionObj->moment_from = $momentFrom;
$requisitionObj->moment_to = $momentTo;
$requisitionObj->save();
return redirect()->route('requisitions.index');
}
}
I have seen laravel custom validation rules where only one field can be validated at a time. But in my scenario I need to check both fields at a time depending on each other. How can I achieve this?
Thanks for any help in advance!
Creating new Rule Class
You can create your custom rule with the artisan command: php artisan make:rule YourRuleNamethis will create a new Rule Class file into the Rules folder.
By default the created file contains a constructor, a passes method and a message method.
Rules Logic
If you have some complicated rules where you need the request or some models, you can pass them via the constructor.
public function __construct(Request $request, User $user, ....)
{
//save them into class variables to access them later
$this->request = $request;
$this->user = $user;
}
Otherwise you can directly put your validation logic into the passes method:
public function passes($attribute, $value){
//some code
return #myCondition
}
Last you are able to specify the message if the validation fails.
public function message()
{
return 'Your message';
}
To use your rule simply add it to your rules array:
$rules = [
'my_attribute' => [new MyCustomRule(),...],
]
At last, I have solved this problem using FormRequest and AppServiceProvider. Thought this would help others who come to this place.
First I have created FormRequest validator using following artisan command.
php artisan make:request StoreRequisition
Then added primary validation rules and messages into it.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreRequisition extends FormRequest {
public function authorize() {
return true;
}
public function rules() {
$rules = [
'txtTravelDate' => 'required|date_format:Y-m-d|after_or_equal:today',
'txtTimeFrom' => 'required|date_format:H:i|travel_time_validate',
'txtTimeTo' => 'required|date_format:H:i',
];
return $rules;
}
public function messages() {
return [
'txtTravelDate.required' => 'Travel date is required!',
'txtTravelDate.date_format' => 'Invalid format for Travel Date!',
'txtTravelDate.after_or_equal' => 'Travel Date should be today or later!',
'txtTimeFrom.required' => 'Time From is required!',
'txtTimeFrom.date_format' => 'Invalid format for Time From!',
'txtTimeFrom.travel_time_validate' => 'Invalid time selected!',
'txtTimeTo.required' => 'Time To is required!',
'txtTimeTo.date_format' => 'Invalid format for Time To!',
'listFunction.required' => 'Department to be selected!',
'txtPickLoc.required' => 'Pickup Location is required!',
'txtDropLoc.required' => 'Drop Location is required!',
'listPurpose.required' => 'Travel Purpose to be selected!'
];
}
}
Then inside app\Providers\AppServiceProvider, added the extra validation logic.
public function boot() {
Validator::extend(
'travel_time_validate',
function ($attribute, $value, $parameters, $validator) {
$inputs = $validator->getData();
/* convert time to moments */
$momentFrom = strtotime($inputs['txtTravelDate'] . " " . $inputs['txtTimeFrom']);
$momentTo = strtotime($inputs['txtTravelDate'] . " " . $inputs['txtTimeTo']);
$result = true;
if ($momentFrom >= $momentTo) {
$result = false;
}
return $result;
}
);
}
My Controller:
public function store(StoreRequisition $request, Requisition $requisitionObj) {
$validatedData = $request->validated();
/* store form data into requisition object */
$requisitionObj->requester_id = Auth::user()->id;
$requisitionObj->travel_date = $request->txtTravelDate;
$requisitionObj->time_from = $request->txtTimeFrom;
$requisitionObj->time_to = $request->txtTimeTo;
$requisitionObj->purpose_id = $request->listPurpose;
/* Finally save the record into the database */
$requisitionObj->save();
return redirect()->route('requisitions.index');
}
Example how make custom rule for validation in Laravel 8.x / Lumen 8.x.
public static function rules(){
return [
'number' => [
'required', 'min:1', 'max:30', 'string', self::testNumber(),
],
];
}
public static function testNumber(){
return function($attribute, $value, $fail){
if ($value === 'foo'){
$fail('The '.$attribute.' is invalid.');
}
};
}
I need to check some special validation in my action store
public function store(Request $request) {
$this->validate($request, [
'practice'=>'required|max:100',
'project'=>'required',
'work_place'=>'required',
'telephone_1'=>'required',
'date_recurring_for_beginning' => 'required|date',
'date_recurring_for_end' => 'required|date|after_or_equal:date_recurring_for_beginning',
]);
RequestCollaborator::create($request->all());
return redirect()->route('requestsCollaborator.index')
->with('flash_message',
trans('request.request_created'));
}
I have to validate if the difference between date_recurring_for_beginning and date_recurring_for_end is 3 months?
there is any solution for doing this or I have to create a custom validation?
You can use Validator::extend() and can create your custom validation rule. Like
Validator::extend('valid_date_range', function ($attribute, $value, $parameters, $validator) {
$dateBeginning = \Carbon::createFromFormat('Y-m-d', $parameters[0]); // do confirm the date format.
$dateEnd = \Carbon::createFromFormat('Y-m-d', $value);
return $dateBeginning->diffInMonths($dateEnd) == $parameters[1];
});
You can use this like:
'date_recurring_for_end' => 'required|date|valid_date_range:date_recurring_for_beginning,3'
For more details about the custom validation. Please follow the documentation.
https://laravel.com/docs/5.8/validation
Create a custom validation rule within your app/Providers/AppServiceProvider:
public function boot()
{
Validator::extend('date_difference', function ($attribute, $value, $parameters, $validator) {
$firstDate = Carbon::parse($parameters[0]);
$secondDate = Carbon::parse($parameters[1]);
$minDifference = (int)$parameters[2];
if($firstDate->diffInMonths($secondDate) < $minDifference)
return false;
return true;
});
}
To use this rule:
$this->validate([
'some_field' => 'date_difference:date_one,date_two,3',
]);
Hope it helps.
I need to check if a user has posted the same password as the one in the database. Field for old password is 'oldpass'. The custom validator i created is called 'passcheck'. It should fail or pass accordingly.
My UsersController code below doesnt work. What could have I have done wrong?
$rules = array(
'oldpass' => 'passcheck',
);
$messages = array(
'passcheck' => 'Your old password was incorrect',
);
Validator::extend('passcheck', function($attribute, $value, $parameters)
{
if(!DB::table('users')->where('password', Hash::make(Input::get('oldpass')))->first()){
return false;
}
else{
return true;
};
});
$validator = Validator::make($inputs, $rules, $messages);
You should use something like this,
$user = DB::table('users')->where('username', 'someusername')->first();
if (Hash::check(Input::get('oldpass'), $user->password)) {
// The passwords match...
return true;
}
else {
return false;
}
So, you have to get the record using username or any other field and then check the password.
#lucasmichot offered even shorter solution:
Validator::extend('passcheck', function ($attribute, $value, $parameters)
{
return Hash::check($value, Auth::user()->getAuthPassword());
});
I would make it like this:
/**
* Rule is to be defined like this:
*
* 'passcheck:users,password,id,1' - Means password is taken from users table, user is searched by field id equal to 1
*/
Validator::extend('passcheck', function ($attribute, $value, $parameters) {
$user = DB::table($parameters[0])->where($parameters[2], $parameters[3])->first([$parameters[1]]);
if (Hash::check($value, $user->{$parameters[1]})) {
return true;
} else {
return false;
}
});
This validator rule will make database query to check current user's password
You can make it even shorter and save query:
Validator::extend('passcheck', function ($attribute, $value, $parameters) {
return Hash::check($value, Auth::user()->getAuthPassword());
});
Please dont tie your rule to an Html element. Use the parameters Laravel provides to create your custom rules. This would be (asuming that you have a user authenticated):
Validator::extend('passcheck', function($attribute, $value, $parameters) {
return Hash::check($value, Auth::user()->password); // Works for any form!
});
$messages = array(
'passcheck' => 'Your old password was incorrect',
);
$validator = Validator::make(Input::all(), [
'oldpass' => 'passcheck',
// more rules ...
], $messages);
I use the following rules for validation on creating a new user:
protected $rules= [
'name' => 'required',
'email' => [
'required',
'unique:user',
'email'
]
];
When updating an existing user I use the same ruleset as shown above
but don't want a validation error if the user didn't change his email at all.
I currently resolve this by using the following:
if (!User::changed('email')) {
unset($user->email);
}
It feels like a dirty workaround to me so I was wondering if there are better alternatives.
Also note that the changed method is something I wrote myself. Does anyone know if there
is a native Laravel 4 method for checking whether a model property has changed?
Thanks!
The unique validation rule allows to ignore a given ID, which in your case is the ID of the data set you are updating.
'email' => 'unique:users,email_address,10'
http://four.laravel.com/docs/validation#rule-unique
One approach is to create a validation function in the model and call it with the controller passing in the input, scenario and id (to ignore).
public function validate($input, $scenario, $id = null)
{
$rules = [];
switch($scenario)
{
case 'store':
$rules = [
'name' => 'required|min:5|unique:users',
'email' => 'required|email|unique:users',
'password' => 'required|min:4|confirmed'
];
break;
case 'update';
$rules = [
'name' => 'required|min:5|unique:users' .',name,' . $id,
'email' => 'required|email|unique:users' .',email,' . $id,
'password' => 'min:4|confirmed'
];
break;
}
return Validator::make($input, $rules);
}
Then in the controller:
$input = Input::all();
$validation = $user->validate($input, 'update', $user->id);
if ($validation->fails())
{
// Do stuff
}
else
{
// Validation passes
// Do other stuff
}
As others mentioned, the 3rd parameter of the unique rule specifies an id to ignore. You can add other cases, such as 'login' to reuse the validation function.
Alternatively, Jeffrey Way at Tuts Premium has a great series of lessons in "What's New In Laravel 4" which includes a couple of other approaches to handling validation using services and listeners.
See the documentation on http://four.laravel.com/docs/validation#rule-unique
You can exclude the users own id
protected $rules= [
'name' => 'required',
'email' => [
'required',
'unique:user,email,THE_USERS_USER_ID',
'email'
]
];
As of 2014-01-14, you can use sometimes attribute, I believe Taylor added them 2 days ago to Laravel 4.1
$v = Validator::make($data, array(
'email' => 'sometimes|required|email',
));
sometimes only validate input if it exists. this may or may not suit your exact scenario, if you don't have a default value for insert.
http://laravel.com/docs/validation#conditionally-adding-rules
I handle this sort of thing in my validator function. My validators array is setup as a class variable. I then do something like this:
public function validate()
{
//exclude the current user id from 'unqiue' validators
if( $this->id > 0 )
{
$usernameUnique = 'unique:users,username,'.$this->id;
$emailUnique = 'unique:users,email,'.$this->id;
$apiUnique = 'unique:users,api_key,'.$this->id;
}
else
{
$usernameUnique = 'unique:users,username';
$emailUnique = 'unique:users,email';
$apiUnique = 'unique:users,api_key';
}
$this->validators['username'] = array('required', 'max:32', $usernameUnique);
$this->validators['email'] = array('required', 'max:32', $emailUnique);
$this->validators['api_key'] = array('required', 'max:32', $apiUnique);
$val = Validator::make($this->attributes, $this->validators);
if ($val->fails())
{
throw new ValidationException($val);
}
}
I have solved this by having different rules for update and create on models that need to do so, like Users.
I have a Model class that extends Eloquent, where I define the validation, and then all child models that extend the Model can have have both the $rules and $update_rules defined. If you define only $rules, it will be used both for create and update.
class Model extends Eloquent {
protected $errors;
protected static $rules = array();
protected $validator;
public function __construct(array $attributes = array(), Validator $validator = null) {
parent::__construct($attributes);
$this->validator = $validator ?: \App::make('validator');
}
protected static function boot() {
parent::boot();
# call validatie when createing
static::creating(function($model) {
return $model->validate();
});
# call validatie when updating with $is_update = true param
static::updating(function($model) {
return $model->validate(true);
});
}
public function validate($is_update = false) {
# if we have $update_rules defined in the child model, and save is an update
if ($is_update and isset(static::$update_rules)) {
$v = $this->validator->make($this->attributes, static::$update_rules);
}
else {
$v = $this->validator->make($this->attributes, static::$rules);
}
if ($v->passes()) {
return true;
}
$this->setErrors($v->messages());
return false;
}
protected function setErrors($errors) {
$this->errors = $errors;
}
public function getErrors() {
return $this->errors;
}
public function hasErrors() {
return ! empty($this->errors);
}
}