Merge branch '4.3' into 4.4

* 4.3:
  Do not include hidden commands in suggested alternatives
  [DependencyInjection] Fix wrong exception when service is synthetic
This commit is contained in:
Nicolas Grekas 2019-09-28 16:56:00 +02:00
commit 399e0fb06f
6 changed files with 68 additions and 6 deletions

View File

@ -557,6 +557,10 @@ class Application implements ResetInterface
{
$namespaces = [];
foreach ($this->all() as $command) {
if ($command->isHidden()) {
continue;
}
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
foreach ($command->getAliases() as $alias) {
@ -654,6 +658,11 @@ class Application implements ResetInterface
$message = sprintf('Command "%s" is not defined.', $name);
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
// remove hidden commands
$alternatives = array_filter($alternatives, function ($name) {
return !$this->get($name)->isHidden();
});
if (1 == \count($alternatives)) {
$message .= "\n\nDid you mean this?\n ";
} else {
@ -662,7 +671,7 @@ class Application implements ResetInterface
$message .= implode("\n ", $alternatives);
}
throw new CommandNotFoundException($message, $alternatives);
throw new CommandNotFoundException($message, array_values($alternatives));
}
// filter out aliases for commands which are already on the list
@ -685,13 +694,18 @@ class Application implements ResetInterface
}
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
if (!$commandList[$cmd] instanceof Command) {
return $cmd;
$commandList[$cmd] = $this->commandLoader->get($cmd);
}
if ($commandList[$cmd]->isHidden()) {
return false;
}
$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
}, array_values($commands));
$suggestions = $this->getAbbreviationSuggestions($abbrevs);
$suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));
throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands));
}

View File

@ -75,6 +75,7 @@ class ApplicationTest extends TestCase
require_once self::$fixturesPath.'/FooWithoutAliasCommand.php';
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering.php';
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering2.php';
require_once self::$fixturesPath.'/FooHiddenCommand.php';
}
protected function normalizeLineBreaks($text)
@ -664,6 +665,7 @@ class ApplicationTest extends TestCase
$application->add(new \Foo1Command());
$application->add(new \Foo2Command());
$application->add(new \Foo3Command());
$application->add(new \FooHiddenCommand());
$expectedAlternatives = [
'afoobar',

View File

@ -0,0 +1,21 @@
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class FooHiddenCommand extends Command
{
protected function configure()
{
$this
->setName('foo:hidden')
->setAliases(['afoohidden'])
->setHidden(true)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
}
}

View File

@ -113,6 +113,10 @@ abstract class AbstractRecursivePass implements CompilerPassInterface
*/
protected function getConstructor(Definition $definition, $required)
{
if ($definition->isSynthetic()) {
return null;
}
if (\is_string($factory = $definition->getFactory())) {
if (!\function_exists($factory)) {
throw new RuntimeException(sprintf('Invalid service "%s": function "%s" does not exist.', $this->currentId, $factory));

View File

@ -568,12 +568,10 @@ class AutowirePassTest extends TestCase
);
}
/**
* @exceptedExceptionMessage Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy": method "setLogger()" does not exist.
*/
public function testWithNonExistingSetterAndAutowiring()
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass": method "setLogger()" does not exist.');
$container = new ContainerBuilder();
$definition = $container->register(CaseSensitiveClass::class, CaseSensitiveClass::class)->setAutowired(true);

View File

@ -15,9 +15,11 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\AutowireRequiredMethodsPass;
use Symfony\Component\DependencyInjection\Compiler\DefinitionErrorExceptionPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
@ -131,4 +133,25 @@ class ResolveBindingsPassTest extends TestCase
$pass = new ResolveBindingsPass();
$pass->process($container);
}
public function testSyntheticServiceWithBind()
{
$container = new ContainerBuilder();
$argument = new BoundArgument('bar');
$container->register('foo', 'stdClass')
->addArgument(new Reference('synthetic.service'));
$container->register('synthetic.service')
->setSynthetic(true)
->setBindings(['$apiKey' => $argument]);
$container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class)
->setBindings(['$apiKey' => $argument]);
(new ResolveBindingsPass())->process($container);
(new DefinitionErrorExceptionPass())->process($container);
$this->assertSame([1 => 'bar'], $container->getDefinition(NamedArgumentsDummy::class)->getArguments());
}
}