symfony 控制器

tech2022-08-28  114

symfony 控制器

This article was peer reviewed by Wern Ancheta. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

本文由Wern Ancheta进行同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!



It’s undeniable how useful console commands can be when developing software. Not too long ago we re-introduced the Symfony Console component.

不可否认,开发软件时控制台命令有多有用。 不久之前,我们重新引入了Symfony Console组件 。

This component allows us to create structured and testable CLI commands. We created some simple commands and tested them; but when our commands become bigger and more complex, we need a different set of tools.

该组件使我们可以创建结构化且可测试的CLI命令。 我们创建了一些简单的命令并对其进行了测试; 但是当我们的命令变得越来越大,越来越复杂时,我们需要一套不同的工具。

This is what we are going to look at today: advanced Symfony console tools.

这就是我们今天要看的:高级Symfony控制台工具。

Let’s create a command that we can use to show some of these features. Most of the basic functionality was shown in the re-introduction to the Symfony console article, so be sure to check it before advancing – it’s a quick but useful read!

让我们创建一个可用来显示其中一些功能的命令。 Symfony控制台文章的重新介绍中显示了大多数基本功能,因此请务必在进行升级之前对其进行检查-这是快速但有用的阅读!

安装 (Installation)

composer require symfony/console

Essential information about Composer can be found here, and if you’re not familiar with well designed isolated PHP environments in which to develop your PHP apps like Vagrant, we have a fantastic book explaining it all in depth available for purchase here.

关于作曲家基本信息,可以发现在这里 ,如果你不熟悉其开发PHP应用程序,如精心设计的隔离PHP环境流浪 ,我们有一个梦幻般的书,介绍它在所有可购买深度这里 。

创建我们的命令 (Creating our command)

Let’s create a command for an all time favorite: Fizzbuzz.

让我们为一直以来喜欢的命令创建一个命令:Fizzbuzz。

Fizzbuzz is a simple problem often used in programming interviews to assert the programming competence of the interviewee. The definition of Fizzbuzz normally comes in the following form:

Fizzbuzz是一个简单的问题,通常在编程访谈中用来确定受访者的编程能力。 Fizzbuzz的定义通常以以下形式出现:

Write a program that prints the numbers from 1 to x. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five, print “FizzBuzz”.

编写一个程序,打印从1到x的数字。 但是,对于三倍打印“ Fizz”而不是数字,对于五倍打印“ Buzz”。 对于三和五的倍数的数字,请打印“ FizzBu​​zz”。

Our command will receive an argument which will be the top limit for Fizzbuzz.

我们的命令将收到一个参数,该参数将是Fizzbuzz的最高限制。

First of all, let’s create our Fizzbuzz class.

首先,让我们创建Fizzbuzz类。

<?php declare(strict_types=1); namespace FizzBuzz; class Fizzbuzz{ public function isFizz(int $value): bool{ if($value % 3 === 0){ return true; } return false; } public function isBuzz(int $value): bool{ if($value % 5 === 0){ return true; } return false; } public function calculateFizzBuzz(int $number): bool{ if($this->isFizz($number) && $this->isBuzz($number)){ echo "FizzBuzz \n"; return true; } if($this->isFizz($number)){ echo "Fizz \n"; return true; } if($this->isBuzz($number)){ echo "Buzz \n"; return true; } echo $number . "\n"; return true; } public function firstNFizzbuzz(int $maxValue): void{ $startValue = 1; while($startValue <= $maxValue){ $this->calculateFizzBuzz($startValue); $startValue++; } } }

Pretty straightforward. The firstNFizzbuzz() method prints the results of Fizzbuzz for a $maxValue of numbers. It does this by calling the calculateFizzBuzz() method recursively.

非常简单。 firstNFizzbuzz()方法为$maxValue数字打印Fizzbuzz的结果。 它通过递归调用calculateFizzBuzz()方法来实现。

Next, let’s write our command. Create a FizzCommand.php file with the following contents:

接下来,让我们编写命令。 创建具有以下内容的FizzCommand.php文件:

<?php namespace FizzBuzz; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use FizzBuzz\Fizzbuzz; class FizzCommand extends Command{ protected function configure(){ $this->setName("FizzBuzz:FizzBuzz") ->setDescription("Runs Fizzbuzz") ->addArgument('Limit', InputArgument::REQUIRED, 'What is the limit you wish for Fizzbuzz?'); } protected function execute(InputInterface $input, OutputInterface $output){ $fizzy = new FizzBuzz(); $input = $input->getArgument('Limit'); $result = $fizzy->firstNFizzbuzz($input); } }

And finally our console file.

最后是我们的console文件。

#!/usr/bin/env php <?php require_once __DIR__ . '/vendor/autoload.php'; use Symfony\Component\Console\Application; use FizzBuzz\FizzCommand; $app = new Application(); $app->add(new FizzCommand()); $app->run();

Here we create a new Console Application and register our FizzCommand() into it. Don’t forget to make this file executable.

在这里,我们创建一个新的控制台应用程序并将其FizzCommand()注册到其中。 不要忘记使该文件可执行。

We can now check if our command is correctly registered by running the ./console command. We can also execute our command with ./console FizzBuzz:Fizzbuzz 25. This will calculate and print the Fizzbuzz results from 1 to 25.

现在,我们可以通过运行./console命令来检查我们的命令是否正确注册。 我们还可以使用./console FizzBuzz:Fizzbuzz 25执行命令。 这将从1到25计算并打印Fizzbuzz结果。

Up until now, we haven’t done anything new. But there are a couple of ways we can improve our command. First of all, the command is not very intuitive. How do we know that we have to pass the limit to the command? For that, the Symfony Console offers us the Question helper.

到目前为止,我们还没有做任何新的事情。 但是,有两种方法可以改善我们的命令。 首先,命令不是很直观。 我们如何知道必须将限制传递给命令? 为此,Symfony控制台向我们提供了问题帮助器 。

问题助手 (Question Helper)

The Question helper provides functionality to ask the user for more information. This way we can interactively collect information for the execution of our commands.

问题帮助器提供了向用户询问更多信息的功能。 这样,我们可以交互地收集信息以执行命令。

Let’s change our command to, instead of receiving a limit of execution through the command execution prompt, ask the user for a limit. For that, the question helper has a single method: ask(). This method receives as arguments an InputInterface, an OutputInterface and a question.

让我们将命令更改为,而不是通过命令执行提示接收执行限制,而是向用户询问限制。 为此,问题助手有一个方法: ask() 。 这个方法接收作为参数的InputInterface ,一个OutputInterface和question 。

Let’s change the FizzCommand.php file so it looks like this:

让我们更改FizzCommand.php文件,使其看起来像这样:

<?php namespace FizzBuzz; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Question\Question; use FizzBuzz\Fizzbuzz; class FizzCommand extends Command{ protected function configure(){ $this->setName("FizzBuzz:FizzBuzz") ->setDescription("Runs Fizzbuzz"); } protected function execute(InputInterface $input, OutputInterface $output){ $fizzy = new FizzBuzz(); $helper = $this->getHelper('question'); $question = new Question('Please select a limit for this execution: ', 25); $limit = $helper->ask($input, $output, $question); $result = $fizzy->firstNFizzbuzz($limit); } }

We no longer expect an argument on the configure() method. We instantiate a new Question with a default of 25 and use it on the ask() method we talked about earlier.

我们不再期望对configure()方法使用参数。 我们实例化一个默认值为25的新Question并将其用于我们之前讨论的ask()方法。

Now we have an interactive command that asks for a limit before executing Fizzbuzz.

现在,我们有一个交互式命令,要求在执行Fizzbuzz之前先进行限制。

The question helper also gives us functionality to validate the answers. So let’s use it to make sure the limit is an integer.

问题帮助程序还为我们提供了验证答案的功能。 因此,让我们使用它来确保限制为整数。

protected function execute(InputInterface $input, OutputInterface $output){ $fizzy = new FizzBuzz(); $helper = $this->getHelper('question'); $question = new Question('Please select a limit for this execution: ', 25); $question->setValidator(function ($answer) { if (!is_numeric($answer)) { throw new \RuntimeException('The limit should be an integer.'); } return $answer; }); $question->setNormalizer(function ($value) { return $value ? trim($value) : ''; }); $question->setMaxAttempts(2); $limit = $helper->ask($input, $output, $question); $result = $fizzy->firstNFizzbuzz($limit); }

Not only are we making sure that our limit is an integer by using the setValidator() function, we are also normalizing the input in case the user inserts some blank spaces and also setting the maximum amount of attempts permitted to two.

通过使用setValidator()函数,不仅可以确保我们的限制是整数,还可以在用户插入一些空格的情况下对输入进行规范化,并将最大尝试次数设置为两次。

The question helper offers a lot more functionality like letting the user choose from a list of answers, multiple answers, hiding the user answer, and autocompletion. The official documentation has a lot more information on that.

问题帮助器提供了更多功能,例如让用户从答案列表中选择,多个答案,隐藏用户答案以及自动完成。 官方文档对此有更多信息。

桌子 (Tables)

Another very useful function provided by the console component is the possibility to display tabular data.

控制台组件提供的另一个非常有用的功能是可以显示表格数据。

To display a table we need to use the Table class; set the headers and rows, and finally render the table. This can be very useful when it comes to showing structured data. Let’s imagine we want to create a command to show the conversions for some metric systems.

要显示一个表,我们需要使用Table类。 设置标题和行,最后渲染表。 当显示结构化数据时,这可能非常有用。 假设我们要创建一个命令来显示某些度量系统的转换。

Let’s add MetricsCommand.php to our new php file.

让我们将MetricsCommand.php添加到我们的新php文件中。

<?php namespace Metric; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Helper\Table; class MetricsCommand extends Command{ protected function configure(){ $this->setName("Metrics") ->setDescription("Inches to centimeters table."); } public function execute(InputInterface $input, OutputInterface $output){ $table = new Table($output); $table ->setHeaders(array('Inches', 'Centimeters')) ->setRows(array( array('1', '2.54'), array('5', '12.7'), array('10', '25.4'), array('50', '127'), )) ; $table->render(); } }

And our new console file:

还有我们的新console文件:

#!/usr/bin/env php <?php require_once __DIR__ . '/vendor/autoload.php'; use Symfony\Component\Console\Application; use Metric\MetricsCommand; $app = new Application(); $app->add(new MetricsCommand()); $app->run();

It’s a very simple command: it renders a table with some values converted from inches to centimeters. If we run our command using ./console Metrics, the result will be something like this:

这是一个非常简单的命令:它渲染一个表格,其中某些值从英寸转换为厘米。 如果我们使用./console Metrics运行命令,则结果将如下所示:

The Table class also offers us different separator styles for our tables. Check this page if you want to know more. .

Table类还为我们的Table提供了不同的分隔符样式。 如果您想了解更多,请查看此页面 。 。

进度条 (Progress Bars)

While questions and tables can be very useful, the most important element might be the progress bar. Progress bars give us feedback about the execution of the command and allow us to have a clear view of how long we might have to wait for an operation to finish.

尽管问题和表格可能非常有用,但最重要的元素可能是进度栏。 进度条为我们提供了有关命令执行的反馈,并让我们清晰地了解了等待操作完成的时间。

Progress bars are essential for longer running commands. To use them, we need the ProgressBar, pass it a total number of units (if we actually know how many units we expect) and advance it as the command executes.

进度条对于长时间运行的命令至关重要。 要使用它们,我们需要ProgressBar ,将总数传递给它(如果我们实际上知道我们期望多少个单元),并在命令执行时将其前进。

A simple command with a progress bar may look like this:

一个带有进度条的简单命令可能如下所示:

<?php namespace Progress; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Helper\ProgressBar; class ProgressCommand extends Command{ protected function configure(){ $this->setName("Progress") ->setDescription("Check Console componenet progress bar."); } public function execute(InputInterface $input, OutputInterface $output) { $progress = new ProgressBar($output); $progress->start(); $i = 0; while ($i++ < 50) { usleep(300000); $progress->advance(); } $progress->finish(); } }

And the respective console:

以及相应的console :

#!/usr/bin/env php <?php require_once __DIR__ . '/vendor/autoload.php'; use Symfony\Component\Console\Application; use Progress\ProgressCommand; $app = new Application(); $app->add(new ProgressCommand()); $app->run();

This a very simple command. We set up the bar and loop through a sleep() function. The final output will look like this:

这是一个非常简单的命令。 我们设置了bar,并通过sleep()函数进行循环。 最终输出将如下所示:

More information on progress bars can be found in the official documentation.

有关进度条的更多信息,请参见官方文档 。

自定义我们的进度条 (Customizing Our Progress Bar)

Customizing progress bars can be useful to provide extra information while the user waits.

自定义进度条对于在用户等待时提供额外的信息很有用。

By default, the information shown in the progress bar depends on the level of verbosity of the OutputInterface instance. So, if we want to show different levels of information we can use the setFormat() method.

默认情况下,进度栏中显示的信息取决于OutputInterface实例的详细程度。 因此,如果我们想显示不同级别的信息,可以使用setFormat()方法。

$bar->setFormat('verbose');

The built-in formats are: normal, verbose, very_verbose and debug.

内置格式为: normal , verbose , very_verbose和debug 。

If we use use normal format for example, the result will look like this:

例如,如果使用normal格式,则结果将如下所示:

We can also set our own format.

我们还可以设置自己的格式。

The progress bar is a string that’s composed of different specific placeholders. We can combine those specific placeholders to create our own progress bars. The available placeholders are: current, max, bar, percent, elapsed, remaining, estimated, memory and message. So if, for instance, we wanted to copy the exact same default progress bar, we could use the following:

进度条是由不同的特定占位符组成的字符串。 我们可以结合使用这些特定的占位符来创建自己的进度条。 可用的占位符是: current , max , bar , percent , elapsed , remaining , estimated , memory和message 。 因此,例如,如果我们想复制完全相同的默认进度条,则可以使用以下内容:

$bar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');

There’s a lot more to customizing progress bars – read about it here.

自定义进度条还有更多内容- 在此处阅读。

在命令内调用命令 (Calling a command inside a command)

Another very useful feature to have is the ability to run a command inside a command. For example, we might have a command which depends on another command to successfully run, or a succession of commands we might want to run in a sequence.

另一个非常有用的功能是能够在命令内部运行命令。 例如,我们可能有一个依赖于另一个命令才能成功运行的命令,或者我们可能希望按顺序运行的一系列命令。

For example, imagine we wanted to create a command to run our fizzbuzz command. We would need to create a new command inside our /src folder and inside the execute() method, have the following:

例如,假设我们想创建一个命令来运行fizzbuzz命令。 我们需要在/src文件夹内以及execute()方法内创建一个新命令,其内容如下:

protected function execute(InputInterface $input, OutputInterface $output) { $command = $this->getApplication()->find('FizzBuzz:FizzBuzz'); $returnCode = $command->run(); }

Since our FizzBuzz command doesn’t receive any arguments, that would be enough. In case our command needed arguments we would have to create an array of arguments and use the ArrayInput class to pass them.

由于我们的FizzBu​​zz命令不接收任何参数,这就足够了。 如果我们的命令需要参数,则必须创建一个参数数组并使用ArrayInput类传递它们。

Other than that it’s all about using the find() method with our command name to find and register our command.

除此之外,还需要使用带有我们命令名称的find()方法来查找和注册我们的命令。

颜色和款式 (Color and Style)

Coloring and styling the output can be useful for alerting or informing the user about something in the command’s execution. For that, we just need to add the following tags to our writeln() method, just like the following:

对输出进行着色和样式设置对于警告或通知用户有关命令执行中的某些内容很有用。 为此,我们只需要将以下标签添加到我们的writeln()方法中,如下所示:

// green text $output->writeln('<info>Output here</info>'); // yellow text $output->writeln('<comment>Output here</comment>'); // black text on a cyan background $output->writeln('<question>Output here</question>'); // white text on a red background $output->writeln('<error>Output here</error>');

There’s also the option to define our own styles using the OutputFormatterStyle class:

还有一个选项可以使用OutputFormatterStyle类来定义我们自己的样式:

$style = new OutputFormatterStyle('red', 'yellow', array('bold', 'blink')); $output->getFormatter()->setStyle('fire', $style); $output->writeln('<fire>foo</fire>');

More information on styling the output can be found here.

有关设置输出样式的更多信息,请参见此处 。

加起来 (Summing up)

From styling to helpers, we saw a lot of functionality that the Symfony console provides out of the box. After today, there’s absolutely no excuse to have badly documented command line tools!

从样式到助手,我们看到了Symfony控制台提供的许多功能。 今天过后,绝对没有借口使用糟糕的命令行工具!

Which helpers and components of the Console do you frequently use? How do you start your CLI tools? Is the Symfony Console enough for you, or do you prefer an alternative?

您经常使用控制台的哪些帮助程序和组件? 如何启动CLI工具? Symfony控制台足以满足您的需求,还是您更喜欢替代产品 ?

翻译自: https://www.sitepoint.com/symfony-console-beyond-the-basics-helpers-and-other-tools/

symfony 控制器

最新回复(0)