构建包安装程序
发布于 作者 TJ Miller
我认为我们大多数使用 Laravel 一段时间的人都很熟悉包安装流程:通过 Composer 添加包,注册服务提供者,发布配置文件,更新环境文件,希望你能记得更新 .env.example
,并且在完成所有操作后,你希望自己没有遗漏任何步骤。这通常涉及从 README
中复制粘贴,并在编辑器和浏览器之间来回切换。随着 Laravel 5.5 的发布,我们对这个流程有了很大的改进,引入了 包发现,但这并没有改变这个流程本身。
当我开始构建 Laravel 的 Honeybadger 集成时,我几乎从未见过 PHP 包的安装命令。我能想到的唯一一个命令是 Laravel Spark。当我们开始为集成概述功能时,Josh 建议构建一个类似于 Ruby gem 中的安装命令。我认为这是一个非常棒的想法,它将使安装流程更加顺畅。
我对添加此功能有一些非常具体的目标
- 显示所有执行的任务(成功和失败)
- 尽可能避免手动操作
- 使用命令提示符获取任何所需的信息
- 兼容 Laravel 和 Lumen
可见性
我真的不希望这个安装程序只是在后台运行,修改你的许多文件,然后只是返回一个消息说一切都很成功。我也不会希望输出过于冗长。
我偶然发现了 Nuno Maduro 的一个很棒的包 nunomaduro/laravel-console-task。我真的很喜欢它简单的 API 和漂亮的输出。然而,它在 Lumen 中运行时遇到了一些问题,所以我编写了一个简单的类来收集任务名称和结果状态。
<?php namespace Honeybadger\HoneybadgerLaravel; use Illuminate\Console\OutputStyle; class CommandTasks{ /** * @var \Illuminate\Console\OutputStyle */ protected $output; /** * @var array */ protected $results = []; /** * Set command output. * * @param \Illuminate\Console\OutputStyle $output * @return self */ public function setOutput(OutputStyle $output) : self { $this->output = $output; return $this; } /** * Add task with result to the stack. * * @param string $name * @param bool $result * @return self */ public function addTask(string $name, bool $result) : self { $this->results[$name] = $result; return $this; } /** * Send results to the command output. * * @return void */ public function outputResults() : void { collect($this->results)->each(function ($result, $description) { $this->output->writeLn(vsprintf('%s: %s', [ $description, $result ? '<fg=green>✔</>' : '<fg=red>✘</>', ])); }); } /** * Get the results of all tasks. * * @return array */ public function getResults() : array { return $this->results; }}
它保持了简单的 API 和漂亮的输出
$this->tasks->addTask( 'Write HONEYBADGER_API_KEY to .env', $this->installer->writeConfig( ['HONEYBADGER_API_KEY' => $this->config['api_key']], base_path('.env') ));
避免手动操作
使用安装程序的目的是使安装流程快速、简单且愉快。我发现安装新包最大的痛点之一是更新 .env
文件和 .env.example
文件。
我最终编写了一个非常轻量级的包来完成这项工作,即 sixlive/dotenv-editor。
public function writeConfig(array $config, string $filePath) : bool{ try { $env = new DotenvEditor; $env->load($filePath); } catch (InvalidArgumentException $e) { return false; } collect($config)->each(function ($value, $key) use ($env) { $env->set($key, $value); }); return $env->save();}
然后我们可以使用该方法写入这两个环境文件。我们将在 .env.example
文件中写入一个空值,并将通过命令输入收集的 API 写入 .env
文件
private function writeEnv() : void{ $this->tasks->addTask( 'Write HONEYBADGER_API_KEY to .env', $this->installer->writeConfig( ['HONEYBADGER_API_KEY' => $this->config['api_key']], base_path('.env') ) ); $this->tasks->addTask( 'Write HONEYBADGER_API_KEY placeholder to .env.example', $this->installer->writeConfig( ['HONEYBADGER_API_KEY' => ''], base_path('.env.example') ) );}
我还想为 Laravel 和 Lumen 发布配置文件。使用 Laravel 非常简单,你可以调用 vendor:publish
命令。
public function publishLaravelConfig() : bool{ return Artisan::call('vendor:publish', [ '--provider' => HoneybadgerServiceProvider::class, ]) === 0;}
Lumen 则有点棘手,因为它缺少 Laravel 附带的许多命令。
public function publishLumenConfig(string $stubPath = null): bool{ if (! is_dir(base_path('config'))) { mkdir(base_path('config')); } return copy( $stubPath ?? __DIR__.'/../config/honeybadger.php', base_path('config/honeybadger.php') );}
在所有配置就位之后,我们需要向 Honeybadger 发送一个测试异常。这样做是为了确保所有配置和安装步骤都正确完成。
提示配置值
在执行任何安装任务之前,我们首先要收集所有配置值,以便我们可以一步完成所有安装操作。
public function handle(){ $this->config = $this->gatherConfig();} private function gatherConfig() : array{ return [ 'api_key' => $this->argument('apiKey') ?? $this->promptForApiKey(), 'send_test' => $this->confirm('Would you like to send a test exception now?', true), ];} private function promptForApiKey() : string{ return $this->requiredSecret('Your API key', 'The API key is required');}
Laravel 使我们能够非常轻松地直接将所有配置值提示到一个关联数组中。这使得在整个命令中引用这些值变得超级简单。
我需要确保 API 密钥是必需的。我编写了一个非常简单的函数,它会持续提示输入 API,直到输入为止。
trait RequiredInput{ public function requiredSecret($question, $failedMessage) { $input = $this->secret($question); if (is_null($input)) { $this->error($failedMessage); return $this->requiredSecret($question, $failedMessage); } return $input; }
总结
Honeybadger 团队非常努力地提供流畅、精致、愉快的端到端体验,我认为这与 Laravel 的一些核心原则完美契合。我认为,通过为包使用安装程序,它将这种体验从他们的应用程序带到了你的终端。我们正在对安装程序进行最后的润色,它将很快加入到 honeybadger-io/honeybadger-laravel 库中。你可以关注此处的 pull 请求 honeybadger-io/honeybadger-laravel/#11。同时,Honeybadger 仍然非常容易上手。