8000 [Console] Add support for command lazy-loading by chalasr · Pull Request #22734 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Console] Add support for command lazy-loading #22734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ CHANGELOG
`Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass` instead
* Deprecated `TranslatorPass`, use
`Symfony\Component\Translation\DependencyInjection\TranslatorPass` instead
* Added `command` attribute to the `console.command` tag which takes the command
name as value, using it makes the command lazy

3.3.0
-----
Expand Down
26 changes: 15 additions & 11 deletions src/Symfony/Bundle/FrameworkBundle/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,7 @@ public function doRun(InputInterface $input, OutputInterface $output)
{
$this->kernel->boot();

$container = $this->kernel->getContainer();

foreach ($this->all() as $command) {
if ($command instanceof ContainerAwareInterface) {
$command->setContainer($container);
}
}

$this->setDispatcher($container->get('event_dispatcher'));
$this->setDispatcher($this->kernel->getContainer()->get('event_dispatcher'));

return parent::doRun($input, $output);
}
Expand All @@ -98,7 +90,13 @@ public function get($name)
{
$this->registerCommands();

return parent::get($name);
$command = parent::get($name);

if ($command instanceof ContainerAwareInterface) {
$command->setContainer($this->kernel->getContainer());
}

return $command;
}

/**
Expand Down Expand Up @@ -144,9 +142,15 @@ protected function registerCommands()
}
}

if ($container->has('console.command_loader')) {
$this->setCommandLoader($container->get('console.command_loader'));
}

if ($container->hasParameter('console.command.ids')) {
foreach ($container->getParameter('console.command.ids') as $id) {
$this->add($container->get($id));
if (false !== $id) {
$this->add($container->get($id));
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,15 @@ private function getKernel()

$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock();
$container
->expects($this->once())
->expects($this->atLeastOnce())
->method('has')
->with('router')
->will($this->returnValue(true))
->will($this->returnCallback(function ($id) {
if ('console.command_loader' === $id) {
return false;
}

return true;
}))
;
$container
->expects($this->any())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ private function getKernel()
$container
->expects($this->atLeastOnce())
->method('has')
->with('router')
->will($this->returnValue(true));
->will($this->returnCallback(function ($id) {
if ('console.command_loader' === $id) {
return false;
}

return true;
}))
;
$container
->expects($this->any())
->method('get')
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bundle/FrameworkBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"fig/link-util": "^1.0",
"symfony/asset": "~3.3|~4.0",
"symfony/browser-kit": "~2.8|~3.0|~4.0",
"symfony/console": "~3.3|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/css-selector": "~2.8|~3.0|~4.0",
"symfony/dom-crawler": "~2.8|~3.0|~4.0",
"symfony/polyfill-intl-icu": "~1.0",
Expand Down Expand Up @@ -64,7 +64,7 @@
"phpdocumentor/type-resolver": "<0.2.0",
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/asset": "<3.3",
"symfony/console": "<3.3",
"symfony/console": "<3.4",
"symfony/form": "<3.3",
"symfony/property-info": "<3.3",
"symfony/serializer": "<3.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<service id="security.console.user_password_encoder_command" class="Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand">
<argument type="service" id="security.encoder_factory"/>
<argument type="collection" /> <!-- encoders' user classes -->
<tag name="console.command" />
<tag name="console.command" command="security:encode-password" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@
<service id="web_server.command.server_run" class="Symfony\Bundle\WebServerBundle\Command\ServerRunCommand">
<argument>%kernel.project_dir%/web</argument>
<argument>%kernel.environment%</argument>
<tag name="console.command" />
<tag name="console.command" command="server:run" />
</service>

<service id="web_server.command.server_start" class="Symfony\Bundle\WebServerBundle\Command\ServerStartCommand">
<argument>%kernel.project_dir%/web</argument>
<argument>%kernel.environment%</argument>
<tag name="console.command" />
<tag name="console.command" command="server:start" />
</service>

<service id="web_server.command.server_stop" class="Symfony\Bundle\WebServerBundle\Command\ServerStopCommand">
<tag name="console.command" />
<tag name="console.command" command="server:stop" />
</service>

<service id="web_server.command.server_status" class="Symfony\Bundle\WebServerBundle\Command\ServerStatusCommand">
<tag name="console.command" />
<tag name="console.command" command="server:status" />
</service>
</services>
</container>
57 changes: 47 additions & 10 deletions src/Symfony/Component/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\Console;

use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
Expand Down Expand Up @@ -64,6 +65,7 @@ class Application
private $runningCommand;
private $name;
private $version;
private $commandLoader;
private $catchExceptions = true;
private $autoExit = true;
private $definition;
Expand Down Expand Up @@ -96,6 +98,11 @@ public function setDispatcher(EventDispatcherInterface $dispatcher)
$this->dispatcher = $dispatcher;
}

public function setCommandLoader(CommandLoaderInterface $commandLoader)
{
$this->commandLoader = $commandLoader;
}

/**
* Runs the current application.
*
Expand Down Expand Up @@ -431,6 +438,10 @@ public function add(Command $command)
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
}

if (!$command->getName()) {
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($command)));
}

$this->commands[$command->getName()] = $command;

foreach ($command->getAliases() as $alias) {
Expand All @@ -451,12 +462,16 @@ public function add(Command $command)
*/
public function get($name)
{
if (!isset($this->commands[$name])) {
if (isset($this->commands[$name])) {
$command = $this->commands[$name];
} elseif ($this->commandLoader && $this->commandLoader->has($name)) {
$command = $this->commandLoader->get($name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$command = $this->commands[$name] = ...;?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add() does more than $this->command[$name] = $command, hence calling it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

omfg. my bad :)

$command->setName($name);
$this->add($command);
} else {
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
}

$command = $this->commands[$name];

if ($this->wantHelps) {
$this->wantHelps = false;

Expand All @@ -478,7 +493,7 @@ public function get($name)
*/
public function has($name)
{
return isset($this->commands[$name]);
return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name));
}

/**
Expand Down Expand Up @@ -555,7 +570,7 @@ public function findNamespace($namespace)
*/
public function find($name)
{
$allCommands = array_keys($this->commands);
$allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);

Expand All @@ -581,12 +596,12 @@ public function find($name)

// filter out aliases for commands which are already on the list
if (count($commands) > 1) {
$commandList = $this->commands;
$commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
$commandName = $commandList[$nameOrAlias]->getName();
$commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
$commandName = $commandList[$nameOrAlias] instanceof Command ? $commandList[$nameOrAlias]->getName() : $nameOrAlias;

return $commandName === $nameOrAlias || !in_array($commandName, $commands);
});
}));
}

$exact = in_array($name, $commands, true);
Expand All @@ -598,6 +613,9 @@ public function find($name)
$maxLen = max(Helper::strlen($abbrev), $maxLen);
}
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
if (!$commandList[$cmd] instanceof Command) {
return $cmd;
}
$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();

return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
Expand All @@ -622,7 +640,18 @@ public function find($name)
public function all($namespace = null)
{
if (null === $namespace) {
return $this->commands;
if (!$this->commandLoader) {
return $this->commands;
}

$commands = $this->commands;
foreach ($this->commandLoader->getNames() as $name) {
if (!isset($commands[$name])) {
$commands[$name] = $this->commandLoader->get($name);
}
}

return $commands;
}

$commands = array();
Expand All @@ -632,6 +661,14 @@ public function all($namespace = null)
}
}

if ($this->commandLoader) {
foreach ($this->commandLoader->getNames() as $name) {
if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
$commands[$name] = $this->commandLoader->get($name);
}
}
}

return $commands;
}

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

3.4.0
-----

* added `CommandLoaderInterface` and PSR-11 `ContainerCommandLoader`

3.3.0
-----

Expand Down
4 changes: 0 additions & 4 deletions src/Symfony/Component/Console/Command/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ public function __construct($name = null)
}

$this->configure();

if (!$this->name) {
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Symfony\Component\Console\CommandLoader;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;

/**
* @author Robin Chalas <robin.chalas@gmail.com>
*/
interface CommandLoaderInterface
{
/**
* Loads a command.
*
* @param string $name
*
* @return Command
*
* @throws CommandNotFoundException
*/
public function get($name);

/**
* Checks if a command exists.
*
* @param string $name
*
* @return bool
*/
public function has($name);

/**
* @return string[] All registered command names
*/
public function getNames();
}
Loading
0