I'm trying to override the custom Laravel authentication by checking if the user confirmed his/her email address. At the same time I would like to log authentication attempts.
The latter I'm trying to achieve with two listeners which I registered in EventServiceProvider.php
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
'Illuminate\Auth\Events\Failed' => [
'App\Listeners\LogFailedAuthenticationAttempt',
],
In app/Http/Controllers/Auth/LoginController.php I have the following.
/**
* Validate the user login request.
* Override vendor method.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function validateLogin(Request $request)
{
$rules = [
'email' => [
'required',
'string',
'exists:users,email,confirmed,1',
],
'password' => [
'required',
'string',
],
];
$messages = [
'email.exists' => 'The combination of email address and password is unknown or the email address has not yet been validated.',
];
$validator = Validator::make($request->all(), $rules, $messages);
// $this->validate($request, $rules, $messages);
if ($validator->fails()) {
return redirect('nl')
->withErrors($validator)
->withInput();
}
}
The problem is that this way it seems to ignore to check if the user confirmed it's email address. And auth:middleware is used. Now change this:
//$validator = Validator::make($request->all(), $rules, $messages);
$this->validate($request, $rules, $messages);
Now it's checked if the address is confirmed, but the Failed event is never called. How can I achieve both calling the Event and the custom rules?
Can someone help me with multiple select in CakePHP 3?
I have a project in CakePHP 3.6. In one of the view, I need to add student's presences, and I wanna do it with a multiple select (Select2).
In one lesson I can choose many students. The students are saved in DB, and in the select input, I wanna get the students from there (DB).
I try to use select2.org script, but it does not work as I want. The input doesn't show the student's name.
This is my input:
echo $this->Form->input('students_id', [
'type' => 'select',
'multiple' => true,
'options' => $students,
'hiddenField' => false,
'id' => 'students_id',
]);
This my script:
$('#students_id').select2({
tag: true,
multiple: 'multiple'
});
And in the controller I get students list in this way:
$students = $this->Students->find('list', ['limit' => 200]);
EDIT:
StudentsTable:
class StudentsTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('students');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->belongsTo('Courses', [
'foreignKey' => 'course_id',
'joinType' => 'INNER'
]);
$this->hasMany('LessonPresences', [
'foreignKey' => 'student_id'
]);
}
/**
* Default validation rules.
*
* #param \Cake\Validation\Validator $validator Validator instance.
* #return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->scalar('name')
->maxLength('name', 45)
->requirePresence('name', 'create')
->notEmpty('name');
$validator
->scalar('lastname')
->maxLength('lastname', 45)
->requirePresence('lastname', 'create')
->notEmpty('lastname');
$validator
->email('email')
->allowEmpty('email');
$validator
->scalar('phone')
->maxLength('phone', 18)
->allowEmpty('phone');
$validator
->integer('grander')
->allowEmpty('grander');
$validator
->scalar('address')
->maxLength('address', 100)
->allowEmpty('address');
$validator
->dateTime('add_date')
->requirePresence('add_date', 'create')
->notEmpty('add_date');
$validator
->date('sign_date')
->requirePresence('sign_date', 'create')
->notEmpty('sign_date');
$validator
->integer('status')
->allowEmpty('status');
$validator
->date('course_end')
->allowEmpty('course_end');
return $validator;
}
}
I'm trying to create customized messages for validation in Laravel 5. Here is what I have tried so far:
$messages = [
'required' => 'Harap bagian :attribute di isi.',
'unique' => ':attribute sudah digunakan',
];
$validator = Validator::make($request->all(), [
'username' => array('required','unique:Userlogin,username'),
'password' => 'required',
'email' => array('required','unique:Userlogin,email'),$messages
]);
if ($validator->fails()) {
return redirect('/')
->withErrors($validator) // send back all errors to the login form
->withInput();
} else {
return redirect('/')
->with('status', 'Kami sudah mengirimkan email, silahkan di konfirmasi');
}
But it's not working. The message is still the same as the default one. How can I fix this, so that I can use my custom messages?
Laravel 5.7.*
Also You can try something like this. For me is the easiest way to make custom messages in methods when you want to validate requests:
public function store()
{
request()->validate([
'file' => 'required',
'type' => 'required'
],
[
'file.required' => 'You have to choose the file!',
'type.required' => 'You have to choose type of the file!'
]);
}
If you use $this->validate() simplest one, then you should write code something like this..
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.'
];
$this->validate($request, $rules, $customMessages);
You can provide custom message like :
$rules = array(
'URL' => 'required|url'
);
$messages = array(
'URL.required' => 'URL is required.'
);
$validator = Validator::make( $request->all(), $rules, $messages );
if ( $validator->fails() )
{
return [
'success' => 0,
'message' => $validator->errors()->first()
];
}
or
The way you have tried, you missed Validator::replacer(), to replace the :variable
Validator::replacer('custom_validation_rule', function($message, $attribute, $rule, $parameters){
return str_replace(':foo', $parameters[0], $message);
});
You can read more from here and replacer from here
For Laravel 8.x, 7.x, 6.x
With the custom rule defined, you might use it in your controller validation like so :
$validatedData = $request->validate([
'f_name' => 'required|min:8',
'l_name' => 'required',
],
[
'f_name.required'=> 'Your First Name is Required', // custom message
'f_name.min'=> 'First Name Should be Minimum of 8 Character', // custom message
'l_name.required'=> 'Your Last Name is Required' // custom message
]
);
For localization you can use :
['f_name.required'=> trans('user.your first name is required'],
Hope this helps...
$rules = [
'username' => 'required,unique:Userlogin,username',
'password' => 'required',
'email' => 'required,unique:Userlogin,email'
];
$messages = [
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
];
$request->validate($rules,$messages);
//only if validation success code below will be executed
//Here is the shortest way of doing it.
$request->validate([
'username' => 'required|unique:Userlogin,username',
'password' => 'required',
'email' => 'required|unique:Userlogin,email'
],
[
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
]);
//The code below will be executed only if validation is correct.
run below command to create a custom rule on Laravel
ı assuming that name is CustomRule
php artisan make:rule CustomRule
and as a result, the command was created such as PHP code
if required keyword hasn't on Rules,That rule will not work
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRule implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
//return true or false
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
}
}
and came time using that
first, we should create a request class if we have not
php artisan make:request CustomRequest
CustomRequest.php
<?php
namespace App\Http\Requests\Payment;
use App\Rules\CustomRule;
use Illuminate\Foundation\Http\FormRequest;
class CustomRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules(): array
{
return [
'custom' => ['required', new CustomRule()],
];
}
/**
* #return array|string[]
*/
public function messages(): array
{
return [
'custom.required' => ':attribute can not be empty.',
];
}
}
and on your controller, you should inject custom requests to the controller
your controller method
class FooController
{
public function bar(CustomRequest $request)
{
}
}
You can also use the methods setAttributeNames() and setCustomMessages(),
like this:
$validation = Validator::make($this->input, static::$rules);
$attributeNames = array(
'email' => 'E-mail',
'password' => 'Password'
);
$messages = [
'email.exists' => 'No user was found with this e-mail address'
];
$validation->setAttributeNames($attributeNames);
$validation->setCustomMessages($messages);
For those who didn't get this issue resolve (tested on Laravel 8.x):
$validated = Validator::make($request->all(),[
'code' => 'required|numeric'
],
[
'code.required'=> 'Code is Required', // custom message
'code.numeric'=> 'Code must be Number', // custom message
]
);
//Check the validation
if ($validated->fails())
{
return $validated->errors();
}
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.',
'max' => 'The :attribute field is may not be greater than :max.'
];
$this->validate($request, $rules, $customMessages);
In the case you are using Request as a separate file:
public function rules()
{
return [
'preparation_method' => 'required|string',
];
}
public function messages()
{
return [
'preparation_method.required' => 'Description is required',
];
}
Tested out in Laravel 6+
you can customise the message for different scenarios based on the request.
Just return a different message with a conditional.
<?php
namespace App\Rules;
use App\Helpers\QueryBuilderHelper;
use App\Models\Product;
use Illuminate\Contracts\Validation\Rule;
class ProductIsUnique implements Rule
{
private array $attributes;
private bool $hasAttributes;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct(array $attributes)
{
$this->attributes = $attributes;
$this->hasAttributes = true;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
$brandAttributeOptions = collect($this->attributes['relationships']['brand-attribute-options']['data'])->pluck('id');
$query = Product::query();
$query->when($brandAttributeOptions->isEmpty(), function ($query) use ($value) {
$query->where('name', $value);
$this->hasAttributes = false;
});
return !$query->exists();
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return ($this->hasAttributes) ? 'The Selected attributes & Product Name are not unique' : 'Product Name is not unique';
}
}
Laravel 10.x
If you are using Form Requests, add another method called messages(): array in your request.
class YourRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required',
'email' => 'required|email',
...
];
}
//Add the following method
public function messages(): array
{
return [
'email.required' => 'Custom message for Email Required',
];
}
}
Then the message will be displayed automatically once the request is send from the form.
I am trying to write a validation rule in CakePHP 3 that checks, if the prename and lastname OR the company name is set.
Validators:
$validator
->add('prename', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
$validator
->add('lastname', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
$validator
->add('name', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
Rule definition:
public function validateName($check, array $context)
{
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return true;
} else {
return false;
}
}
But the validation does not behave as expected. If I enter the company name, I get validation errors for prename and lastname saying that the fields is required. Same when I enter the prename and lastname, it says the company name is required.
What am I doing wrong?
I have also faces this type of weird behaviors with cakePhp 3.x.I manage to solve this problem.
Below is the code to solve the asked question
$validator
->notEmpty('company_name', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
$validator
->notEmpty('prename', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
$validator
->notEmpty('lastname', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
I hope this will be the solution for your problem.
The provided answers all did not work 100%, so I am going to post what I have come up with. I am using conditional validation as described in the CakePHP 3 docs.
CustomersTable.php:
public function validationDefault(Validator $validator)
{
$validator->notEmpty('name', __("Required when prename and lastname is empty."), function ($context) {
return !$context['data']['prename'] && !$context['data']['lastname'];
});
$validator->notEmpty('prename', __('Required when company or lastname is empty.'), function ($context) {
return !$context['data']['name'];
});
$validator->notEmpty('lastname', __('Required if company or prename is empty.'), function ($context) {
return !$context['data']['name'];
});
return $validator;
}
This approach correctly validates the data when it is submitted. However, some browsers say that those fields have to be filled because they are required. To avoid that, we have to define the fields as required => false:
add.ctp view file:
echo $this->Form->input('prename', [
'label' => ['text' => __('Prename (*): ')],
'required' => false,
]);
echo $this->Form->input('lastname', [
'label' => ['text' => __('Lastname (*): ')],
'required' => false,
]);
echo $this->Form->input('name', [
'label' => ['text' => __('Company name (*): ')],
'required' => false,
]);
We have the following code running in production, which is much alike yours:
$validator
->add('various_fee_text', 'custom', [
'rule' => [$this, 'variousFieldsChecker'],
'message' => __('Udfyld både Tekst og DKK feltet'),
])
->allowEmpty('various_fee_text');
Vaildation rule:
/**
* Method checks whether or not various fee text and various fee prices are either both empty, both set or "dirt",
* meaning only one of them is set and the other is empty. We want either both to be set or both to be empty.
*
* #return bool depending on it's OK or not
*/
public function variousFieldsChecker($value, $context)
{
$varioustext = $context['data']['various_fee_text'];
$variousPrice = $context['data']['various_fee_price'];
if (!empty($varioustext) && !empty($variousPrice)) {
return true;
} elseif ((empty($varioustext) && empty($variousPrice))) {
return true;
}
return false;
}
I think what you need is to append the ->allowEmpty() like suggested previously.
For this CakePhp provide create custom validation. You need to create two validation function on your model class and call them conditionally on controller function. You can create validation function like as
public function validationName($validator){
$validator
->requirePresence('prename')
->notEmpty('prename', 'Prename must be set.')
->requirePresence('lastname')
->notEmpty('lastname', 'Lastname must be set.')
->allowEmpty('name');
return $validator;
}
public function validationCompany($validator){
$validator
->requirePresence('name')
->notEmpty('name', 'Company name must be set.')
->allowEmpty('prename')
->allowEmpty('lastname');
return $validator;
}
On controller you can call these function conditionally like as
$validator = 'company';
if(empty($this->request->data[''])){
$validator = 'name';
}
$entity = $this->{$this->modelClass}->newEntity();
$entitydata = $this->{$this->modelClass}->patchEntity($entity, $this->request->data, ['validate' => $validator]);
$this->{$this->modelClass}->save($entitydata);
in my controller i have
public function store(Request $request) {
$validator = Validator::make($request->all(), [
"list_img" => "required",
"ge_title" => "required|max:255"
]);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
if validation fails i got messages -
validation.required
validation.required .....
instead of
ge_title is required
list_img is required
p.s. I have 3 languages on my site and i dont have validation.php file in resources/lang (if it matters)
Try to add the third argument the error messages:
public function store(Request $request){
$validator = Validator::make($request->all(), [
"list_img" => "required",
"ge_title" => "required|max:255"
], [
"list_img.required" => "List img is required",
"ge_title.required" => trans('errors.required'), //if you have multilang. then use trans function
"ge_title.max" => trans('errors.max_title')
]);
if ($validator->fails()){
return redirect()->back()->withErrors($validator)->withInput();
}
}
It is not
$request->query->all()
instead of
$request->all()
for post or something like this ?