本书未发布

Artisan 命令

未匹配的标注

Laravel 附带了一个 PHP 可执行的 artisan 文件,为框架提供了一个命令行界面文件。 通过这个 CLI,您可以访问像php artisan migratephp artisan make:model Post这样的命令。 你可以用命令做很多事情。 请务必阅读Laravel 文档中的artisan控制台。

假设我们想为我们的终端用户提供一个简单的 artisan 命令,通过:  php artisan blogpackage:install 发布配置文件。

创建一个新命令

src/ 目录中创建一个新的 Console 文件夹,并创建一个名为 InstallBlogPackage.php 的新文件。 这个类将继承 Laravel 的 Command 类,并提供 $signature (命令)和 $description 属性。 在 handle()方法中,我们指定命令将执行的操作。 在这种情况下,我们提供了一些反馈,说明我们正在“安装”这个包,并且我们将调用另一个 artisan 命令来发布配置文件。 最后,我们让用户知道我们完成了。

// 'src/Console/InstallBlogPackage.php'
<?php

namespace JohnDoe\BlogPackage\Console;

use Illuminate\Console\Command;

class InstallBlogPackage extends Command
{
    protected $signature = 'blogpackage:install';

    protected $description = 'Install the BlogPackage';

    public function handle()
    {
        $this->info('Installing BlogPackage...');

        $this->info('Publishing configuration...');

        $this->call('vendor:publish', [
            '--provider' => "JohnDoe\BlogPackage\BlogPackageServiceProvider",
            '--tag' => "config"
        ]);

        $this->info('Installed BlogPackage');
    }
}

在服务提供者中注册该命令

我们需要向最终用户展示这个包的功能,从而在扩展包的服务提供者中注册它。

因为我们只想从命令行提供这个功能,所以我们将它添加到 if-runningInConsole()-语句中(不要忘记导入类) :

// 'BlogPackageServiceProvider.php'
use JohnDoe\BlogPackage\Console\InstallBlogPackage;

public function boot()
{
  if ($this->app->runningInConsole()) {
    // publish config file

    $this->commands([
        InstallBlogPackage::class,
    ]);
  }
}

测试 artisan 命令

为了测试我们的命令是否有效,让我们在 Unit test 文件夹中创建一个名为 InstallBlogPackageTest.php 的新单元测试。

由于我们使用 Orchestra Testbench,我们在 config path()处有一个 config 文件夹,其中包含普通 Laravel 安装程序可能拥有的每个文件。 (你可以使用dd(config_path())检查这个目录的位置)。 因此,我们可以很容易地断言这个目录在运行我们的 artisan 命令之后应该有我们的blogpackage.php配置文件。 为了确保我们从一个干净的状态开始,让我们首先删除所有上次测试产生的配置文件。

// 'tests/Unit/InstallBlogPackageTest.php'
<?php

namespace JohnDoe\BlogPackage\Tests\Unit;

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use JohnDoe\BlogPackage\Tests\TestCase;

class InstallBlogPackageTest extends TestCase
{
    /** @test */
    function the_install_command_copies_a_the_configuration()
    {
        // make sure we're starting from a clean state
        if (File::exists(config_path('blogpackage.php'))) {
            unlink(config_path('blogpackage.php'));
        }

        $this->assertFalse(File::exists(config_path('blogpackage.php')));

        Artisan::call('blogpackage:install');

        $this->assertTrue(File::exists(config_path('blogpackage.php')));
    }
}

隐藏命令

在某些情况下,您可能希望将该命令从 Artisan 命令列表中排除。您可以在命令类上定义 $ hidden 属性,该属性不会在 Artisan 命令列表中显示特定命令。但是请注意,该命令仍然可以使用,只是被隐藏。

class InstallBlogPackage extends Command
{
    protected $hidden = true;

    protected $signature = 'blogpackage:install';

    protected $description = 'Install the BlogPackage';

    public function handle()
    {
        // ...
    }
}

创建生成器命令

Laravel 提供了一种简单的方法来创建 Generator 命令,即具有签名的命令,例如 php artisan make:controller 之类的命令。这些命令将通用的预定义模板 (stub) 修改为特定的应用程序。例如,通过自动注入正确的命名空间。

为了创建一个 Generator 命令,您必须扩展 Illuminate\Console\GeneratorCommand 类,并覆盖以下属性和方法:

  • protected $name: 命令的名称
  • protected $description: 命令说明
  • protected $type: 命令生成类的类型
  • protected function getStub(): 返回 stub 模板文件路径的方法
  • protected function getDefaultNamespace($rootNamespace): 所生成类的默认命名空间
  • public function handle(): 命令的主体

GeneratorCommand 基类提供了一些辅助方法:

  • getNameInput(): 返回从命令行执行传递的参数
  • qualifyClass(string $name): 返回给定参数的验证后类名
  • getPath(string $name): 返回给定参数的文件路径

考虑以下 php artisan make:foo MyFoo 命令的示例:

<?php

namespace JohnDoe\BlogPackage\Console;

use Illuminate\Console\GeneratorCommand;

class MakeFooCommand extends GeneratorCommand
{
    protected $name = 'make:foo';

    protected $description = 'Create a new foo class';

    protected $type = 'Foo';

    protected function getStub()
    {
        return __DIR__ . '/stubs/foo.php.stub';
    }

    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace . '\Foo';
    }

    public function handle()
    {
        parent::handle();

        $this->doOtherOperations();
    }

    protected function doOtherOperations()
    {
        // Get the fully qualified class name (FQN)
        $class = $this->qualifyClass($this->getNameInput());

        // get the destination path, based on the default namespace
        $path = $this->getPath($class);

        $content = file_get_contents($path);

        // Update the file content with additional data (regular expressions)

        file_put_contents($path, $content);
    }
}

请注意,该类将根据 getDefaultNamespace() 方法中指定的名称空间导出到目录

创建 stub

您可以将 stub 存储在其他目录中,但是现在考虑将存根存储在Console\stub目录中。对于我们的 Foo 类生成器,存根可能如下所示:

// 'stubs/foo.php.stub'
<?php

namespace DummyNamespace;

use JohnDoe\BlogPackage\Foo;

class DummyClass implements Foo
{
    public function myFoo()
    {
        // foo
    }
}

请注意,DummyNamespaceDummyClass 是占位符(在 GeneratorCommand 基类中严格定义:Laravel 希望这些特定名称被替换)并自动用正确的值替换。

测试生成器命令

我们可以在 tests / Feature 目录中为该命令添加功能测试,称为 MakeFooCommandTest.php,它可以验证是否创建了新文件并包含正确的内容:

<?php

namespace JohnDoe\BlogPackage\Tests\Feature;

use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
use JohnDoe\BlogPackage\Tests\TestCase;

class MakeFooCommandTest extends TestCase
{
    /** @测试 */
    function it_creates_a_new_foo_class()
    {
        // Foo类的目标路径
        $fooClass = app_path('Foo/MyFooClass.php');

        // 确保我们从清空状态开始
        if (File::exists($fooClass)) {
            unlink($fooClass);
        }

        $this->assertFalse(File::exists($fooClass));

        // 运行make命令
        Artisan::call('make:foo MyFooClass');

        // 声明一个新文件已创建
        $this->assertTrue(File::exists($fooClass));

        // 声明文件包含正确的内容
        $expectedContents = <<<CLASS
<?php

namespace App\Foo;

use JohnDoe\BlogPackage\Foo;

class MyFooClass implements Foo
{
    public function myFoo()
    {
        // foo
    }
}
CLASS;

        $this->assertEquals($expectedContents, file_get_contents($fooClass));
    }
}

创建仅测试命令

在某些情况下,您只想使用某个命令进行测试,而不在应用程序本身中使用。例如,当您的程序包提供 Command 类可以使用的 Trait 时。要测试,您想使用实际命令进行测试。

该命令本身不会向软件包添加功能,因此不应发布。但是,仅从服务提供商中排除命令并不是解决方案,因为您希望能够在测试中运行该命令。

优雅的解决方案 suggested by Marcel Pociot 是通过在 Laravel 的 Application::starting() 命令中加入钩子,从而 在测试中注册该命令:

<?php

namespace JohnDoe\BlogPackage\Tests\Feature;

use JohnDoe\BlogPackage\Tests\Commands\TestCommand;
use Illuminate\Console\Application;
use Illuminate\Support\Facades\Artisan;
use Orchestra\Testbench\TestCase;

class TestCommandTest extends TestCase
{
   /** @test **/
   public function it_does_a_certain_thing()
   {
        Application::starting(function ($artisan) {
            $artisan->add(app(TestCommand::class));
        });

        // Running the command 
        Artisan::call('test-command:run');

       // assertions...
   }
}

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/laravel-package...

译文地址:https://learnku.com/docs/laravel-package...

上一篇 下一篇
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
贡献者:2
讨论数量: 0
发起讨论 只看当前版本


暂无话题~