Laravel 5:如何使用findOrFail()方法?

7

我只是跟着一些教程学习,目前我所做的是:

我的 App/Exceptions/Handler.php

<?php
...
use Illuminate\Database\Eloquent\ModelNotFoundException;
...
public function render($request, Exception $e)
{
    if ($e instanceof ModelNotFoundException){
        abort(404);
    }
        return parent::render($request, $e);
}

我的UsersController看起来像这样:
...
public function edit($id)
{
    $data = User::findOrFail($id);
    $roles = Role::where('title', '!=', 'Super Admin')->get();
    return View('admin.user.edit', compact(['data', 'roles']));
}
...

使用以上代码,如果我访问http://my.url/users/10/edit ,我得到了NotFoundHttpException in Application.php line 901:错误,这是因为我的记录中没有id为10,但是使用User::find($id);语句,我会得到一个没有数据的正常视图,因为我的记录中没有id为10。
我想要的是显示默认的404页面,然后在记录无法找到时重定向到某个地方或返回一些内容,应该如何使用User::findOrFail($id);来实现?我该怎么做?
非常感谢,任何帮助都将不胜感激。ps:.env APP_DEBUG = true

尝试{} 捕获(Exception $e) {} - mercury
4个回答

24

这做了你要求的事情。不需要例外。

public function edit($id)
{
    $data = User::find($id);
    if ($data == null) {
        // User not found, show 404 or whatever you want to do
        // example:
        return View('admin.user.notFound', [], 404);
    } else {
        $roles = Role::where('title', '!=', 'Super Admin')->get();
        return View('admin.user.edit', compact(['data', 'roles']));
    }
}

关于Illuminate\Database\Eloquent\ModelNotFoundException,你的异常处理程序并不必要。

如果未捕获此异常,则会自动向用户发送404 HTTP响应,因此在使用[findOrFail()]时不需要编写显式检查以返回404响应。

此外,我相信您现在因为处于调试模式而获得异常页面而非404。


9
public function singleUser($id)
{
    try {
        $user= User::FindOrFail($id);
        return response()->json(['user'=>user], 200);
    } catch (\Exception $e) {
        return response()->json(['message'=>'user not found!'], 404);
    }
}

1
虽然这可能有所帮助,请考虑在您的答案中添加解释。 - Keshu R.
FindOrFail 如果请求找到结果成功为true,则可以显示响应,否则默认响应404。 - Iklan Hits

6

findOrFail()函数类似于find()函数,但多了一个功能——抛出“未找到”异常。

有时候,如果没有找到模型,您可能希望抛出异常。这在路由或控制器中特别有用。但是,findOrFailfirstOrFail方法将检索查询的第一个结果;如果没有找到结果,则会抛出Illuminate\Database\Eloquent\ModelNotFoundException异常:

$model = App\Flight::findOrFail(1);

$model = App\Flight::where('legs', '>', 100)->firstOrFail();

如果异常未被捕获,将自动向用户发送404 HTTP响应。使用这些方法时,无需编写显式检查以返回404响应:

Route::get('/api/flights/{id}', function ($id) {
    return App\Flight::findOrFail($id);
});

虽然不建议这样做,但如果您仍然希望全局处理此异常,则根据您的handle.php文件进行以下更改:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)
{
    if ($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {

        //redirect to errors.custom view page 
        return response()->view('errors.custom', [], 404);
    }

    return parent::render($request, $exception);
}

1
上面话题的后续补充:如果您想处理API后端的异常,并且不想在每个方法中检查空结果并单独返回400错误请求,请按如下方式操作...
public function open($ingredient_id){
    $ingredient = Ingredient::find($ingredient_id);
    if(!$ingredient){
        return response()->json(['error' => 1, 'message' => 'Unable to find Ingredient with ID '. $ingredient_id], 400);
    }
    return $ingredient;
}

请使用findOrFail并在app/Exceptions/Handler.php中捕获异常。

public function render($request, Exception $exception)
{
    if ($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
        return response()->json(['error'=>1,'message'=> 'ModelNotFoundException handled for API' ], 400);
    }
    return parent::render($request, $exception);
}

这样,在您的控制器中,它将会是这个样子:
public function open($ingredient_id){
    return Ingredient::findOrFail($ingredient_id);
}  

这更加清晰。考虑到你有大量的模型和控制器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接