I am trying to fetch details of some user based on id, if id does not exist in database, how to handle error in that case and how can i show some error message for assets/lang/en/somefile.php , saying that 'errorMessage' => 'Some error occured.Please try again!.',
$city=City::with('locations')->findOrFail($id);
// if $id does not exit how to handle error
// how to show message form asses/lang/en/somefile.php to user.
// like "please try again"
return view('admin.city.viewCity',compact('city'));
With laravel you can pass error to view like this,
controller,
Redirect::back()->withInput()->withErrors(['msg' => 'try again']);
view,
<ul class="errors">
#foreach ($errors->all() as $message)
<li>{{ $message }}</li>
#endforeach
</ul>
You can just use find() instead of findOrFail(). Controller's method should looks like...
public function methodName(Request $request, $id)
{
$city = City::with('locations')->find($id);
if ($city === null) {
return redirect()->back()->withErrors(['msg' => 'Can not find city.']);
} else {
return view('admin.city.viewCity', [
'city' => $city,
]);
}
}
Or shorter version:
return $city === null
? redirect()->back()->withErrors(['msg' => 'Can not find city.'])
: view('admin.city.viewCity', [
'city' => $city,
]);
Please try this
$city = City::with('locations')->findOrFail($id);
if(count($city) > 0 ){
return view('admin.city.viewCity',compact('city'))
}else{
return view('your message inside balde')
}
or
$city = City::with('locations')->findOrFail($id);
if(count($city) > 0 ){
return view('admin.city.viewCity',compact('city'))
}else{
$errorMessage = "User not found";
return view('admin.city.viewCity',compact('errorMessage'))
}
Please try this what I have done before
if(!$city->isEmpty()){
return view('single', compact('city'));
}else{
return view('nodata', compact('city'));
}
noted: nodata it mean your blade view to show message error to user
Related
I'm learning Laravel and I have a question that I do not understand.
I'm using query builder to run my own queries and I don't really know how to return error message when there is no record:
public function store()
{
$item = request()->validate([
'item' => 'required|min:6|max:10'
]);
$details = DB::connection('sqlsrv')->table('TABLENAME')->where('ITEMID', '=', $item )->get();
return view('itemdetails.create', compact('details'));
}
So if $details is null I need to return message how to do that? Something like in raw PHP
if(empty($details))
{
throw new Exception('My text')
}
Or check in a blade file:
#if (count($details) != 1)
I don't have a record!
#endif
I tried firstOrFail but looks like this is not working.
Is there any other ways (best ways)?
In controller
$validator = \Validator::make($request->all(), [
'item' => 'required|min:6|max:10'
]);
$details = DB::connection('sqlsrv')->table('TABLENAME')->where('ITEMID', '=', $item )->get();
if (!$details) {
$validator->errors()->add('item', 'Item not found');
}
if ($validator->fails()) {
return redirect()
->back()
->withErrors($validator)
->withInput();
}
return view('itemdetails.create', compact('details'));
}
And in the view file
{{$validator->errors()->first('item')}}
Just use normal if condition will do for Controller
if($details) //True
{
//Redirect to..
}else
{
//Redirect to.. //False
}
For blade you may use #if(count($details)) if true it will display info #else {{No data}} #endif
How to test specific validation errors in php unit thrown in validation error ?
with below code we could check session has errors, but not the exact error
$this->assertSessionHasErrors();
assertSessionHasErrors can receive an array, as documented:
$this->assertSessionHasErrors([
'field' => 'Field error message.'
]);
Got the answer
$errors = session('errors');
$this->assertSessionHasErrors();
$this->assertEquals($errors->get('name')[0],"Your error message for validation");
$errors is MessageBag object which stored in laravel session when validation error thrown
using $errors->get('name') you could see all the validation errors as an array
You may use the combination of assertStatus and assertJson
...
->assertStatus(422)
->assertJson([
'errors' => [
'field' => [
'Error message'
]
]
]);
You can use $response->assertSessionHasErrors('key')
https://laravel.com/docs/7.x/http-tests#assert-session-has-errors
an example for required attribute will be
$response = $this->json('POST', '/api/courses', $this->data([
'name' => '',
'api_token' => $this->user->api_token
]));
$response->assertSessionHasErrors('name');
You can add an extra assertion, to make sure that no entry was added to the database, in this case "assert no course was added"
$this->assertCount(0, Course::all());
For multiple required attributes you may use a loop something like the following:
collect(['name', 'description', 'amount'])->each(function ($field) {
$response = $this->json('POST', '/api/courses', $this->data([
$field => '',
'api_token' => $this->user->api_token
]));
$response->assertSessionHasErrors($field);
$this->assertCount(0, Course::all());
});
First I use
$this->post()
instead of
$this->jsonPost()
Dont know why, for certain reason, the session would not come out.
Then I just use
$response->assertSessionHasErrors('field_name', 'Error Message!');
To find out what are the error message, you must dump it
$response->dumpSession();
There is also a more elegant way in my opinion:
If you throw an exception via the class GeneralException you can check in a unit test if the session has a flash_danger from throwing a exception.
Lets do a practical example: We want to test that the admin cannot activate an already activated catalogue item.
Test function
public function an_admin_cannot_activate_an_activated_catalogue()
{
$catalogue = factory(Catalogue::class)->states('active')->create();
$response = $this->get("/admin/questionnaire/catalogue/{$catalogue->id}/activate");
$response->assertSessionHas(['flash_danger' => __('The catalogue item is already activated.')]);
}
Model/Repro function
If it is activated we throw an Exception which then can be checked by the test function.
public function activate(Catalogue $catalogue) : Catalogue
{
if ($catalogue->is_active) {
throw new GeneralException(__('The catalogue item is already activated.'));
}
$catalogue->is_active = 1;
$activated = $catalogue->save();
if($activated) {
return $catalogue;
}
}
actually you can easily throw errors from validation using dd() and session('errors')
since errors bag is stored in session you could add dd(session('errors')) in your unit tests to see which fields you are missing.
and finally you can write more proper test by adding $response->assertSessionHasErrors('field_name');
Laravel 7;
In my case, I needed to ensure there was no error.
But below did ignore form-validation errors (at least mine).
$response->assertSessionHasNoErrors();
Hence I created a custom assert function in base TestCase class, like:
use PHPUnit\Framework\Constraint\RegularExpression;
// ...
public static function assertNoErrorReport(TestResponse $response)
{
$error = static::getViewError($response);
if ( ! empty($error)) {
$this->fail('View contains error:' . PHP_EOL . $error);
}
$response->assertSessionHasNoErrors();
}
public function assertHasErrorRegExp(string $pattern, TestResponse $response, string $message = '')
{
$error = static::getViewError($response);
static::assertThat($error, new RegularExpression($pattern),
empty($message) ? $error : $message);
}
public static function getViewError(TestResponse $response)
{
$content = $response->getOriginalContent();
if ( ! $content) {
static::fail('View content missing.');
}
if ($content instanceof View) {
$data = $content->gatherData();
$error = $data['error'] ?? $data['errors'] ?? null;
// Casts array to string.
if (is_array($error)) {
$error = '[' . join(', ', $error) . ']';
}
// Casts Error-bag to string.
$error = '' . $error;
if ($error === '[]') {
return null;
}
} else {
static::fail('Response is not a View.');
}
return $data;
}
However, my assertHasErrorRegExp(...) could be used for OP's case.
I'm having trouble in deleting a record that has file in it. Below is the code.
delete file method :
private function deletePDF(Journal $journal) {
$exist = Storage::disk('file')->exists($journal->file);
if (isset($journal->file) && $exist) {
$delete = Storage::disk('file')->delete($journal->file);
if ($delete) {
return true;
}
return false;
}
}
Destroy method :
public function destroy(Journal $journal, EditionRequest $request) {
$this->deletePDF($journal);
$journal->delete();
return redirect()->route('edition', ['id' => $request->id]);
}
The result game me nothing, it's just return to the page where the record belongs and does not deleting the record. I used the same code for another project with the same laravel version and it's working, but for some reasons it doesn't work here and I'm a lil bit confused.
Update :
EditionRequest :
public function rules() {
// Cek apakah CREATE atau UPDATE
$id = $this->get('id');
if ($this->method() == 'PATCH') {
$volume_rules = 'required|integer|unique_with:edition,number,' . $id;
$number_rules = 'required|integer';
} else {
$volume_rules = 'required|integer|unique_with:edition,number';
$number_rules = 'required|integer';
}
return [
'volume' => $volume_rules,
'number' => $number_rules,
'cover' => 'sometimes|image|max:15000|mimes:jpeg,jpg,bmp,png',
];
}
If it returns to the same page as before, you probably have a validation error in your request!
You can check the errors easily by adding the following snippet to your view:
#if(count($errors) > 0)
<ul>
#foreach($errors->all() as $error)
<li>{{$error}}</li>
#endforeach
</ul>
#endif
With this you should be able to see what's going wrong. Let me know if it worked :)
edit
public function rules() {
// Cek apakah CREATE atau UPDATE
$id = $this->get('id');
if ($this->method() == 'PATCH') {
$volume_rules = 'required|integer|unique_with:edition,number,' . $id;
$number_rules = 'required|integer';
}
else if($this->method() == 'DELETE'){
//your delete validation rules rules
$volume_rules = ''
$number_rules= '';
}
else {
$volume_rules = 'required|integer|unique_with:edition,number';
$number_rules = 'required|integer';
}
return [
'volume' => $volume_rules,
'number' => $number_rules,
'cover' => 'sometimes|image|max:15000|mimes:jpeg,jpg,bmp,png',
];
}
You might even want to not use the request youre using now, which would give you this:
public function destroy(Journal $journal, Request $request)
i'm trying to use callback to simply to check my form input, the offical code is here: https://laravel.com/docs/5.2/validation
the following is my function
public function addthread(Request $request) {
$input = $request->all();
$rules = array('title' => 'required|unique:thread|max:255');
$message = array('title.required' => 'The :attribute field is aaa required.');
$validator = Validator::make($input, $rules, $message);
$validator->after(function($validator) {
if ($this->checkOpt()) {
$validator->errors()->add('num_opt', 'Something is wrong with this field!');
echo 'test';
}
});
if ($validator->fails()) {
return redirect('addthreadhtml')->withErrors($validator)->withInput();
}
}
public function checkOpt() {
return false;
}
the blade tpl:
#if (count($errors) > 0)
<div class="container" stytle="max-width:80%">
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
</div>
#endif
The num_opt error never print out, any idea?
checkOpt() is returning FALSE, so the code will never enter the if statment.
if ($this->checkOpt()) { // this is returning false, right ?? so, its not adding the error
$validator->errors()->add('num_opt', 'Something is wrong with this field!');
echo 'test';
}
Your checkOpt() always returns false, so your condition won't ever be satisfied.
I am trying to make a authentication system and the only issue that I am having is that it will not display the errors if the wrong creds are used. It shows the error when one of the fields is empty but not when they are both filled with wrong info. Can someone help me figure out what is wrong? Thanks for all the help!
Here is my view
{{ Form::open([
"route"=>"user/login",
"autocomplete"=>"off"
]) }}
{{ Form::label("username", "Username") }}
{{ Form::text("username", Input::old("username"), [
"placeholder"=>"Username"
]) }}
{{ Form::label("password", "Password") }}
{{ Form::password("password", [
"placeholder"=>"Password"
]) }}
#if($error = $errors->first("password"))
<div class="error">
{{ $error }}
</div>
#endif
{{ Form::submit("Login") }}
{{ Form::close() }}
here is the controller
<?php
use Illuminate\Support\MessageBag;
class UserController extends BaseController
{
public function loginAction()
{
$errors = new MessageBag();
if($old = Input::old("errors")) {
$errors = $old;
}
$data = [
"errors"=>$errors
];
if(Input::server("REQUEST_METHOD") == "POST") {
$validator = Validator::make(Input::all(), [
"username"=>"required",
"password"=>"required"
]);
if($validator->passes()) {
$credentials = [
"username"=>Input::get("username"),
"password"=>Input::get("password")
];
if(Auth::attempt($credentials)) {
//return Redirect::route("user/login");
echo "login success";
}
} else {
echo "Login failed";
$data["errors"] = new MessageBag([
"password"=>[
"Username and/or password invalid."
]
]);
$data["username"] = Input::get("username");
return Redirect::route("user/login")
->withInput($data);
}
}
return View::make("user/login", $data);
}
}
It looks like you are not displaying any message if the authentication fails. Auth::attempt() will try to match the username and password and if it fails it should add something to the errors array.
if(Auth::attempt($credentials)) {
//return Redirect::route("user/login");
echo "login success";
}
else // add this
{
echo 'login failed - username and/or password provided are not correct';
}
That said, you probably need to add an else statement here.