Reputation: 7278
I am looking for something which can be like findOrDo(). Like do this when data not found. Something could be like
Model::findOrDo($id,function(){
return "Data not found";
});
Is there any similar thing in laravel that I can do this elegantly and beautifully ?
*I tried googling but could not find one
Upvotes: 15
Views: 61087
Reputation: 1795
In the newer version of Laravel (for me in v9.41.0) we have the Register method in Handler.php ,
so for customize the exception of findOrFail method we have to add this code to that file:
$this->renderable(function (NotFoundHttpException $exception, $request) {
if ($request->expectsJson()) {
//when you need it for API
return response()->json([
'responseCode'=> 404,
'message' => "Item not found",
'errorCode' => 1000404
], 404 );
}else{
return view("some-custom-view");
}
});
I needed NotFoundHttpException which has the namespace below (you can use any other Exception for customization) and have to be used out of the class:
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Upvotes: 1
Reputation: 1756
A little later for the party, from laravel 5.4 onward, Eloquent Builder supports macros. So, I would write a macro (in a separate provider) like follows.
Builder::macro('firstOrElse', function($callback) {
$res = $this->get();
if($res->isEmpty()) {
$callback->call($this);
}
return $res->first();
});
I can then do a retrieval as follows.
$firstMatchingStudent = DB::table('students')->where('name', $name)
->firstOrElse(function() use ($name) {
throw new ModelNotFoundException("No student was found by the name $name");
});
This will assign the first object of the result set if it is not empty, otherwise will adapt the behaviour I pass into the macro as a closure (throw Illuminate\Database\Eloquent\ModelNotFoundException
in this case).
For the case of a model also this would work, except that models always return the builder instance.
Upvotes: 1
Reputation: 1871
use Illuminate\Database\Eloquent\ModelNotFoundException;
// Will return a ModelNotFoundException if no user with that id
try
{
$user = User::findOrFail($id);
}
// catch(Exception $e) catch any exception
catch(ModelNotFoundException $e)
{
dd(get_class_methods($e)); // lists all available methods for exception object
dd($e);
}
Upvotes: 45
Reputation: 2663
as of Laravel v5.7, you can do this (the retrieving single model variation of @thewizardguy answer)
// $model will be null if not found
$model = Model::where('id', $id)->first();
if($model) {
doActions();
}
Upvotes: 2
Reputation: 31
An alternative process could be to evaluate a collection instead. So,
$modelCollection = Model::where('id', $id)->get();
if(!$modelCollection->isEmpty()) {
doActions();
}
I agree it isn't as elegant, a one-liner or as case specific as you or I might like, but aside from writing a try catch statement every time, it's a nice alternative.
Upvotes: 3
Reputation: 333
By default, when you use an Eloquent model’s findOrFail
in a Laravel 5 application and it fails, it returns the following error:
ModelNotFoundException in Builder.php line 129:
'No query results for model [App\Model]'.
So to catch the exception and display a custom 404 page with your error message like "Ooops"....
Open up the app/Exceptions/Handler.php
file, and add the code shown below to the top of the render function:
public function render($request, Exception $e)
{
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException)
{
abort(404, 'Oops...Not found!');
}
return parent::render($request, $e);
}
Upvotes: 5
Reputation: 7556
Another option is to modify the default Laravel Exception Handler, found in app/Exceptions/Handler.php on the render()
function I made this change:
public function render($request, Exception $e)
{
if(get_class($e) == "Illuminate\Database\Eloquent\ModelNotFoundException") {
return (new Response('Model not found', 400));
}
return parent::render($request, $e);
}
That way instead of getting a 500, I send back a 400 with a custom message without having to do a try catch on every single findOrFail()
Upvotes: 10