2015-08-24 02:36:41 +01:00
< ? 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\DependencyInjection\Tests\Compiler ;
2017-02-18 17:42:54 +00:00
use PHPUnit\Framework\TestCase ;
2015-08-24 02:36:41 +01:00
use Symfony\Component\DependencyInjection\Compiler\AutowirePass ;
use Symfony\Component\DependencyInjection\ContainerBuilder ;
2017-03-19 11:22:02 +00:00
use Symfony\Component\DependencyInjection\Definition ;
2017-03-17 09:21:51 +00:00
use Symfony\Component\DependencyInjection\Exception\RuntimeException ;
2015-08-24 02:36:41 +01:00
use Symfony\Component\DependencyInjection\Reference ;
2017-01-22 14:49:28 +00:00
use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic ;
2017-02-26 17:31:03 +00:00
use Symfony\Component\DependencyInjection\TypedReference ;
2015-08-24 02:36:41 +01:00
/**
* @ author Kévin Dunglas < dunglas @ gmail . com >
*/
2017-02-18 17:42:54 +00:00
class AutowirePassTest extends TestCase
2015-08-24 02:36:41 +01:00
{
public function testProcess ()
{
$container = new ContainerBuilder ();
$container -> register ( 'foo' , __NAMESPACE__ . '\Foo' );
$barDefinition = $container -> register ( 'bar' , __NAMESPACE__ . '\Bar' );
$barDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 1 , $container -> getDefinition ( 'bar' ) -> getArguments ());
$this -> assertEquals ( 'foo' , ( string ) $container -> getDefinition ( 'bar' ) -> getArgument ( 0 ));
}
2017-01-22 14:49:28 +00:00
/**
* @ requires PHP 5.6
*/
public function testProcessVariadic ()
{
$container = new ContainerBuilder ();
$container -> register ( 'foo' , Foo :: class );
$definition = $container -> register ( 'fooVariadic' , FooVariadic :: class );
$definition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 1 , $container -> getDefinition ( 'fooVariadic' ) -> getArguments ());
$this -> assertEquals ( 'foo' , ( string ) $container -> getDefinition ( 'fooVariadic' ) -> getArgument ( 0 ));
}
2015-08-24 02:36:41 +01:00
public function testProcessAutowireParent ()
{
$container = new ContainerBuilder ();
$container -> register ( 'b' , __NAMESPACE__ . '\B' );
$cDefinition = $container -> register ( 'c' , __NAMESPACE__ . '\C' );
$cDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 1 , $container -> getDefinition ( 'c' ) -> getArguments ());
$this -> assertEquals ( 'b' , ( string ) $container -> getDefinition ( 'c' ) -> getArgument ( 0 ));
}
public function testProcessAutowireInterface ()
{
$container = new ContainerBuilder ();
$container -> register ( 'f' , __NAMESPACE__ . '\F' );
$gDefinition = $container -> register ( 'g' , __NAMESPACE__ . '\G' );
$gDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
2016-02-23 09:13:51 +00:00
$this -> assertCount ( 3 , $container -> getDefinition ( 'g' ) -> getArguments ());
2015-08-24 02:36:41 +01:00
$this -> assertEquals ( 'f' , ( string ) $container -> getDefinition ( 'g' ) -> getArgument ( 0 ));
$this -> assertEquals ( 'f' , ( string ) $container -> getDefinition ( 'g' ) -> getArgument ( 1 ));
2016-02-23 09:13:51 +00:00
$this -> assertEquals ( 'f' , ( string ) $container -> getDefinition ( 'g' ) -> getArgument ( 2 ));
2015-08-24 02:36:41 +01:00
}
public function testCompleteExistingDefinition ()
{
$container = new ContainerBuilder ();
$container -> register ( 'b' , __NAMESPACE__ . '\B' );
$container -> register ( 'f' , __NAMESPACE__ . '\F' );
$hDefinition = $container -> register ( 'h' , __NAMESPACE__ . '\H' ) -> addArgument ( new Reference ( 'b' ));
$hDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 2 , $container -> getDefinition ( 'h' ) -> getArguments ());
$this -> assertEquals ( 'b' , ( string ) $container -> getDefinition ( 'h' ) -> getArgument ( 0 ));
$this -> assertEquals ( 'f' , ( string ) $container -> getDefinition ( 'h' ) -> getArgument ( 1 ));
}
public function testCompleteExistingDefinitionWithNotDefinedArguments ()
{
$container = new ContainerBuilder ();
$container -> register ( 'b' , __NAMESPACE__ . '\B' );
$container -> register ( 'f' , __NAMESPACE__ . '\F' );
$hDefinition = $container -> register ( 'h' , __NAMESPACE__ . '\H' ) -> addArgument ( '' ) -> addArgument ( '' );
$hDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 2 , $container -> getDefinition ( 'h' ) -> getArguments ());
$this -> assertEquals ( 'b' , ( string ) $container -> getDefinition ( 'h' ) -> getArgument ( 0 ));
$this -> assertEquals ( 'f' , ( string ) $container -> getDefinition ( 'h' ) -> getArgument ( 1 ));
}
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " a " : multiple candidate services exist for interface " Symfony \ Component \ DependencyInjection \T ests \ Compiler \ CollisionInterface " . This type - hint could be aliased to one of these existing services : " c1 " , " c2 " , " c3 " .
2015-08-24 02:36:41 +01:00
*/
public function testTypeCollision ()
{
$container = new ContainerBuilder ();
$container -> register ( 'c1' , __NAMESPACE__ . '\CollisionA' );
$container -> register ( 'c2' , __NAMESPACE__ . '\CollisionB' );
2016-03-06 22:03:14 +00:00
$container -> register ( 'c3' , __NAMESPACE__ . '\CollisionB' );
2015-08-24 02:36:41 +01:00
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\CannotBeAutowired' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2015-11-23 22:18:49 +00:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " a " : multiple candidate services exist for class " Symfony\Component\DependencyInjection\Tests\Compiler\Foo " . This type-hint could be aliased to one of these existing services: " a1 " , " a2 " .
2015-11-23 22:18:49 +00:00
*/
public function testTypeNotGuessable ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a1' , __NAMESPACE__ . '\Foo' );
$container -> register ( 'a2' , __NAMESPACE__ . '\Foo' );
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\NotGuessableArgument' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " a " : multiple candidate services exist for class " Symfony\Component\DependencyInjection\Tests\Compiler\A " . This type-hint could be aliased to one of these existing services: " a1 " , " a2 " .
2015-11-23 22:18:49 +00:00
*/
public function testTypeNotGuessableWithSubclass ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a1' , __NAMESPACE__ . '\B' );
$container -> register ( 'a2' , __NAMESPACE__ . '\B' );
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\NotGuessableArgumentForSubclass' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2016-02-22 00:27:26 +00:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " a " : no services were found matching the " Symfony \ Component \ DependencyInjection \T ests \ Compiler \ CollisionInterface " interface and it cannot be auto - registered for argument $collision of method Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired :: __construct () .
2016-02-22 00:27:26 +00:00
*/
public function testTypeNotGuessableNoServicesFound ()
{
$container = new ContainerBuilder ();
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\CannotBeAutowired' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2015-11-23 22:18:49 +00:00
public function testTypeNotGuessableWithTypeSet ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a1' , __NAMESPACE__ . '\Foo' );
2017-02-19 11:32:55 +00:00
$container -> register ( 'a2' , __NAMESPACE__ . '\Foo' );
2017-02-01 11:51:46 +00:00
$container -> register ( Foo :: class , Foo :: class );
2015-11-23 22:18:49 +00:00
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\NotGuessableArgument' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 1 , $container -> getDefinition ( 'a' ) -> getArguments ());
2017-02-01 11:51:46 +00:00
$this -> assertEquals ( Foo :: class , ( string ) $container -> getDefinition ( 'a' ) -> getArgument ( 0 ));
2015-11-23 22:18:49 +00:00
}
2015-08-24 02:36:41 +01:00
public function testWithTypeSet ()
{
$container = new ContainerBuilder ();
$container -> register ( 'c1' , __NAMESPACE__ . '\CollisionA' );
2017-02-01 11:51:46 +00:00
$container -> register ( 'c2' , __NAMESPACE__ . '\CollisionB' );
$container -> setAlias ( CollisionInterface :: class , 'c2' );
2015-08-24 02:36:41 +01:00
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\CannotBeAutowired' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 1 , $container -> getDefinition ( 'a' ) -> getArguments ());
2017-02-01 11:51:46 +00:00
$this -> assertEquals ( CollisionInterface :: class , ( string ) $container -> getDefinition ( 'a' ) -> getArgument ( 0 ));
2015-08-24 02:36:41 +01:00
}
public function testCreateDefinition ()
{
$container = new ContainerBuilder ();
$coopTilleulsDefinition = $container -> register ( 'coop_tilleuls' , __NAMESPACE__ . '\LesTilleuls' );
$coopTilleulsDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 1 , $container -> getDefinition ( 'coop_tilleuls' ) -> getArguments ());
2017-01-10 07:04:52 +00:00
$this -> assertEquals ( 'autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas' , $container -> getDefinition ( 'coop_tilleuls' ) -> getArgument ( 0 ));
2015-08-24 02:36:41 +01:00
2017-01-10 13:59:43 +00:00
$dunglasDefinition = $container -> getDefinition ( 'autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas' );
2015-08-24 02:36:41 +01:00
$this -> assertEquals ( __NAMESPACE__ . '\Dunglas' , $dunglasDefinition -> getClass ());
$this -> assertFalse ( $dunglasDefinition -> isPublic ());
$this -> assertCount ( 1 , $dunglasDefinition -> getArguments ());
2017-01-10 07:04:52 +00:00
$this -> assertEquals ( 'autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille' , $dunglasDefinition -> getArgument ( 0 ));
2015-08-24 02:36:41 +01:00
2017-01-10 13:59:43 +00:00
$lilleDefinition = $container -> getDefinition ( 'autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille' );
2015-08-24 02:36:41 +01:00
$this -> assertEquals ( __NAMESPACE__ . '\Lille' , $lilleDefinition -> getClass ());
}
public function testResolveParameter ()
{
$container = new ContainerBuilder ();
$container -> setParameter ( 'class_name' , __NAMESPACE__ . '\Foo' );
$container -> register ( 'foo' , '%class_name%' );
$barDefinition = $container -> register ( 'bar' , __NAMESPACE__ . '\Bar' );
$barDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertEquals ( 'foo' , $container -> getDefinition ( 'bar' ) -> getArgument ( 0 ));
}
public function testOptionalParameter ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'foo' , __NAMESPACE__ . '\Foo' );
$optDefinition = $container -> register ( 'opt' , __NAMESPACE__ . '\OptionalParameter' );
$optDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$definition = $container -> getDefinition ( 'opt' );
$this -> assertNull ( $definition -> getArgument ( 0 ));
$this -> assertEquals ( 'a' , $definition -> getArgument ( 1 ));
$this -> assertEquals ( 'foo' , $definition -> getArgument ( 2 ));
}
2015-11-03 19:42:49 +00:00
public function testDontTriggerAutowiring ()
2015-08-24 02:36:41 +01:00
{
$container = new ContainerBuilder ();
$container -> register ( 'foo' , __NAMESPACE__ . '\Foo' );
$container -> register ( 'bar' , __NAMESPACE__ . '\Bar' );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertCount ( 0 , $container -> getDefinition ( 'bar' ) -> getArguments ());
}
2015-11-04 18:04:11 +00:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " a " : argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument :: __construct () has type " Symfony \ Component \ DependencyInjection \T ests \ Compiler \N otARealClass " but this class does not exist .
2015-11-04 18:04:11 +00:00
*/
public function testClassNotFoundThrowsException ()
{
$container = new ContainerBuilder ();
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\BadTypeHintedArgument' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2015-11-04 00:40:26 +00:00
2016-04-20 13:06:08 +01:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " a " : argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument :: __construct () has type " Symfony \ Component \ DependencyInjection \T ests \ Compiler \ OptionalServiceClass " but this class does not exist .
2016-04-20 13:06:08 +01:00
*/
public function testParentClassNotFoundThrowsException ()
{
$container = new ContainerBuilder ();
$aDefinition = $container -> register ( 'a' , __NAMESPACE__ . '\BadParentTypeHintedArgument' );
$aDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2015-11-04 00:40:26 +00:00
public function testDontUseAbstractServices ()
{
$container = new ContainerBuilder ();
$container -> register ( 'abstract_foo' , __NAMESPACE__ . '\Foo' ) -> setAbstract ( true );
$container -> register ( 'foo' , __NAMESPACE__ . '\Foo' );
$container -> register ( 'bar' , __NAMESPACE__ . '\Bar' ) -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$arguments = $container -> getDefinition ( 'bar' ) -> getArguments ();
$this -> assertSame ( 'foo' , ( string ) $arguments [ 0 ]);
}
2016-02-21 23:51:49 +00:00
public function testSomeSpecificArgumentsAreSet ()
{
$container = new ContainerBuilder ();
$container -> register ( 'foo' , __NAMESPACE__ . '\Foo' );
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'dunglas' , __NAMESPACE__ . '\Dunglas' );
$container -> register ( 'multiple' , __NAMESPACE__ . '\MultipleArguments' )
-> setAutowired ( true )
// set the 2nd (index 1) argument only: autowire the first and third
// args are: A, Foo, Dunglas
-> setArguments ( array (
1 => new Reference ( 'foo' ),
));
$pass = new AutowirePass ();
$pass -> process ( $container );
$definition = $container -> getDefinition ( 'multiple' );
$this -> assertEquals (
array (
new Reference ( 'a' ),
new Reference ( 'foo' ),
new Reference ( 'dunglas' ),
),
$definition -> getArguments ()
);
}
2016-02-22 01:17:09 +00:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-01-25 12:02:51 +00:00
* @ expectedExceptionMessage Cannot autowire service " arg_no_type_hint " : argument $foo of method Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments :: __construct () must have a type - hint or be given a value explicitly .
2016-02-22 01:17:09 +00:00
*/
public function testScalarArgsCannotBeAutowired ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'dunglas' , __NAMESPACE__ . '\Dunglas' );
$container -> register ( 'arg_no_type_hint' , __NAMESPACE__ . '\MultipleArguments' )
-> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$container -> getDefinition ( 'arg_no_type_hint' );
}
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-01-25 12:02:51 +00:00
* @ expectedExceptionMessage Cannot autowire service " not_really_optional_scalar " : argument $foo of method Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArgumentsOptionalScalarNotReallyOptional :: __construct () must have a type - hint or be given a value explicitly .
2016-02-22 01:17:09 +00:00
*/
public function testOptionalScalarNotReallyOptionalThrowException ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'lille' , __NAMESPACE__ . '\Lille' );
$container -> register ( 'not_really_optional_scalar' , __NAMESPACE__ . '\MultipleArgumentsOptionalScalarNotReallyOptional' )
-> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
public function testOptionalScalarArgsDontMessUpOrder ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'lille' , __NAMESPACE__ . '\Lille' );
$container -> register ( 'with_optional_scalar' , __NAMESPACE__ . '\MultipleArgumentsOptionalScalar' )
-> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$definition = $container -> getDefinition ( 'with_optional_scalar' );
$this -> assertEquals (
array (
new Reference ( 'a' ),
// use the default value
'default_val' ,
new Reference ( 'lille' ),
),
$definition -> getArguments ()
);
}
public function testOptionalScalarArgsNotPassedIfLast ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'lille' , __NAMESPACE__ . '\Lille' );
$container -> register ( 'with_optional_scalar_last' , __NAMESPACE__ . '\MultipleArgumentsOptionalScalarLast' )
-> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$definition = $container -> getDefinition ( 'with_optional_scalar_last' );
$this -> assertEquals (
array (
new Reference ( 'a' ),
new Reference ( 'lille' ),
),
$definition -> getArguments ()
);
}
2016-03-12 20:10:13 +00:00
2016-10-05 21:46:29 +01:00
public function testSetterInjection ()
{
$container = new ContainerBuilder ();
$container -> register ( 'app_foo' , Foo :: class );
$container -> register ( 'app_a' , A :: class );
$container -> register ( 'app_collision_a' , CollisionA :: class );
$container -> register ( 'app_collision_b' , CollisionB :: class );
// manually configure *one* call, to override autowiring
$container
-> register ( 'setter_injection' , SetterInjection :: class )
2017-02-25 16:12:16 +00:00
-> setAutowired ( true )
2016-10-05 21:46:29 +01:00
-> addMethodCall ( 'setWithCallsConfigured' , array ( 'manual_arg1' , 'manual_arg2' ))
;
$pass = new AutowirePass ();
$pass -> process ( $container );
$methodCalls = $container -> getDefinition ( 'setter_injection' ) -> getMethodCalls ();
$this -> assertEquals (
2017-03-01 21:48:20 +00:00
array ( 'setWithCallsConfigured' , 'setFoo' , 'setDependencies' , 'setChildMethodWithoutDocBlock' ),
2017-02-25 16:12:16 +00:00
array_column ( $methodCalls , 0 )
2016-10-05 21:46:29 +01:00
);
// test setWithCallsConfigured args
$this -> assertEquals (
array ( 'manual_arg1' , 'manual_arg2' ),
$methodCalls [ 0 ][ 1 ]
);
// test setFoo args
$this -> assertEquals (
array ( new Reference ( 'app_foo' )),
$methodCalls [ 1 ][ 1 ]
);
}
public function testExplicitMethodInjection ()
{
$container = new ContainerBuilder ();
$container -> register ( 'app_foo' , Foo :: class );
$container -> register ( 'app_a' , A :: class );
$container -> register ( 'app_collision_a' , CollisionA :: class );
$container -> register ( 'app_collision_b' , CollisionB :: class );
$container
-> register ( 'setter_injection' , SetterInjection :: class )
2017-02-25 16:12:16 +00:00
-> setAutowired ( true )
-> addMethodCall ( 'notASetter' , array ())
2016-10-05 21:46:29 +01:00
;
$pass = new AutowirePass ();
$pass -> process ( $container );
$methodCalls = $container -> getDefinition ( 'setter_injection' ) -> getMethodCalls ();
$this -> assertEquals (
2017-03-01 21:48:20 +00:00
array ( 'notASetter' , 'setFoo' , 'setDependencies' , 'setWithCallsConfigured' , 'setChildMethodWithoutDocBlock' ),
2017-02-25 16:12:16 +00:00
array_column ( $methodCalls , 0 )
);
$this -> assertEquals (
array ( new Reference ( 'app_a' )),
$methodCalls [ 0 ][ 1 ]
2016-10-05 21:46:29 +01:00
);
}
2017-03-05 22:31:39 +00:00
public function testTypedReference ()
2017-02-26 17:31:03 +00:00
{
$container = new ContainerBuilder ();
$container
-> register ( 'bar' , Bar :: class )
-> setAutowired ( true )
-> setProperty ( 'a' , array ( new TypedReference ( A :: class , A :: class )))
;
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertSame ( A :: class , $container -> getDefinition ( 'autowired.' . A :: class ) -> getClass ());
}
2016-03-12 20:10:13 +00:00
/**
* @ dataProvider getCreateResourceTests
2017-01-26 15:09:57 +00:00
* @ group legacy
2016-03-12 20:10:13 +00:00
*/
public function testCreateResourceForClass ( $className , $isEqual )
{
$startingResource = AutowirePass :: createResourceForClass (
new \ReflectionClass ( __NAMESPACE__ . '\ClassForResource' )
);
$newResource = AutowirePass :: createResourceForClass (
new \ReflectionClass ( __NAMESPACE__ . '\\' . $className )
);
// hack so the objects don't differ by the class name
$startingReflObject = new \ReflectionObject ( $startingResource );
$reflProp = $startingReflObject -> getProperty ( 'class' );
$reflProp -> setAccessible ( true );
$reflProp -> setValue ( $startingResource , __NAMESPACE__ . '\\' . $className );
if ( $isEqual ) {
$this -> assertEquals ( $startingResource , $newResource );
} else {
$this -> assertNotEquals ( $startingResource , $newResource );
}
}
public function getCreateResourceTests ()
{
return array (
2016-06-21 07:03:42 +01:00
array ( 'IdenticalClassResource' , true ),
array ( 'ClassChangedConstructorArgs' , false ),
2016-03-12 20:10:13 +00:00
);
}
2016-04-25 12:21:08 +01:00
2016-03-31 13:26:29 +01:00
public function testIgnoreServiceWithClassNotExisting ()
{
$container = new ContainerBuilder ();
$container -> register ( 'class_not_exist' , __NAMESPACE__ . '\OptionalServiceClass' );
$barDefinition = $container -> register ( 'bar' , __NAMESPACE__ . '\Bar' );
$barDefinition -> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertTrue ( $container -> hasDefinition ( 'bar' ));
}
2016-10-05 21:46:29 +01:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-03-23 22:53:25 +00:00
* @ expectedExceptionMessage Cannot autowire service " setter_injection_collision " : multiple candidate services exist for interface " Symfony \ Component \ DependencyInjection \T ests \ Compiler \ CollisionInterface " . This type - hint could be aliased to one of these existing services : " c1 " , " c2 " .
2016-10-05 21:46:29 +01:00
*/
public function testSetterInjectionCollisionThrowsException ()
{
$container = new ContainerBuilder ();
$container -> register ( 'c1' , CollisionA :: class );
$container -> register ( 'c2' , CollisionB :: class );
$aDefinition = $container -> register ( 'setter_injection_collision' , SetterInjectionCollision :: class );
2017-02-25 16:12:16 +00:00
$aDefinition -> setAutowired ( true );
2016-10-05 21:46:29 +01:00
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2017-01-25 12:02:51 +00:00
2017-01-25 12:10:29 +00:00
public function testEmptyStringIsKept ()
{
$container = new ContainerBuilder ();
$container -> register ( 'a' , __NAMESPACE__ . '\A' );
$container -> register ( 'lille' , __NAMESPACE__ . '\Lille' );
$container -> register ( 'foo' , __NAMESPACE__ . '\MultipleArgumentsOptionalScalar' )
-> setAutowired ( true )
-> setArguments ( array ( '' , '' ));
2017-01-25 12:02:51 +00:00
$pass = new AutowirePass ();
$pass -> process ( $container );
2017-01-25 12:10:29 +00:00
$this -> assertEquals ( array ( new Reference ( 'a' ), '' , new Reference ( 'lille' )), $container -> getDefinition ( 'foo' ) -> getArguments ());
2017-01-25 12:02:51 +00:00
}
2017-02-18 11:21:50 +00:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
2017-04-04 08:47:41 +01:00
* @ expectedExceptionMessage Service " a " can use either autowiring or a factory , not both .
2017-02-18 11:21:50 +00:00
*/
2017-04-04 08:47:41 +01:00
public function testWithFactory ()
2017-02-18 11:21:50 +00:00
{
$container = new ContainerBuilder ();
2017-04-04 08:47:41 +01:00
$container -> register ( 'a' , __NAMESPACE__ . '\A' )
-> setFactory ( 'foo' )
2017-02-18 11:21:50 +00:00
-> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2017-03-17 09:21:51 +00:00
/**
* @ dataProvider provideNotWireableCalls
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
*/
public function testNotWireableCalls ( $method , $expectedMsg )
{
$container = new ContainerBuilder ();
$foo = $container -> register ( 'foo' , NotWireable :: class ) -> setAutowired ( true );
if ( $method ) {
$foo -> addMethodCall ( $method , array ());
}
$pass = new AutowirePass ();
if ( method_exists ( $this , 'expectException' )) {
$this -> expectException ( RuntimeException :: class );
$this -> expectExceptionMessage ( $expectedMsg );
} else {
$this -> setExpectedException ( RuntimeException :: class , $expectedMsg );
}
$pass -> process ( $container );
}
public function provideNotWireableCalls ()
{
return array (
2017-03-23 22:53:25 +00:00
array ( 'setNotAutowireable' , 'Cannot autowire service "foo": argument $n of method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable() has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.' ),
2017-03-17 09:21:51 +00:00
array ( 'setBar' , 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setBar() has only optional arguments, thus must be wired explicitly.' ),
array ( 'setOptionalNotAutowireable' , 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setOptionalNotAutowireable() has only optional arguments, thus must be wired explicitly.' ),
array ( 'setOptionalNoTypeHint' , 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setOptionalNoTypeHint() has only optional arguments, thus must be wired explicitly.' ),
array ( 'setOptionalArgNoAutowireable' , 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setOptionalArgNoAutowireable() has only optional arguments, thus must be wired explicitly.' ),
array ( null , 'Cannot autowire service "foo": method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod() must be public.' ),
);
}
2017-03-21 15:17:00 +00:00
2017-03-23 22:53:25 +00:00
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @ expectedExceptionMessage Cannot autowire service " j " : multiple candidate services exist for class " Symfony\Component\DependencyInjection\Tests\Compiler\I " . This type-hint could be aliased to one of these existing services: " f " , " i " ; or be updated to " Symfony\Component\DependencyInjection\Tests\Compiler\IInterface " .
*/
public function testAlternatives ()
{
$container = new ContainerBuilder ();
$container -> setAlias ( IInterface :: class , 'i' );
$container -> register ( 'f' , F :: class );
$container -> register ( 'i' , I :: class );
$container -> register ( 'j' , J :: class )
-> setAutowired ( true );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2017-03-19 11:22:02 +00:00
public function testById ()
{
$container = new ContainerBuilder ();
$container -> register ( A :: class , A :: class );
$container -> register ( DInterface :: class , F :: class );
$container -> register ( 'd' , D :: class )
-> setAutowired ( Definition :: AUTOWIRE_BY_ID );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertSame ( array ( 'service_container' , A :: class , DInterface :: class , 'd' ), array_keys ( $container -> getDefinitions ()));
$this -> assertEquals ( array ( new Reference ( A :: class ), new Reference ( DInterface :: class )), $container -> getDefinition ( 'd' ) -> getArguments ());
}
public function testByIdDoesNotAutoregister ()
{
$container = new ContainerBuilder ();
$container -> register ( 'f' , F :: class );
$container -> register ( 'e' , E :: class )
-> setAutowired ( Definition :: AUTOWIRE_BY_ID );
$pass = new AutowirePass ();
$pass -> process ( $container );
$this -> assertSame ( array ( 'service_container' , 'f' , 'e' ), array_keys ( $container -> getDefinitions ()));
}
/**
* @ expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @ expectedExceptionMessage Cannot autowire service " j " : argument $i of method Symfony\Component\DependencyInjection\Tests\Compiler\J :: __construct () references class " Symfony\Component\DependencyInjection\Tests\Compiler\I " but no such service exists. This type-hint could be aliased to the existing " i " service; or be updated to " Symfony\Component\DependencyInjection\Tests\Compiler\IInterface " .
*/
public function testByIdAlternative ()
{
$container = new ContainerBuilder ();
$container -> setAlias ( IInterface :: class , 'i' );
$container -> register ( 'i' , I :: class );
$container -> register ( 'j' , J :: class )
-> setAutowired ( Definition :: AUTOWIRE_BY_ID );
$pass = new AutowirePass ();
$pass -> process ( $container );
}
2015-08-24 02:36:41 +01:00
}
class Foo
{
}
class Bar
{
public function __construct ( Foo $foo )
{
}
}
class A
{
}
class B extends A
{
}
class C
{
public function __construct ( A $a )
{
}
}
interface DInterface
{
}
interface EInterface extends DInterface
{
}
2016-02-23 09:13:51 +00:00
interface IInterface
{
}
class I implements IInterface
{
}
class F extends I implements EInterface
2015-08-24 02:36:41 +01:00
{
}
class G
{
2016-02-23 09:13:51 +00:00
public function __construct ( DInterface $d , EInterface $e , IInterface $i )
2015-08-24 02:36:41 +01:00
{
}
}
class H
{
public function __construct ( B $b , DInterface $d )
{
}
}
2017-03-21 15:17:00 +00:00
class D
{
public function __construct ( A $a , DInterface $d )
{
}
}
class E
{
public function __construct ( D $d = null )
{
}
}
2017-03-23 22:53:25 +00:00
class J
{
public function __construct ( I $i )
{
}
}
2015-08-24 02:36:41 +01:00
interface CollisionInterface
{
}
class CollisionA implements CollisionInterface
{
}
class CollisionB implements CollisionInterface
{
}
class CannotBeAutowired
{
public function __construct ( CollisionInterface $collision )
{
}
}
2017-02-18 11:21:50 +00:00
class CannotBeAutowiredForwardOrder
{
public function __construct ( CollisionA $a , CollisionInterface $b , CollisionB $c )
{
}
}
class CannotBeAutowiredReverseOrder
{
public function __construct ( CollisionA $a , CollisionB $c , CollisionInterface $b )
{
}
}
2015-08-24 02:36:41 +01:00
class Lille
{
}
class Dunglas
{
public function __construct ( Lille $l )
{
}
}
class LesTilleuls
{
public function __construct ( Dunglas $k )
{
}
}
class OptionalParameter
{
public function __construct ( CollisionInterface $c = null , A $a , Foo $f = null )
{
}
}
2015-11-04 18:04:11 +00:00
class BadTypeHintedArgument
{
public function __construct ( Dunglas $k , NotARealClass $r )
{
}
}
2016-04-20 13:06:08 +01:00
class BadParentTypeHintedArgument
{
public function __construct ( Dunglas $k , OptionalServiceClass $r )
{
}
}
2015-11-23 22:18:49 +00:00
class NotGuessableArgument
{
public function __construct ( Foo $k )
{
}
}
class NotGuessableArgumentForSubclass
{
public function __construct ( A $k )
{
}
}
2016-02-21 23:51:49 +00:00
class MultipleArguments
{
public function __construct ( A $k , $foo , Dunglas $dunglas )
{
}
2016-02-22 01:17:09 +00:00
}
class MultipleArgumentsOptionalScalar
{
public function __construct ( A $a , $foo = 'default_val' , Lille $lille = null )
{
}
}
class MultipleArgumentsOptionalScalarLast
{
public function __construct ( A $a , Lille $lille , $foo = 'some_val' )
{
}
}
class MultipleArgumentsOptionalScalarNotReallyOptional
{
public function __construct ( A $a , $foo = 'default_val' , Lille $lille )
{
}
2016-02-29 00:33:45 +00:00
}
2016-03-12 20:10:13 +00:00
/*
* Classes used for testing createResourceForClass
*/
class ClassForResource
{
public function __construct ( $foo , Bar $bar = null )
{
}
public function setBar ( Bar $bar )
{
}
}
class IdenticalClassResource extends ClassForResource
{
}
2016-10-05 21:46:29 +01:00
2016-03-12 20:10:13 +00:00
class ClassChangedConstructorArgs extends ClassForResource
{
public function __construct ( $foo , Bar $bar , $baz )
{
}
}
2016-10-05 21:46:29 +01:00
2017-02-25 16:12:16 +00:00
class SetterInjection extends SetterInjectionParent
2016-10-05 21:46:29 +01:00
{
2017-02-25 16:12:16 +00:00
/**
* @ required
*/
2016-10-05 21:46:29 +01:00
public function setFoo ( Foo $foo )
{
// should be called
}
2017-02-25 16:12:16 +00:00
/** @inheritdoc*/
2016-10-05 21:46:29 +01:00
public function setDependencies ( Foo $foo , A $a )
{
// should be called
}
2017-02-25 16:12:16 +00:00
/** {@inheritdoc} */
2016-10-05 21:46:29 +01:00
public function setWithCallsConfigured ( A $a )
{
// this method has a calls configured on it
}
public function notASetter ( A $a )
{
// should be called only when explicitly specified
}
2016-12-23 12:58:16 +00:00
2017-03-17 09:21:51 +00:00
/**
* @ required */
2017-03-01 21:48:20 +00:00
public function setChildMethodWithoutDocBlock ( A $a )
{
}
2016-10-05 21:46:29 +01:00
}
2017-02-25 16:12:16 +00:00
class SetterInjectionParent
{
/** @required*/
public function setDependencies ( Foo $foo , A $a )
{
// should be called
}
public function notASetter ( A $a )
{
// @required should be ignored when the child does not add @inheritdoc
}
2017-03-17 09:21:51 +00:00
/** @required <tab> prefix is on purpose */
2017-02-25 16:12:16 +00:00
public function setWithCallsConfigured ( A $a )
{
}
2017-03-01 21:48:20 +00:00
/** @required */
public function setChildMethodWithoutDocBlock ( A $a )
{
}
2017-02-25 16:12:16 +00:00
}
2016-10-05 21:46:29 +01:00
class SetterInjectionCollision
{
2017-02-25 16:12:16 +00:00
/**
* @ required
*/
2016-10-05 21:46:29 +01:00
public function setMultipleInstancesForOneArg ( CollisionInterface $collision )
{
// The CollisionInterface cannot be autowired - there are multiple
// should throw an exception
}
}
2017-03-17 09:21:51 +00:00
class NotWireable
{
public function setNotAutowireable ( NotARealClass $n )
{
}
public function setBar ()
{
}
public function setOptionalNotAutowireable ( NotARealClass $n = null )
{
}
public function setOptionalNoTypeHint ( $foo = null )
{
}
public function setOptionalArgNoAutowireable ( $other = 'default_val' )
{
}
/** @required */
protected function setProtectedMethod ( A $a )
{
}
}