如何巧妙地处理Artisan命令中的例外

问题描述:

使用Lumen创建一个API--爱Laravel,但所有与View一起的View对于我创建的项目来说都是过度的。如何巧妙地处理Artisan命令中的例外

无论如何,我已经做出了一系列命令,它们出去收集数据并将其存储到数据库中。

<?php 

namespace App\Console\Commands; 

use Illuminate\Console\Command; 
use Symfony\Component\Console\Input\InputOption; 

use App\User; 

class GetItems extends Command { 

    /** 
    * The console command name. 
    * 
    * @var string 
    */ 
    protected $name = 'GetItems'; 

    /** 
    * The console command description. 
    * 
    * @var string 
    */ 
    protected $description = "Get items and store it into the Database"; 

    /** 
    * Execute the console command. 
    * 
    * @return void 
    */ 
    public function fire() 
    { 
     $this->info("Collecting ..."); 

     $users = User::all(); 

     foreach($users as $user) 
     { 
      $user->getItems(); 
     } 

    } 

    /** 
    * Get the console command options. 
    * 
    * @return array 
    */ 
    protected function getOptions() 
    { 
     return []; 
    } 

} 

我有3个类似的命令,每一个都收集稍微不同的数据集。

有没有一种方法可以注入一个中间层,捕获来自我的命令中每个fire()函数的异常?我正在考虑扩展Command类 - 但是想看看框架创建者是否已经有一种方法可以实现推荐(文档/搜索没有帮助)。

我知道替代方法是将所有命令组合成一个文件并使用选项,但是这使得它很难与之协作。

有什么建议吗?

+0

你尝试使用'尝试{}赶上(\例外$ E){}'内' - > fire()'方法?你得到的错误是什么?那个异常来自哪里? – ljubadr

+0

@ljubadr是的,只能在该类中工作,但因为我有许多类似的类,所以我必须重复try {} catch块。我觉得将一个异常向上堆栈并将其捕获到堆栈中'fire()'被调用 – Moe

答案取决于我们希望应用程序在命令引发异常时执行的操作。这个问题没有描述处理异常的理想方式,所以我们来看几个选项。

Laravel和Lumen项目包括一个中心例外Handler类,我们可以使用它来定义不同例外的行为。该类处理从Web请求和控制台命令冒出的任何异常。

Laravel使用report()方法中的 app/Exceptions/Handler.php来确定如何记录异常。我们可以在这里添加逻辑错误报告:

public function report(Exception $e) 
{ 
    if ($e instanceof CustomConsoleException) { 
     // do something specific... 
    } 
    ... 
} 

renderForConsole()方法让我们定制,我们要如何显示控制台命令的错误和异常消息。该项目的异常Handler通常不包含此方法定义,但如果需要,我们可以在应用程序/例外/ Handler.php覆盖它:

public function renderForConsole($output, Exception $e) 
{ 
    $output->writeln('Something broke!'); 

    (new ConsoleApplication)->renderException($e, $output); 
} 

在上面的例子中,$output是一个Symfony\Component\Console\Output \OutputInterface参考对象,我们可以使用它将文本写入控制台命令的输出流。

正如我们从上面可以猜到的那样,*异常处理程序被设计用于处理我们的代码在较低级别处理未捕获的异常,所以当我们需要在异常后执行某些特定操作时,它并不是非常有用。以类似的方式,我们可以覆盖app/Console/Kernel.php中的reportException()renderException()方法。

如果我们需要做一些具体的事情,除了只承认一个命令通过显示一条消息来抛出一个异常,我们实际上应该把这个逻辑写入命令本身。为了避免重复的代码,我们可以使用一个抽象类,这三个类似的命令为提供具体实现:

abstract class AbstractGetItems extends Command 
{ 
    ... 
    final public function fire() 
    { 
     try { 
      $this->getItems(); 
     } catch (Exception $e) { 
      // handle exception... 
     } 
    } 

    abstract protected function getItems(); 
} 

这个抽象命令强制子类来实现getItems()方法,它的类fire()自动调用。我们可以添加任何其他共享逻辑到这个类。子命令只需要定义自己的具体实施getItems(),和父类将处理异常为他们:

class GetSpecificItems extends AbstractGetItems 
{ 
    ... 
    protected function getItems() 
    { 
     // fetch specific items... 
    } 
} 
+0

感谢这个Cy。它使感官。这是否也适用于流明中的Artisan命令? – Moe

+1

@莫 - 不客气!是的,这个答案中的信息也适用于流明。 –

+0

我想我想处理命令级别的异常给我发送一封包含调试信息的电子邮件 – Moe