Laravel "At Least One" Field Required Validation - php

So I have this form with these fields
{{ Form::open(array('url' => 'user', 'id' => 'user_create_form')) }}
<div class="form-input-element">
<label for="facebook_id">ID Facebook</label>
{{ Form::text('facebook_id', Input::old('facebook_id'), array('placeholder' => 'ID Facebook')) }}
</div>
<div class="form-input-element">
<label for="twitter_id">ID Twitter</label>
{{ Form::text('twitter_id', Input::old('twitter_id'), array('placeholder' => 'ID Twitter')) }}
</div>
<div class="form-input-element">
<label for="instagram_id">ID Instagram</label>
{{ Form::text('instagram_id', Input::old('instagram_id'), array('placeholder' => 'ID Instagram')) }}
</div>
{{ Form::close() }}
I'd like to tell Laravel that at least one of these fields is required. How do I do that using the Validator?
$rules = array(
'facebook_id' => 'required',
'twitter_id' => 'required',
'instagram_id' => 'required',
);
$validator = Validator::make(Input::all(), $rules);

Try checking out required_without_all:foo,bar,..., it looks like that should do it for you. To quote their documentation:
The field under validation must be present only when the all of the other specified fields are not present.
Example:
$rules = array(
'facebook_id' => 'required_without_all:twitter_id,instagram_id',
'twitter_id' => 'required_without_all:facebook_id,instagram_id',
'instagram_id' => 'required_without_all:facebook_id,twitter_id',
);
$validator = Validator::make(Input::all(), $rules);

**For automatic validation**
$rules = array(
'facebook_id' => 'required_without_all:twitter_id,instagram_id',
'twitter_id' => 'required_without_all:facebook_id,instagram_id',
'instagram_id' => 'required_without_all:facebook_id,twitter_id',
);
$message = array(
'facebook_id' => 'The facebook field is required when none of twitter / instagram are present.',
'twitter_id' => 'The twitter field is required when none of facebook / instagram are present.',
'instagram_id' => 'The instagram field is required when none of twitter / facebook are present.');
$validator = Validator::make(Input::all(), $rules, $message)->validate();

use this code i already made it
php artisan make:rule RequiredWithout
use Illuminate\Contracts\Validation\Rule;
class RequiredWithout implements Rule
{
private $without = [];
private $current_attribute = "";
private $no_need = "";
public function __construct($without)
{
if(is_string($without))
{
$this->without = [$without];
}
elseif(is_array($without))
{
$this->without = $without;
}
else
throw new \Exception('$without must be array or string');
}
public function passes($attribute, $value)
{
$this->current_attribute = $attribute;
$requests = request()->all();
foreach ($this->without as $WO_i)
{
if(array_key_exists($WO_i, $requests))
{
$this->no_need = $WO_i;
return false;
}
}
return true;
}
public function message()
{
return "the $this->current_attribute Field and $this->no_need Shouldn't be Exist in this request together";
}
}
and then in the controller use this
'country_id' => ['nullable', 'exists:countries,id', new ValidCountryID(), new RequiredWithout('country_code')],
'country_code' => ['nullable', 'exists:countries,IsoCountryCode', new ValidCountryID(), new RequiredWithout('country_id')],

Rule required_without_all can be hacked to get the desired results.
Create a dummy rule for require_one, and pass all fields to the rule params. if none exists, the dummy rules fires up with required.
$rules = array(
'facebook_id' => 'required',
'twitter_id' => 'required',
'instagram_id' => 'required',
);
$keys = implode(',', array_keys($rules));
$rules['require_one'] = "required_without_all:$keys";
$messages = [
'require_one.required_without_all' => '*At least one field is required'
];
$validator = Validator::make(Input::all(), $rules, $messages);

This is possible to implement with an After Validation Hook:
$validator->after(function ($validator) {
if (empty($this->validated())) {
$validator->errors()->add('empty', 'At least one field must be provided.');
}
});
Or if you are using a FormRequest:
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (empty($this->validated())) {
$validator->errors()->add('empty', 'At least one field must be provided.');
}
});
}

Related

Is there a way to display which element in an array failed validation?

I'm using a Class extends Laravel's FormRequest class. I have arrays incoming, so I have rules like:
public function rules()
{
return [
'name' => 'required',
'name.*.value' => 'required',
'email' => 'required',
'email.*.value' => 'required|email',
];
}
Basicly when I do my Ajax call it returns 422 with message for eg:
The name.0.value field is required.
I want it to be something like : The {index}th name is required.
public function messages()
{
return [
'email.*.value.required' => 'Recipient email field is required',
'email.*.value.email' => 'Wrong e-mail format',
];
}
Is there an option to include the * somehow in the message? Or am I supposed to process it with JQuery?
Thanks in advance.
Try to use loop like this:
public function messages() {
$messages = [];
foreach ($this->get('email') as $key => $val) {
$messages["email.$key.value.required"] = "email $key is required";
$messages["email.$key.value.email"] = "email $key is wrong e-mail format";
}
return $messages;
}
I have refactored the code a little bit, to suit my style. It's working like this as well, if someone like this style more. Of course TsaiKoga's answer is flawless, and good to go with it!
public function messages(){
$messages=[];
foreach ($this->get('email') as $key => $val) {
$messages = [
"email.$key.value.required" => "$key th e-mail is required",
"email.$key.value.email" => "$key th e-mail is wrong e-mail format",
"name.$key.value.required" => "$key th name is required"];
}
return $messages;
}
$rules = [
'name' => 'required',
'password' => 'required',
'email' => 'required|email'
];
$validator = Validator::make($request->only('name','password','email'), $rules);
if ($validator->fails()) {
$messages = $validator->errors()->messages();
return response()->json(['status' => 'error', 'messages' => $messages]);}

method not allowed laravel validation post

I want to validate input in POST method but the result message shows that Method is Not Allowed. Here's my code for create new user in database (UserController.php)
public function userRegister(Request $request)
{
$data['error']['state'] = false;
$rules = [
'name' => 'required',
'username' => 'required|unique:username',
'nip' => 'required|unique:nip',
'email' => 'required|unique:email',
'phone' => 'required',
'avatar' => 'required',
'password' => 'required',
'faculty_id' => 'required',
'building_id' => 'required',
'room_id' => 'required'
];
$message = [
'required' => 'Fill the required field.',
'username.unique' => 'Username already taken.',
'nip.unique' => 'Staff ID already taken.',
'email.unique' => 'Email already taken.',
];
$validator = $this->validate($request,$rules,$message);
if($validator->fails()){
$data['error']['state'] = true;
$data['error']['data'] = $validator->errors()->first();
}
else{
$data['user']['name'] = $request->input('user.name');
$data['user']['surname'] = $request->input('user.surname');
$data['user']['username'] = $request->input('user.username');
$data['user']['nip'] = $request->input('user.nip');
$data['user']['email'] = $request->input('user.email');
$data['user']['password'] = Hash::make($request->input('user.password'));
$data['user']['phone'] = $request->input('user.phone');
$data['user']['level'] = $request->input('user.role');
$data['user']['username_telegram'] = $request->input('user.username_telegram');
$data['user']['user_email_action'] = $request->input('user.user_email_action');
$data['user']['user_telegram_action'] = $request->input('user.user_telegram_action');
$data['user']['faculty_id'] = $request->input('user.faculty');
$data['user']['building_id'] = $request->input('user.building');
$data['user']['room_id'] = $request->input('user.room');
$data['user']['verified'] = 0;
if(!empty($request->input('user.avatar'))){
$data['user']['avatar'] = $request->input('user.username').'-'.$request->input('user.new_avatar');
}
else{
$data['user']['avatar'] = 'default.png';
}
$user_id = DB::table('register')->insertGetId($data['user'],'id');
}
return response()->json($data);
}
Here's the message:
Error Message
Do you know how to solve it? Thank you.
Your question doesn't show the routes of your application but you'll need to make sure your form is set to post
<form action="/my/url/path" method="post">
and your route is set to 'post'
E.g.
Route::post('/my/url/path', 'MyController#userRegister');
Please note that if you're not using Laravel Collective you'll need to make sure you include the CSRF token
<form method="POST" action="/my/url/path">
#csrf (laravel 5.6)
{{ csrf_field() }} (previous versions)

Custom Laravel validation messages

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.

Trying to create two way login form in Laravel - 'Array to string conversion'

I have normal login form which work great. Now I'm trying to make second simple step when user enter his password and user name and if they are correct to redirect him to new page where he must enter pass phrase in order to continue.
I'm not sure if this is correct what I have make so far. This is my route:
Route::get ('/users/login', ['uses' => 'UsersController#login', 'before' => 'guest']);
Route::post('/users/login', ['uses' => 'UsersController#loginSubmit', 'before' => 'guest']);
// new
Route::get('/users/auth', ['uses' => 'UsersController#loginAuth', 'before' => 'guest']);
Route::post('/users/auth', ['uses' => 'UsersController#loginSubmitAuth', 'before' => 'auth|csrf']);
This is my auth.blade.php
{{ Form::open(['class' => 'form-horizontal']) }}
<div class="form-group"> {{ Form::textarea('key', ['class' => 'form-control', 'id' => 'key', 'autocomplete' => 'off']) }} </div><br/>
<hr />
<div class="row">
<button type="submit" class="btn btn-primary col-xs-4 col-xs-offset-4">Login</button>
</div>
<hr />
{{ Form::close() }}
This is my controller
public function login() {
return View::make('site.users.login');
}
public function loginSubmit() {
$validatorRules = array(
'captcha' => 'required|captcha',
'username' => 'required|alpha_dash',
'password' => 'required|min:6'
);
Input::merge(array_map('trim', Input::all()));
$validator = Validator::make(Input::all(), $validatorRules);
if ($validator->fails()) {
return Redirect::to('/users/login')->withErrors($validator->errors())->withInput(Input::except(['captcha']));
}
$user = User::where('username', Input::get('username'))->first();
if (!$user) {
$validator->messages()->add('username', 'Invalid login or password.');
return Redirect::to('/users/login')->withErrors($validator->errors())->withInput(Input::except(['captcha']));
}
if (!Hash::check(Input::get('password'), $user->password)) {
$validator->messages()->add('username', 'Invalid login or password.');
return Redirect::to('/users/login')->withErrors($validator->errors())->withInput(Input::except(['captcha']));
}
//$user->last_login = \Carbon\Carbon::now();
//$user->save();
//Session::put('user', ['user_id' => $user->user_id]);
return Redirect::to('/users/auth');
}
public function loginAuth() {
return View::make('site.users.auth');
}
public function loginSubmitAuth() {
$validatorRules = array(
'key' => 'required',
'captcha' => 'required|captcha'
);
Input::merge(array_map('trim', Input::all()));
$validator = Validator::make(Input::all(), $validatorRules);
if ($validator->fails()) {
return Redirect::to('/users/auth')->withErrors($validator->errors())->withInput(Input::except(['captcha']));
}
$user = User::where('key', Input::get('key'))->first();
if (!$user) {
$validator->messages()->add('key', 'Invalid Key.');
return Redirect::to('/users/auth')->withErrors($validator->errors())->withInput(Input::except(['captcha']));
}
$user->last_login = \Carbon\Carbon::now();
$user->save();
Session::put('user', ['user_id' => $user->user_id]);
return Redirect::to('/');
}
Current error is 'Array to string conversion'
Any help is appreciated. Thank's
The issue of second parameter in Form::textarea you need to pass null to make it empty in second parameter and array in third parameter like,
<div class="form-group">
{{ Form::textarea('key',null, ['class' => 'form-control', 'id' => 'key', 'autocomplete' => 'off']) }}
</div><br/>
You can refer to Creating a Textarea Input Field
Can you try if this fixes your problem:
{{ Form::textarea('key', null, ['class' => 'form-control', 'id' => 'key', 'autocomplete' => 'off']) }}
It's this way because the value argument comes second and it is mandatory in difference with the third one which is optional

Laravel MethodNotAllowedHttpException, but my methods match

I have a registration form that I'm creating using the blade templating like so:
{{ Form::open(array('url'=>'registerUser', 'method'=>'POST', 'class'=>'loginForm SignUp')) }}
In routes.php, I have the following route:
Route::post('registerUser', 'UsersController#doRegister');
But when I submit the form, I get a MethodNotAllowedHttpException. Pretty much every other question I've found online about this was a case of the form having the GET method while the route had POST, but mine match, so I'm pretty confused.
Edit: Here's my full routes file:
Route::get('', 'UsersController#showLogin');
Route::get('login', 'UsersController#showLogin');
Route::post('doLogin', 'UsersController#doLogin');
Route::get('signUp', 'UsersController#showSignUp');
Route::post('authenticateCode', 'UsersController#authenticateCode');
Route::post('requestCode', 'UsersController#requestCode');
Route::get('showRegister', 'UsersController#showRegister');
Route::post('registerUser', 'UsersController#doRegister');
Route::get('dashboard', 'DashboardController#showDashboard');
Here's the controller function:
public function doRegister() {
$rules = array(
'fname' => 'required|alpha|min:2',
'lname' => 'required|alpha|min:2',
'email' => 'required|email|unique:users',
'phone' => 'required|alpha_num|min:7',
'company' => 'required|alpha_spaces|min:2',
'password' => 'required|alpha_num|between:6,12|confirmed', // these password rules need to be improved
'password_confirmation' => 'required|alpha_num|between:6,12'
);
$validator = Validator::make(Input::all(), $rules);
if($validator->passes()) {
$user = User::create(array(
'fname' => Input::get('fname'),
'lname' => Input::get('lname'),
'email' => Input::get('email'),
'password' => Hash::make(Input::get('password')),
'phone' => Input::get('phone'),
'company' => Input::get('company')
));
// Update the invite key that was passed to the register page
// with this new user's ID.
$key = InviteKey::find(Input::get('key'));
$key->user_id = $user->id;
$key->save();
return Redirect::to('login')->with('message', 'Thank you for registering!');
} else {
return Redirect::to('register')
->with('message', 'The following errors occurred')
->withErrors($validator)
->withInput(Input::except('password'));
}
}

Categories