1
0

提交代码

This commit is contained in:
2020-08-06 14:50:07 +08:00
parent 9d0d5f4be9
commit d7a848c824
11299 changed files with 1321854 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass;
class AddAnnotatedClassesToCachePassTest extends TestCase
{
public function testExpandClasses()
{
$r = new \ReflectionClass(AddAnnotatedClassesToCachePass::class);
$pass = $r->newInstanceWithoutConstructor();
$r = new \ReflectionMethod(AddAnnotatedClassesToCachePass::class, 'expandClasses');
$r->setAccessible(true);
$expand = $r->getClosure($pass);
$this->assertSame('Foo', $expand(['Foo'], [])[0]);
$this->assertSame('Foo', $expand(['\\Foo'], [])[0]);
$this->assertSame('Foo', $expand(['Foo'], ['\\Foo'])[0]);
$this->assertSame('Foo', $expand(['Foo'], ['Foo'])[0]);
$this->assertSame('Foo', $expand(['\\Foo'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo', $expand(['Foo'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo', $expand(['\\Foo'], ['\\Foo\\Bar\\Acme'])[0]);
$this->assertSame('Foo\\Bar', $expand(['Foo\\'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo\\Bar\\Acme', $expand(['Foo\\'], ['\\Foo\\Bar\\Acme'])[0]);
$this->assertEmpty($expand(['Foo\\'], ['\\Foo']));
$this->assertSame('Acme\\Foo\\Bar', $expand(['**\\Foo\\'], ['\\Acme\\Foo\\Bar'])[0]);
$this->assertEmpty($expand(['**\\Foo\\'], ['\\Foo\\Bar']));
$this->assertEmpty($expand(['**\\Foo\\'], ['\\Acme\\Foo']));
$this->assertEmpty($expand(['**\\Foo\\'], ['\\Foo']));
$this->assertSame('Acme\\Foo', $expand(['**\\Foo'], ['\\Acme\\Foo'])[0]);
$this->assertEmpty($expand(['**\\Foo'], ['\\Acme\\Foo\\AcmeBundle']));
$this->assertEmpty($expand(['**\\Foo'], ['\\Acme\\FooBar\\AcmeBundle']));
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\*\\Bar'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertEmpty($expand(['Foo\\*\\Bar'], ['\\Foo\\Acme\\Bundle\\Bar']));
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\**\\Bar'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertSame('Foo\\Acme\\Bundle\\Bar', $expand(['Foo\\**\\Bar'], ['\\Foo\\Acme\\Bundle\\Bar'])[0]);
$this->assertSame('Acme\\Bar', $expand(['*\\Bar'], ['\\Acme\\Bar'])[0]);
$this->assertEmpty($expand(['*\\Bar'], ['\\Bar']));
$this->assertEmpty($expand(['*\\Bar'], ['\\Foo\\Acme\\Bar']));
$this->assertSame('Foo\\Acme\\Bar', $expand(['**\\Bar'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertSame('Foo\\Acme\\Bundle\\Bar', $expand(['**\\Bar'], ['\\Foo\\Acme\\Bundle\\Bar'])[0]);
$this->assertEmpty($expand(['**\\Bar'], ['\\Bar']));
$this->assertSame('Foo\\Bar', $expand(['Foo\\*'], ['\\Foo\\Bar'])[0]);
$this->assertEmpty($expand(['Foo\\*'], ['\\Foo\\Acme\\Bar']));
$this->assertSame('Foo\\Bar', $expand(['Foo\\**'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\**'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertSame(['Foo\\Bar'], $expand(['Foo\\*'], ['Foo\\Bar', 'Foo\\BarTest']));
$this->assertSame(['Foo\\Bar', 'Foo\\BarTest'], $expand(['Foo\\*', 'Foo\\*Test'], ['Foo\\Bar', 'Foo\\BarTest']));
$this->assertSame(
'Acme\\FooBundle\\Controller\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Acme\\FooBundle\\Controller\\DefaultController'])[0]
);
$this->assertSame(
'FooBundle\\Controller\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\FooBundle\\Controller\\DefaultController'])[0]
);
$this->assertSame(
'Acme\\FooBundle\\Controller\\Bar\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Acme\\FooBundle\\Controller\\Bar\\DefaultController'])[0]
);
$this->assertSame(
'Bundle\\Controller\\Bar\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Bundle\\Controller\\Bar\\DefaultController'])[0]
);
$this->assertSame(
'Acme\\Bundle\\Controller\\Bar\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Acme\\Bundle\\Controller\\Bar\\DefaultController'])[0]
);
$this->assertSame('Foo\\Bar', $expand(['Foo\\Bar'], [])[0]);
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\**'], ['\\Foo\\Acme\\Bar'])[0]);
}
}

View File

@@ -0,0 +1,131 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass;
use Symfony\Component\Stopwatch\Stopwatch;
class ControllerArgumentValueResolverPassTest extends TestCase
{
public function testServicesAreOrderedAccordingToPriority()
{
$services = [
'n3' => [[]],
'n1' => [['priority' => 200]],
'n2' => [['priority' => 100]],
];
$expected = [
new Reference('n1'),
new Reference('n2'),
new Reference('n3'),
];
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->setDefinition('argument_resolver', $definition);
foreach ($services as $id => list($tag)) {
$container->register($id)->addTag('controller.argument_value_resolver', $tag);
}
$container->setParameter('kernel.debug', false);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals($expected, $definition->getArgument(1)->getValues());
$this->assertFalse($container->hasDefinition('n1.traceable'));
$this->assertFalse($container->hasDefinition('n2.traceable'));
$this->assertFalse($container->hasDefinition('n3.traceable'));
}
public function testInDebugWithStopWatchDefinition()
{
$services = [
'n3' => [[]],
'n1' => [['priority' => 200]],
'n2' => [['priority' => 100]],
];
$expected = [
new Reference('n1'),
new Reference('n2'),
new Reference('n3'),
];
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->register('debug.stopwatch', Stopwatch::class);
$container->setDefinition('argument_resolver', $definition);
foreach ($services as $id => list($tag)) {
$container->register($id)->addTag('controller.argument_value_resolver', $tag);
}
$container->setParameter('kernel.debug', true);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals($expected, $definition->getArgument(1)->getValues());
$this->assertTrue($container->hasDefinition('debug.n1'));
$this->assertTrue($container->hasDefinition('debug.n2'));
$this->assertTrue($container->hasDefinition('debug.n3'));
$this->assertTrue($container->hasDefinition('n1'));
$this->assertTrue($container->hasDefinition('n2'));
$this->assertTrue($container->hasDefinition('n3'));
}
public function testInDebugWithouStopWatchDefinition()
{
$expected = [new Reference('n1')];
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->register('n1')->addTag('controller.argument_value_resolver');
$container->setDefinition('argument_resolver', $definition);
$container->setParameter('kernel.debug', true);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals($expected, $definition->getArgument(1)->getValues());
$this->assertFalse($container->hasDefinition('debug.n1'));
$this->assertTrue($container->hasDefinition('n1'));
}
public function testReturningEmptyArrayWhenNoService()
{
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->setDefinition('argument_resolver', $definition);
$container->setParameter('kernel.debug', false);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals([], $definition->getArgument(1)->getValues());
}
public function testNoArgumentResolver()
{
$container = new ContainerBuilder();
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertFalse($container->hasDefinition('argument_resolver'));
}
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
class FragmentRendererPassTest extends TestCase
{
/**
* Tests that content rendering not implementing FragmentRendererInterface
* triggers an exception.
*/
public function testContentRendererWithoutInterface()
{
$this->expectException('InvalidArgumentException');
$builder = new ContainerBuilder();
$fragmentHandlerDefinition = $builder->register('fragment.handler');
$builder->register('my_content_renderer', 'Symfony\Component\DependencyInjection\Definition')
->addTag('kernel.fragment_renderer', ['alias' => 'foo']);
$pass = new FragmentRendererPass();
$pass->process($builder);
$this->assertEquals([['addRendererService', ['foo', 'my_content_renderer']]], $fragmentHandlerDefinition->getMethodCalls());
}
public function testValidContentRenderer()
{
$builder = new ContainerBuilder();
$fragmentHandlerDefinition = $builder->register('fragment.handler')
->addArgument(null);
$builder->register('my_content_renderer', 'Symfony\Component\HttpKernel\Tests\DependencyInjection\RendererService')
->addTag('kernel.fragment_renderer', ['alias' => 'foo']);
$pass = new FragmentRendererPass();
$pass->process($builder);
$serviceLocatorDefinition = $builder->getDefinition((string) $fragmentHandlerDefinition->getArgument(0));
$this->assertSame(ServiceLocator::class, $serviceLocatorDefinition->getClass());
$this->assertEquals(['foo' => new ServiceClosureArgument(new Reference('my_content_renderer'))], $serviceLocatorDefinition->getArgument(0));
}
}
class RendererService implements FragmentRendererInterface
{
public function render($uri, Request $request = null, array $options = [])
{
}
public function getName()
{
return 'test';
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler;
class LazyLoadingFragmentHandlerTest extends TestCase
{
public function testRender()
{
$renderer = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface')->getMock();
$renderer->expects($this->once())->method('getName')->willReturn('foo');
$renderer->expects($this->any())->method('render')->willReturn(new Response());
$requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
$requestStack->expects($this->any())->method('getCurrentRequest')->willReturn(Request::create('/'));
$container = $this->getMockBuilder('Psr\Container\ContainerInterface')->getMock();
$container->expects($this->once())->method('has')->with('foo')->willReturn(true);
$container->expects($this->once())->method('get')->willReturn($renderer);
$handler = new LazyLoadingFragmentHandler($container, $requestStack, false);
$handler->render('/foo', 'foo');
// second call should not lazy-load anymore (see once() above on the get() method)
$handler->render('/foo', 'foo');
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
use Symfony\Component\HttpKernel\Log\Logger;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class LoggerPassTest extends TestCase
{
public function testAlwaysSetAutowiringAlias()
{
$container = new ContainerBuilder();
$container->register('logger', 'Foo');
(new LoggerPass())->process($container);
$this->assertFalse($container->getAlias(LoggerInterface::class)->isPublic());
}
public function testDoNotOverrideExistingLogger()
{
$container = new ContainerBuilder();
$container->register('logger', 'Foo');
(new LoggerPass())->process($container);
$this->assertSame('Foo', $container->getDefinition('logger')->getClass());
}
public function testRegisterLogger()
{
$container = new ContainerBuilder();
$container->setParameter('kernel.debug', false);
(new LoggerPass())->process($container);
$definition = $container->getDefinition('logger');
$this->assertSame(Logger::class, $definition->getClass());
$this->assertFalse($definition->isPublic());
}
}

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
class MergeExtensionConfigurationPassTest extends TestCase
{
public function testAutoloadMainExtension()
{
$container = new ContainerBuilder();
$container->registerExtension(new LoadedExtension());
$container->registerExtension(new NotLoadedExtension());
$container->loadFromExtension('loaded', []);
$configPass = new MergeExtensionConfigurationPass(['loaded', 'not_loaded']);
$configPass->process($container);
$this->assertTrue($container->hasDefinition('loaded.foo'));
$this->assertTrue($container->hasDefinition('not_loaded.bar'));
}
}
class LoadedExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$container->register('loaded.foo');
}
}
class NotLoadedExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$container->register('not_loaded.bar');
}
}

View File

@@ -0,0 +1,436 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
class RegisterControllerArgumentLocatorsPassTest extends TestCase
{
public function testInvalidClass()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Class "Symfony\Component\HttpKernel\Tests\DependencyInjection\NotFound" used for service "foo" cannot be found.');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NotFound::class)
->addTag('controller.service_arguments')
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoAction()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Missing "action" attribute on tag "controller.service_arguments" {"argument":"bar"} for service "foo".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['argument' => 'bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoArgument()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Missing "argument" attribute on tag "controller.service_arguments" {"action":"fooAction"} for service "foo".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoService()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Missing "id" attribute on tag "controller.service_arguments" {"action":"fooAction","argument":"bar"} for service "foo".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testInvalidMethod()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Invalid "action" attribute on tag "controller.service_arguments" for service "foo": no public "barAction()" method found on class "Symfony\Component\HttpKernel\Tests\DependencyInjection\RegisterTestController".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'barAction', 'argument' => 'bar', 'id' => 'bar_service'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testInvalidArgument()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Invalid "controller.service_arguments" tag for service "foo": method "fooAction()" has no "baz" argument on class "Symfony\Component\HttpKernel\Tests\DependencyInjection\RegisterTestController".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'baz', 'id' => 'bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testAllActions()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments')
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertEquals(['foo::fooAction'], array_keys($locator));
$this->assertInstanceof(ServiceClosureArgument::class, $locator['foo::fooAction']);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$this->assertSame(ServiceLocator::class, $locator->getClass());
$this->assertFalse($locator->isPublic());
$expected = ['bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'bar'))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testExplicitArgument()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => 'bar'])
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => 'baz']) // should be ignored, the first wins
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$expected = ['bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testOptionalArgument()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => '?bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$expected = ['bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testSkipSetContainer()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ContainerAwareRegisterTestController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertSame(['foo::fooAction'], array_keys($locator));
}
public function testExceptionOnNonExistentTypeHint()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Cannot determine controller argument for "Symfony\Component\HttpKernel\Tests\DependencyInjection\NonExistentClassController::fooAction()": the $nonExistent argument is type-hinted with the non-existent class or interface: "Symfony\Component\HttpKernel\Tests\DependencyInjection\NonExistentClass". Did you forget to add a use statement?');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NonExistentClassController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testExceptionOnNonExistentTypeHintDifferentNamespace()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Cannot determine controller argument for "Symfony\Component\HttpKernel\Tests\DependencyInjection\NonExistentClassDifferentNamespaceController::fooAction()": the $nonExistent argument is type-hinted with the non-existent class or interface: "Acme\NonExistentClass".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NonExistentClassDifferentNamespaceController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoExceptionOnNonExistentTypeHintOptionalArg()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NonExistentClassOptionalController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertSame(['foo::barAction', 'foo::fooAction'], array_keys($locator));
}
public function testArgumentWithNoTypeHintIsOk()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertEmpty(array_keys($locator));
}
public function testControllersAreMadePublic()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->setPublic(false)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$this->assertTrue($container->getDefinition('foo')->isPublic());
}
/**
* @dataProvider provideBindings
*/
public function testBindings($bindingName)
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->setBindings([$bindingName => new Reference('foo')])
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$expected = ['bar' => new ServiceClosureArgument(new Reference('foo'))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function provideBindings()
{
return [
[ControllerDummy::class.'$bar'],
[ControllerDummy::class],
['$bar'],
];
}
/**
* @dataProvider provideBindScalarValueToControllerArgument
*/
public function testBindScalarValueToControllerArgument($bindingKey)
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->setBindings([$bindingKey => '%foo%'])
->addTag('controller.service_arguments');
$container->setParameter('foo', 'foo_val');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
// assert the locator has a someArg key
$arguments = $locator->getArgument(0);
$this->assertArrayHasKey('someArg', $arguments);
$this->assertInstanceOf(ServiceClosureArgument::class, $arguments['someArg']);
// get the Reference that someArg points to
$reference = $arguments['someArg']->getValues()[0];
// make sure this service *does* exist and returns the correct value
$this->assertTrue($container->has((string) $reference));
$this->assertSame('foo_val', $container->get((string) $reference));
}
public function provideBindScalarValueToControllerArgument()
{
yield ['$someArg'];
yield ['string $someArg'];
}
public function testBindingsOnChildDefinitions()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('parent', ArgumentWithoutTypeController::class);
$container->setDefinition('child', (new ChildDefinition('parent'))
->setBindings(['$someArg' => new Reference('parent')])
->addTag('controller.service_arguments')
);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertInstanceOf(ServiceClosureArgument::class, $locator['child::fooAction']);
$locator = $container->getDefinition((string) $locator['child::fooAction']->getValues()[0])->getArgument(0);
$this->assertInstanceOf(ServiceClosureArgument::class, $locator['someArg']);
$this->assertEquals(new Reference('parent'), $locator['someArg']->getValues()[0]);
}
public function testNotTaggedControllerServiceReceivesLocatorArgument()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.not_tagged_controller')->addArgument([]);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locatorArgument = $container->getDefinition('argument_resolver.not_tagged_controller')->getArgument(0);
$this->assertInstanceOf(Reference::class, $locatorArgument);
}
}
class RegisterTestController
{
public function __construct(ControllerDummy $bar)
{
}
public function fooAction(ControllerDummy $bar)
{
}
protected function barAction(ControllerDummy $bar)
{
}
}
class ContainerAwareRegisterTestController implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function fooAction(ControllerDummy $bar)
{
}
}
class ControllerDummy
{
}
class NonExistentClassController
{
public function fooAction(NonExistentClass $nonExistent)
{
}
}
class NonExistentClassDifferentNamespaceController
{
public function fooAction(\Acme\NonExistentClass $nonExistent)
{
}
}
class NonExistentClassOptionalController
{
public function fooAction(NonExistentClass $nonExistent = null)
{
}
public function barAction(NonExistentClass $nonExistent = null, $bar)
{
}
}
class ArgumentWithoutTypeController
{
public function fooAction(string $someArg)
{
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterLocaleAwareServicesPass;
use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener;
use Symfony\Contracts\Translation\LocaleAwareInterface;
class RegisterLocaleAwareServicesPassTest extends TestCase
{
public function testCompilerPass()
{
$container = new ContainerBuilder();
$container->register('locale_aware_listener', LocaleAwareListener::class)
->setPublic(true)
->setArguments([null, null]);
$container->register('some_locale_aware_service', LocaleAwareInterface::class)
->setPublic(true)
->addTag('kernel.locale_aware');
$container->register('another_locale_aware_service', LocaleAwareInterface::class)
->setPublic(true)
->addTag('kernel.locale_aware');
$container->addCompilerPass(new RegisterLocaleAwareServicesPass());
$container->compile();
$this->assertEquals(
[
new IteratorArgument([
0 => new Reference('some_locale_aware_service'),
1 => new Reference('another_locale_aware_service'),
]),
null,
],
$container->getDefinition('locale_aware_listener')->getArguments()
);
}
public function testListenerUnregisteredWhenNoLocaleAwareServices()
{
$container = new ContainerBuilder();
$container->register('locale_aware_listener', LocaleAwareListener::class)
->setPublic(true)
->setArguments([null, null]);
$container->addCompilerPass(new RegisterLocaleAwareServicesPass());
$container->compile();
$this->assertFalse($container->hasDefinition('locale_aware_listener'));
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
use Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass;
class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
{
public function testProcess()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('stdClass', 'stdClass');
$container->register(TestCase::class, 'stdClass');
$container->register('c1', RemoveTestController1::class)->addTag('controller.service_arguments');
$container->register('c2', RemoveTestController2::class)->addTag('controller.service_arguments')
->addMethodCall('setTestCase', [new Reference('c1')]);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertCount(2, $container->getDefinition((string) $controllers['c1::fooAction']->getValues()[0])->getArgument(0));
$this->assertCount(1, $container->getDefinition((string) $controllers['c2::setTestCase']->getValues()[0])->getArgument(0));
$this->assertCount(1, $container->getDefinition((string) $controllers['c2::fooAction']->getValues()[0])->getArgument(0));
(new ResolveInvalidReferencesPass())->process($container);
$this->assertCount(1, $container->getDefinition((string) $controllers['c2::setTestCase']->getValues()[0])->getArgument(0));
$this->assertSame([], $container->getDefinition((string) $controllers['c2::fooAction']->getValues()[0])->getArgument(0));
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
$controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertSame(['c1::fooAction', 'c1:fooAction'], array_keys($controllers));
$this->assertSame(['bar'], array_keys($container->getDefinition((string) $controllers['c1::fooAction']->getValues()[0])->getArgument(0)));
$expectedLog = [
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument resolver for controller "c2::fooAction": no corresponding services exist for the referenced types.',
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.',
];
$this->assertSame($expectedLog, $container->getCompiler()->getLog());
}
public function testInvoke()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('invokable', InvokableRegisterTestController::class)
->addTag('controller.service_arguments')
;
(new RegisterControllerArgumentLocatorsPass())->process($container);
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
$this->assertEquals(
['invokable::__invoke', 'invokable:__invoke', 'invokable'],
array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0))
);
}
}
class RemoveTestController1
{
public function fooAction(\stdClass $bar, ClassNotInContainer $baz = null)
{
}
}
class RemoveTestController2
{
public function setTestCase(TestCase $test)
{
}
public function fooAction(ClassNotInContainer $bar = null)
{
}
}
class InvokableRegisterTestController
{
public function __invoke(\stdClass $bar)
{
}
}
class ClassNotInContainer
{
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class ResettableServicePassTest extends TestCase
{
public function testCompilerPass()
{
$container = new ContainerBuilder();
$container->register('one', ResettableService::class)
->setPublic(true)
->addTag('kernel.reset', ['method' => 'reset']);
$container->register('two', ClearableService::class)
->setPublic(true)
->addTag('kernel.reset', ['method' => 'clear']);
$container->register('services_resetter', ServicesResetter::class)
->setPublic(true)
->setArguments([null, []]);
$container->addCompilerPass(new ResettableServicePass());
$container->compile();
$definition = $container->getDefinition('services_resetter');
$this->assertEquals(
[
new IteratorArgument([
'one' => new Reference('one', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
'two' => new Reference('two', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
]),
[
'one' => 'reset',
'two' => 'clear',
],
],
$definition->getArguments()
);
}
public function testMissingMethod()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Tag kernel.reset requires the "method" attribute to be set.');
$container = new ContainerBuilder();
$container->register(ResettableService::class)
->addTag('kernel.reset');
$container->register('services_resetter', ServicesResetter::class)
->setArguments([null, []]);
$container->addCompilerPass(new ResettableServicePass());
$container->compile();
}
public function testCompilerPassWithoutResetters()
{
$container = new ContainerBuilder();
$container->register('services_resetter', ServicesResetter::class)
->setArguments([null, []]);
$container->addCompilerPass(new ResettableServicePass());
$container->compile();
$this->assertFalse($container->has('services_resetter'));
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class ServicesResetterTest extends TestCase
{
protected function setUp(): void
{
ResettableService::$counter = 0;
ClearableService::$counter = 0;
}
public function testResetServices()
{
$resetter = new ServicesResetter(new \ArrayIterator([
'id1' => new ResettableService(),
'id2' => new ClearableService(),
]), [
'id1' => 'reset',
'id2' => 'clear',
]);
$resetter->reset();
$this->assertEquals(1, ResettableService::$counter);
$this->assertEquals(1, ClearableService::$counter);
}
}