【问题标题】:Method render() is not being called when custom Laravel exception is thrown from view composer从视图编写器抛出自定义 Laravel 异常时,未调用方法 render()
【发布时间】:2019-12-23 16:50:59
【问题描述】:

已编辑: 我有一个带有渲染方法的自定义异常,当我抛出它时会调用它,例如来自控制器,但当我将它扔到 View Composer 中时不会被调用。

所以当我做这样的事情时

public function compose(View $view)
{
    throw new CustomException();
}

并将 dd() 放到异常渲染方法中

public function render()
{
    dd('render is called');
}

我没有得到任何结果。

如果我直接记录我的异常,首先会发现引发了 CustomException,然后结果我看到了 ErrorException。

我找到了一个扔掉它的地方。

\Illuminate\View\Engines\CompilerEngine::handleViewException

protected function handleViewException(Exception $e, $obLevel)
{
    $e = new ErrorException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e);

    parent::handleViewException($e, $obLevel);
}

我在 Laravel 文档中没有发现任何关于该案例的提及。 我在 github 上发现了同样的问题:https://github.com/laravel/framework/issues/24658

所以问题是,这是预期的吗?有没有足够的方法来避免这种行为?

【问题讨论】:

  • 所以你访问$model->foo 会发生什么?
  • @lagbox 如果我直接记录我的异常,发现首先抛出了 CustomException,然后结果我看到了 ErrorException。我不太熟悉 Pipeline 中的逻辑,但不知何故,它从会话中获取了先前的自定义异常,然后用 ErrorException 覆盖它。 ErrorException 正在由 Handler 处理。请随时提出更具体的问题,以便我分享必要的信息。
  • 视图渲染中的异常被捕获,并且永远不会按原样到达处理程序。他们被拦截。 Laravel 这样做是为了提供正确的错误报告(报告刀片中的错误,而不是 /storage/framework/views/xx.php 文件中编译的 php 文件)
  • @N69S 我明白了。我试图稍微改变 CompilerEngine 的行为,以便在我需要应用我的处理时不捕获某些类型的异常。听起来不是很好,但在我的需求范围内我没有看到任何其他方式。我想抛出其他异常(比如说 ViewCustomException)而不是 ErrorException(请参阅我在问题中提到的 CompilerEngine 的代码),它会导致多个抛出的 ViewCustomException 异常。如果您知道 Laravel View 渲染中应用的逻辑,请您告知为什么会发生这种情况?
  • 在我的回答中为您提供了解决方案@mom__66

标签: laravel exception eloquent


【解决方案1】:

编辑

因此,如您所知,视图编译期间的任何异常都会被拦截并重新抛出为ErrorExceptionFatalThrowableError

您可以做的是拦截ErrorException 并检查if ($e->getPrevious() instanceof \CustomException),如果是,则执行您的代码,否则,让处理程序继续。

【讨论】:

  • 感谢您的建议,但仍然没有运气。似乎也没有调用 Handler 中的方法 render()。
  • 这不会一直有效。我在 cmets 中描述的行为表明 ErrorException 的父级将是 ErrorException。我不知道它到底是怎么发生的,但每次都会出现多次\Illuminate\View\Engines\CompilerEngine::handleViewException 和ErrorException(当然第一次除外),所以最终父级将是ErrorException。实际上我不确定它是否仍然容易理解......也许我需要结束这个问题。
  • 你唯一干净的解决方案是不在渲染管道中抛出异常,而是在控制器中预先抛出异常(这是最佳实践)
  • 在我的情况下这是不可能的。我还需要全局处理(正如 Handler 提供的那样)。我已经发布了适合我的最终解决方案 - @N69S
【解决方案2】:

所以我找到了适合自己的解决方案。 我扩展了 CompilerEngine 并添加了额外的处理,以便在我不想时不抛出 ErrorException。 重要的是 - 您生成的异常必须从 ErrorException 继承。否则,您将面临多次调用\App\View\Engines\CompilerEngine::handleViewException,这可能会破坏您的逻辑并将多个日志实体写入您的日志文件。

【讨论】:

  • 你修改了核心 laravel 文件?
  • @N69S 不,我已经创建了自定义 ViewServiceProvider 并在那里注册了我的扩展 CompilerEngine。我没有完全删除 ErrorException 逻辑,只是为我的异常添加了额外的处理以不破坏核心逻辑。
猜你喜欢
  • 1970-01-01
  • 2021-11-05
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 1970-01-01
  • 2019-06-02
  • 2011-10-06
相关资源
最近更新 更多