Laravel conditional validation does not work - validation

I have a form with these fields:
shipping_method (hidden field with value="2" in my testing case)
courier_id
tracking_no
delivery_date
The courier_id field is required only if the shipping_method is 2
<div class="form-group{{ $errors->has('courier_id') ? ' has-error' : ''}}">
<label>Courier</label>
<select name="courier_id" class="form-control">
<option value="">Select...</option>
#foreach($couriers as $courier)
<option value="{{ $courier->id }}">{{ $courier->name }}</option>
#endforeach
</select>
#if ($errors->has('courier_id'))
<span class="help-block">
<strong>{{ $errors->first('courier_id') }}</strong>
</span>
#endif
</div>
In my controller:
public function update(Request $request, $id)
{
$delivery_date = Null;
$courier_id = Null;
$order = Order::findOrFail($id);
$status = 0;
if($order->status == 2) {
$status = 3;
$courier_id = $request->courier_id;
$messages = [ 'courier_id.required' => 'Please select a courier'];
$v = Validator::make(Input::all(), [
'tracking_no' => 'required',
'delivery_date' => 'required|date_format:d/m/Y'
], $messages)->validate();
$v->sometimes('courier_id', 'required', function (Request $request) {
return true;
//return $request->shipping_method == 2;
});
Even though the courier_id is empty, I don't get the error for it.
I have three questions:
Why even when I just return true on the sometimes check, I don't get the error
Not sure what is the parameter I should send to the sometimes check, is it Request $request?
I tried to send the order to the sometimes check instead of the request so I won't have to have a hidden field for it on the form, e.g.
$v->sometimes('courier_id', 'required', function ($order) {
return $order->shipping_method == 2;
});
Again, no error is displayed.
The order status is 2 for sure.
I also tried:
$v->sometimes('courier_id', 'required', function ($order) {
return $order->shipping_method == '2';
});
If I remove the sometimes check, and just add the courier_id validation as required, I do get the error on the form.

You are adding the conditional rule after you validate the data thus making the validator uninformed about that rule. That should answer your first question
For your question 2, 3 the document states that
The $input parameter passed to your Closure will be an instance of Illuminate\Support\Fluent and may be used to access your input and files.
First add the custom rule to the validator. Then validate the data.
$v = Validator::make(Input::all(), [
'tracking_no' => 'required',
'delivery_date' => 'required|date_format:d/m/Y'
], $messages);
$v->sometimes('courier_id', 'required', function (Request $request) {
return $request->shipping_method == 2;
});
$v->validate();
You should be able to do this without a conditional rule.
You can add the following to your existing rule set which should validate
'courier_id' => 'required_if:shipping_method,2'
So your validation should be
$v = Validator::make(Input::all(), [
'tracking_no' => 'required',
'delivery_date' => 'required|date_format:d/m/Y',
'courier_id' => 'required_if:shipping_method,2'
], $messages)->validate();

Related

Can't submit form and show error message "Trying to get property of non-object"

when I access the form and click the submit button I get an error message.
Trying to get property 'nama_plg' of non-object
code details
<tr>
<td><b>Nama</b> </td>
<td>: </td>
<td>{{ $pelanggan->nama_plg }}</td>
<input type="hidden" name="pelanggan_id" value="{{ $pelanggan->pelanggan_id }}" required>
</tr>
this my controller
public function calculate(Request $request)
{
$validate = $request->validate([
'kode_bkg' => 'required|unique:pemesanans',
'tgl_psn' => 'required',
'durasi' => 'required',
]);
$data = $request->toArray();
$pelanggan = Pelanggan::find($request->pelanggan_id);
$title = 'Detail Pemesanan';
$menu = '5';
return view('pemesanan.details', compact('tgl_balik', 'data', 'total_harga', 'bus', 'dp', 'title', 'menu', 'pelanggan'));
}
Route
Route::post('pemesanan/details', ['as' => 'pemesanan.calculate', 'uses' => 'PemesananController#calculate'])->middleware('auth');
How I can fix this?
First of all, you are not validating pelanggan_id inside the request body. This might be the cause of Pelanggan::find($request->pelanggan_id) can return null. In this case of $pelanggan is null, evaluating $pelanggan->name_plg will throw exactly the same exception as you get now.
The solution to your problem.
Validate pelanggan_id field from the request body, so that the controller will return ValidationException and stops executing if the pelanggan_id field is invalid.
Fix Pelanggan::find($request->pelanggan_id) into Pelanggan::findOrFail($request->pelanggan_id). It will throw ModelNotFoundException in the same case as above.

Image Upload => LogicException Unable to guess the mime type as no guessers are available (Did you enable the php_fileinfo extension?)

I'm following the following tutorial -> http://laraveldaily.com/upload-multiple-files-laravel-5-4.
When I go to post my advert, the add goes thorugh without the photographs. My error message is
Unable to guess the mime type as no guessers are available (Did you enable the php_fileinfo extension?)
I have enabled php_fileinfo and restared the server, but to know avail. Any other ideas on how to fix this?
public function store(Request $request){
$Advert = PropertyAdvert::create([
"address" => $request->address,
"county" => $request->county,
"town" => $request->town,
"type" => $request->type,
"rent" => $request->rent,
"date" => $request->date,
"bedrooms" => $request->bedrooms,
"bathrooms" => $request->bathrooms,
"furnished" => $request->furnished,
"description" => $request->description,
"user_id" => Auth::id(),
]);
foreach ($request->photo as $photo) {
$filename = $photo->store('photo');
PropertyAdvertPhoto::create([
'property_id' => $Advert->id,
'filename' => $filename
]);
}
$id = $Advert->id;
return redirect("/property/$id");
}
UploadRequest "Request File"
This is where all the validation rules are stored.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UploadRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$rules = [
'address' => 'required'
];
$photos = count($this->input('photo'));
foreach(range(0, $photos) as $index) {
$rules['photo.' . $index] = 'min:100';
}
return $rules;
}
}
Upload Form
<form method="POST" action="/property" enctype="multipart/form-data">
{{ csrf_field() }}
<div class="form-group row">
<label for="photo" class="col-md-3 col-form-label text-md-right">Images</label>
<div class="col-md-9">
<input required type="file" class="form-control" name="photo[]" multiple>
</div>
</div>
Your code looks good and I always use foreach but the problem with your loop is you need to invoke your fileinput using the file method :
foreach( $request->file('photo') as $photo )
PS: there is a huge difference between $request->photo and $request->file('photo') so to guess the mime type you should use the file method.
Cheers.
The problem is from your validation!
If you have anything like this:
$this->validate($request, [
'image' => 'required|mimes:jpg,png,jpeg,gif,svg|max:2048',
]);
then replace the validation code to:
'image' => 'required|image|max:2048',
In my case, I had further updates like:
'image' => 'required|image|dimensions:min_width=300,min_height=400,ratio=3/4|max:2048',
Hope this helps. Unfortunately I did not find the reason- why Laravel is not able to retrieve the MIME type and validate the image file uploaded here! This could be because of the another missing PHP extension.
Find all possible validation cases from the doc here.

Why is my validation on my Laravel form failing and routing to a different page?

I'm using Laravel 5.4 and trying to submit a form and check if an input is numeric. But when I get to the validation it routes to a different page.If I remove the validation then everything works correctly.
This is my blade form:pin_verification.blade.php
#extends('layouts.master')
#section('title','Verify Order')
#section('extra_head_info')
<meta name="csrf-token" content="{{ csrf_token() }}">
#endsection
#section('content')
#if(count($errors) > 0)
<ul>
#foreach($errors->all() as $error)
<li class="alert alert-danger">{{$error}}</li>
#endforeach
</ul>
#endif
{{ Form::open(['action' => 'PinVerificationController#pinValidation','id'=>'pin_verification_form']) }}
We sent a text message to {{$clean_number}}. You should receive it within a few seconds.<br><br>
{{ Form::label('Pin Code', null, ['class' => 'control-label']) }}
{{ Form::text('pin_number', null,['placeholder' => 'Pin Code'])}}<br><br>
Enter a 4 digit pin you received by phone.
<br>
<br>
{{ Form::submit('Verify',['name'=>'validate'])}}
{{ Form::close() }}
#endsection
When I click my submit button on my pin_verification.blade.php form
I go to my PinVerificationController.php:
class PinVerificationController extends Controller
{
public function pinValidation(Request $request){
if($request->has('validate')){
$validator = $this->validate($request,[
'pin_number' => 'required|numeric'
]);
return redirect("/test/create");
//return $this->validatePin($request);
}else{//choosing verification method
return $this->choosePinVerficationMethod($request);
}
}
public function init(){
...
}
public function choosePinVerficationMethod(Request $request){
...
}
}
My code goes into pinValidation function and into the first if statement but when it hits the
$validator = $this->validate($request,[
'pin_number' => 'required|numeric'
]);
It routes to my init() function to a different controller, CheckoutController.php
If I remove my validation then my code works correctly and I get redirected to redirect("/test/create");
Why is this happening?
My routes are:
Route::get('/order/verify/{encrypted_key}', ['as'=>'pinverification','uses'=>'PinVerificationController#init']);
Route::get('/test/create', ['as'=>'orders_create', 'uses'=>'OrdersController#init']);
Route::post('/order/verify', ['as'=>'pinverification1', 'uses'=>'PinVerificationController#pinValidation']);
Route::get('/order/checkout/{product_id}', ['as'=>'checkout', 'uses'=>'CheckoutController#init']);
It's because you aren't actually checking the validation, you're just performing the method, so then naturally it just routes to /test/create as per the first return redirect instruction.
Try this instead:
public function pinValidation(Request $request){
if($request->has('validate')){
$validator = Validator::make($request->all(), [
'pin_number' => 'required|numeric'
]);
if ($validator->fails()) {
return redirect('test/create')
->withErrors($validator)
->withInput();
} else {
// Success criteria, validation passed.
}
} else {
$this->choosePinVerficationMethod($request);
}
}
The validate method, you have used here redirects you itself:
$validator = $this->validate($request,[
'pin_number' => 'required|numeric'
]);
You should rather use:
$validator = Validator::make($request,[
'pin_number' => 'required|numeric'
]);
and then check for:
if ($validator->fails()) {
//redirect
};
Reference

check if value already exists in db

I have an insert form and a dropdownbox which displays all cars names and when selected one it saves the id in column "car_id" which is unique. What I want is to check if this id already exists and if yes to display a validation message:
create controller
public function create() {
$cars = DB::table('cars')->orderBy('Description', 'asc')->distinct()->lists('Description', 'id');
return View::make('pages.insur_docs_create', array(
'cars' => $cars
));
}
insur_docs_blade.php
<div class="form-group">
{{ Form::label('car', 'Car', array('class'=>'control-label col-lg-4')) }}
<div class="col-lg-8">
{{ Form::select('car', $cars, Input::old('class'), array(
'data-validation' => 'required',
'data-validation-error-msg' => 'You did not enter a valid car',
'class' => 'form-control'))
}}
</div>
</div>
You can use Laravel's Validator class for this. These are a few snippits of how it works. This methods works by using your data model. Instead of writing everything out I added a few links that provide you all the information to complete your validation.
$data = Input::all();
$rules = array(
'car_id' => 'unique'
);
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
return 'Data was saved.';
}
http://laravelbook.com/laravel-input-validation
http://laravel.com/docs/validation
http://daylerees.com/codebright/validation
You can use Laravel's "exists" method like this:
if (User::where('email', $email)->exists()) {
// that email already exists in the users table
}

Passing variables to view

I think I might have discovered a bug. This is what I have until now.
Routes.php
Route::get('/{user}/{char_dynasty}/{char_name}/selectedok', array(
'as' => 'char-profile-get',
'uses' => 'CharacterController#getDropDownList'));
Route::post('/user/{user}/{char_dynasty}/{char_name}/selectedok', array(
'as' => 'char-profile-post',
'uses' => 'CharacterController#postDropDownList'));
CharacterController.php
class CharacterController extends BaseController{
public function getDropDownList($user, $char_dynasty, $char_name)
{
if(Auth::check())
{
$user = Auth::user();
return View::make('layout.notification', array(
'user' => $user,
'char_dynasty' => $char_dynasty,
'char_name' => $char_name));
}
else
{
return App::abort(404);
}
}
public function postDropDownList()
{
if (Auth::check())
{
$user = Auth::user();
$char_name = User::find($user->id)->characters()->where('char_name', '=', Input::get('choose'))->first();
return Redirect::route('char-profile-get', array(Session::get('theuser'),
$char_name->char_dynasty,
$char_name->char_name));
}
}
}
profile.blade.php (snippet)
<form action="{{ URL::route('char-profile-post') }}" method="post">
<select name="choose">
<option value="choose">Choose a character</option>
<option> {{ $c_name }} </option>
</select>
<input type="submit" value="Ok">
{{ Form::token() }}
</form>
The error says that $char_dynasty is undefined which is usually used
<option> {{ $char_dynasty }} </option>
I changed to populate the drop down list with another variable to be able to execute the database query $char_name from postDropDownList.
If I do in function getDropDownList, var_dump($char_dynasty); var_dump($char_name) I get the following
string 'Spirescu' (length=8)
string 'Ion' (length=3)
The point is that the parameters in getDropDownList are with the correct data, but are not transfered to the View. What am I doing wrong? I don't know how to access the variables in the View?
I have also tried return View::make('layout.notification', compact('user' , 'char_dynasty' , 'char_name' ));
or
$data = array(
'user' => $user,
'char_dynasty' => $char_dynasty,
'char_name' => $char_name);
return View::make('layout.notification', $data);
I receive the same error. or $data is not defined.

Resources