8000 [Console] Issue #9564: added SingleCommandApplication · soxofaan/symfony@e73b495 · GitHub
[go: up one dir, main page]

Skip to content

Commit e73b495

Browse files
author
Stefaan Lippens
committed
[Console] Issue symfony#9564: added SingleCommandApplication
Added SingleCommandApplication to simplify creating and using Applications that only provide one Command.
1 parent 48c9985 commit e73b495

File tree

4 files changed

+287
-0
lines changed

4 files changed

+287
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
17+
/**
18+
* Application providing access to just one command.
19+
*
20+
* When a console application only consists of one
21+
* command, having to specify this command's name as first
22+
* argument is superfluous.
23+
* This class simplifies creating and using this
24+
* kind of applications.
25+
*
26+
* Usage:
27+
*
28+
* $cmd = new SimpleCommand();
29+
* $app = new SingleCommandApplication($cmd, '1.2');
30+
* $app->run();
31+
*
32+
* @author Stefaan Lippens <soxofaan@gmail.com>
33+
*/
34+
class SingleCommandApplication extends Application
35+
{
36+
/**
37+
* Name of the single accessible command of this application
38+
* @var string
39+
*/
40+
private $commandName;
41+
42+
/**
43+
* Constructor to build a "single command" application, given a command.
44+
*
45+
* The application will adopt the same name as the command.
46+
*
47+
* @param Command $command The single (accessible) command for this application
48+
* @param string $version The version of the application
49+
*/
50+
public function __construct(Command $command, $version = 'UNKNOWN')
51+
{
52+
parent::__construct($command->getName(), $version);
53+
54+
// Add the given command as single (accessible) command.
55+
$this->add($command);
56+
$this->commandName = $command->getName();
57+
58+
// Override the Application's definition so that it does not
59+
// require a command name as first argument.
60+
$this->getDefinition()->setArguments();
61+
}
62+
63+
/**
64+
* {@inheritdoc}
65+
*/
66+
protected function getCommandName(InputInterface $input)
67+
{
68+
return $this->commandName;
69+
}
70+
71+
/**
72+
* Adds a command object.
73+
*
74+
* This function overrides (public) Application::add()
75+
* but should should only be used internally.
76+
* Will raise \LogicException when called
77+
* after the single accessible command is set up
78+
* (from the constructor).
79+
*
80+
* @param Command $command A Command object
81+
*
82+
* @return Command The registered command
83+
*
84+
* @throws \LogicException
85+
*/
86+
public function add(Command $command)
87+
{
88+
// Fail if we already set up the single accessible command.
89+
if ($this->commandName) {
90+
throw new \LogicException("You should not add additional commands to a SingleCommandApplication instance.");
91+
}
92+
93+
return parent::add($command);
94+
}
95+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
use Symfony\Component\Console\Command\Command;
4+
use Symfony\Component\Console\Input\InputInterface;
5+
use Symfony\Component\Console\Input\InputOption;
6+
use Symfony\Component\Console\Input\InputArgument;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
class FooScaCommand extends Command
10+
{
11+
protected function configure()
12+
{
13+
$this
14+
->setName('foosca')
15+
->setDescription('The foosca command');
16+
$this->addArgument(
17+
'items',
18+
InputArgument::IS_ARRAY,
19+
'Items to process'
20+
);
21+
$this->addOption(
22+
'bar',
23+
'b',
24+
InputOption::VALUE_NONE,
25+
'Enable barring'
26+
);
27+
}
28+
29+
protected function execute(InputInterface $input, OutputInterface $output)
30+
{
31+
$bar = $input->getOption('bar');
32+
$output->writeln('<info>FooSca</info>' . ($bar ? ' (barred)': ' (basic)'));
33+
34+
foreach ($input->getArgument('items') as $item) {
35+
$output->writeln('Item: ' . $item);
36+
}
37+
}
38+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Usage:
2+
foosca [-b|--bar] [items1] ... [itemsN]
3+
4+
Arguments:
5+
items Items to process
6+
7+
Options:
8+
--bar (-b) Enable barring
9+
--help (-h) Display this help message.
10+
--quiet (-q) Do not output any message.
11+
--verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
12+
--version (-V) Display this application version.
13+
--ansi Force ANSI output.
14+
--no-ansi Disable ANSI output.
15+
--no-interaction (-n) Do not ask any interactive question.
16+
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Tests;
13+
14+
use Symfony\Component\Console\Input\ArgvInput;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\StreamOutput;
17+
use Symfony\Component\Console\SingleCommandApplication;
18+
19+
class SingleCommandApplicationTest extends \PHPUnit_Framework_TestCase
20+
{
21+
protected static $fixturesPath;
22+
23+
public static function setUpBeforeClass()
24+
{
25+
self::$fixturesPath = realpath(__DIR__ . '/Fixtures/');
26+
require_once self::$fixturesPath.'/FooCommand.php';
27+
require_once self::$fixturesPath . '/FooScaCommand.php';
28+
}
29+
30+
public function testConstructor()
31+
{
32+
$application = new SingleCommandApplication(new \FooScaCommand(), 'v2.3');
33+
$this->assertEquals(
34+
'foosca',
35+
$application->getName(),
36+
'__construct() takes the application name as its first argument'
37+
);
38+
$this->assertEquals(
39+
'v2.3',
40+
$application->getVersion(),
41+
'__construct() takes the application version as its second argument'
42+
);
43+
$this->assertEquals(
44+
array('help', 'list', 'foosca'),
45+
array_keys($application->all()),
46+
'__construct() registered the help and list commands by default'
47+
);
48+
}
49+
50+
/**
51+
* @dataProvider provideRunData
52+
*/
53+
public function testRun(InputInterface $input, $expectedOutput, $expectedStatusCode=0)
54+
{
55+
// Set up application.
56+
$application = new SingleCommandApplication(new \FooScaCommand(), '1.234');
57+
$application->setAutoExit(false);
58+
$application->setCatchExceptions(false);
59+
60+
// Set up output for application to render to.
61+
$stream = fopen('php://memory', 'w', false);
62+
$output = new StreamOutput($stream);
63+
64+
// Run application with given input.
65+
$statusCode = $application->run($input, $output);
66+
67+
// Get generated output (and normalize newlines)
68+
rewind($stream);
69+
$display = stream_get_contents($stream);
70+
$display = str_replace(PHP_EOL, "\n", $display);
71+
72+
$this->assertEquals($expectedStatusCode, $statusCode);
73+
$this->assertEquals($expectedOutput, $display);
74+
}
75+
76+
public function provideRunData()
77+
{
78+
$data = array();
79+
$data[] = array(
80+
new ArgvInput(array('cli.php')),
81+
"FooSca (basic)\n",
82+
);
83+
84+
$data[] = array(
85+
new ArgvInput(array('cli.php', 'qwe')),
86+
"FooSca (basic)\nItem: qwe\n",
87+
);
88+
89+
$data[] = array(
90+
new ArgvInput(array('cli.php', '--bar', 'qwe')),
91+
"FooSca (barred)\nItem: qwe\n",
92+
);
93+
94+
$data[] = array(
95+
new ArgvInput(array('cli.php', '--bar', 'qwe', 'rty')),
96+
"FooSca (barred)\nItem: qwe\nItem: rty\n",
97+
);
98+
99+
$data[] = array(
100+
new ArgvInput(array('cli.php', 'list')),
101+
"FooSca (basic)\nItem: list\n",
102+
);
103+
104+
$data[] = array(
105+
new ArgvInput(array('cli.php', 'help')),
106+
"FooSca (basic)\nItem: help\n",
107+
);
108+
109+
$data[] = array(
110+
new ArgvInput(array('cli.php', '--help')),
111+
file_get_contents(__DIR__ . '/Fixtures/' . '/application_run_foosca_help.txt'),
112+
);
113+
114+
$data[] = array(
115+
new ArgvInput(array('cli.php', '-h')),
116+
file_get_contents(__DIR__ . '/Fixtures/' . '/application_run_foosca_help.txt'),
117+
);
118+
119+
$data[] = array(
120+
new ArgvInput(array('cli.php', '--version')),
121+
"foosca version 1.234\n"
122+
);
123+
124+
$data[] = array(
125+
new ArgvInput(array('cli.php', '-V')),
126+
"foosca version 1.234\n"
127+
);
128+
129+
return $data;
130+
}
131+
132+
public function testAddingMoreCommands()
133+
{
134+
$app = new SingleCommandApplication(new \FooScaCommand());
135+
$this->setExpectedException('LogicException');
136+
$app->add(new \FooCommand());
137+
}
138+
}

0 commit comments

Comments
 (0)
0