如何巧妙地处理工匠命令中的异常

时间:2017-10-18 22:00:51

标签: php laravel lumen artisan

使用Lumen创建一个API - 喜欢Laravel,但是随之而来的所有View都对我正在创建的项目来说太过分了。

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

<?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类 - 但是想看看框架创建者是否已经有办法实现推荐(文档/搜索没有帮助)。

我知道另一种方法是将所有命令合并到一个文件中并使用选项,但这会使它变得混乱而且难以与之协作。

有什么建议吗?

1 个答案:

答案 0 :(得分:5)

答案取决于我们希望应用程序在命令抛出异常时执行的操作。问题没有描述处理异常的理想方法,所以让我们看一些选项。

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

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

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

renderForConsole()方法允许我们自定义我们希望如何显示控制台命令的错误和异常消息。项目的异常Handler通常不包含此方法定义,但如果需要,我们可以在 app / Exceptions / Handler.php 中覆盖它:

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

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

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

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

如果我们需要做一些具体的事情,除了承认命令通过显示消息引发异常之外,我们真的应该在命令本身中编写这个逻辑。为了避免重复的代码,我们可以使用 abstract 类,这三个类似的命令提供了具体的实现:

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...
    }
}