Skip to content

Commit 2cfcd68

Browse files
committed
add new Symfony factory syntax support
1 parent 779a2e6 commit 2cfcd68

9 files changed

+192
-15
lines changed

ArgumentsValidator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public function __construct(ArgumentValidatorInterface $argumentValidator)
1313
$this->argumentValidator = $argumentValidator;
1414
}
1515

16-
public function validate(\ReflectionMethod $method, array $arguments)
16+
public function validate(\ReflectionFunctionAbstract $method, array $arguments)
1717
{
1818
foreach ($method->getParameters() as $parameterNumber => $parameter) {
1919
if (array_key_exists($parameterNumber, $arguments)) {

ArgumentsValidatorInterface.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
interface ArgumentsValidatorInterface
66
{
7-
public function validate(\ReflectionMethod $method, array $arguments);
7+
public function validate(\ReflectionFunctionAbstract $method, array $arguments);
88
}

ConstructorResolver.php

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
namespace Matthias\SymfonyServiceDefinitionValidator;
44

55
use Matthias\SymfonyServiceDefinitionValidator\Exception\ClassNotFoundException;
6+
use Matthias\SymfonyServiceDefinitionValidator\Exception\FunctionNotFoundException;
67
use Matthias\SymfonyServiceDefinitionValidator\Exception\MethodNotFoundException;
78
use Matthias\SymfonyServiceDefinitionValidator\Exception\NonPublicConstructorException;
89
use Matthias\SymfonyServiceDefinitionValidator\Exception\NonStaticFactoryMethodException;
910
use Symfony\Component\DependencyInjection\ContainerBuilder;
1011
use Symfony\Component\DependencyInjection\Definition;
12+
use Symfony\Component\DependencyInjection\Reference;
1113

1214
class ConstructorResolver implements ConstructorResolverInterface
1315
{
@@ -24,7 +26,19 @@ public function __construct(
2426

2527
public function resolve(Definition $definition)
2628
{
27-
if ($definition->getFactoryClass() && $definition->getFactoryMethod()) {
29+
$factory = method_exists($definition, 'getFactory') ? $definition->getFactory() : null;
30+
31+
if (is_string($factory)) {
32+
if (!function_exists($factory)) {
33+
throw new FunctionNotFoundException($factory);
34+
}
35+
36+
return $factory;
37+
} elseif (is_array($factory) && $factory[0] instanceof Reference) {
38+
return $this->resolveFactoryServiceWithMethod($factory[0], $factory[1]);
39+
} elseif (is_array($factory)) {
40+
return $this->resolveFactoryClassWithMethod($factory[0], $factory[1]);
41+
} elseif ($definition->getFactoryClass() && $definition->getFactoryMethod()) {
2842
return $this->resolveFactoryClassWithMethod(
2943
$definition->getFactoryClass(),
3044
$definition->getFactoryMethod()
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Matthias\SymfonyServiceDefinitionValidator\Exception;
4+
5+
class FunctionNotFoundException extends \RuntimeException implements DefinitionValidationExceptionInterface
6+
{
7+
public function __construct($functionName)
8+
{
9+
parent::__construct(sprintf(
10+
'Function "%s" does not exist',
11+
$functionName
12+
));
13+
}
14+
}

Tests/ConstructorResolverTest.php

+130-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Matthias\SymfonyServiceDefinitionValidator\ResultingClassResolver;
77
use Symfony\Component\DependencyInjection\ContainerBuilder;
88
use Symfony\Component\DependencyInjection\Definition;
9+
use Symfony\Component\DependencyInjection\Reference;
910

1011
class ConstructorResolverTest extends \PHPUnit_Framework_TestCase
1112
{
@@ -55,55 +56,172 @@ public function ifConstructorIsNotPublicItFails()
5556

5657
/**
5758
* @test
59+
* @dataProvider getFactoryServiceAndFactoryMethodAreDefinedData
5860
*/
59-
public function ifFactoryClassAndFactoryMethodAreDefinedResolvedConstructorIsFactoryMethod()
61+
public function ifFactoryServiceAndFactoryMethodAreDefinedResolvedConstructorIsFactoryMethod($factoryClass, Definition $definition, \ReflectionMethod $expectedConstructor)
6062
{
6163
$containerBuilder = new ContainerBuilder();
64+
$containerBuilder->register('factory', $factoryClass);
6265
$resolver = new ConstructorResolver($containerBuilder, new ResultingClassResolver($containerBuilder));
6366

64-
$definition = new Definition();
67+
$this->assertEquals($expectedConstructor, $resolver->resolve($definition));
68+
}
69+
70+
public function getFactoryServiceAndFactoryMethodAreDefinedData()
71+
{
72+
$factoryService = 'factory';
6573
$factoryClass = 'Matthias\SymfonyServiceDefinitionValidator\Tests\Fixtures\FactoryClass';
66-
$definition->setFactoryClass($factoryClass);
6774
$factoryMethod = 'create';
75+
$expectedConstructor = new \ReflectionMethod($factoryClass, $factoryMethod);
76+
77+
$definition = new Definition();
78+
$definition->setFactoryService($factoryService);
6879
$definition->setFactoryMethod($factoryMethod);
6980

70-
$expectedConstructor = new \ReflectionMethod($factoryClass, $factoryMethod);
71-
$this->assertEquals($expectedConstructor, $resolver->resolve($definition));
81+
$data = array(array($factoryClass, $definition, $expectedConstructor));
82+
83+
if (method_exists($definition, 'setFactory')) {
84+
$definition = new Definition();
85+
$definition->setFactory(array(new Reference($factoryService), $factoryMethod));
86+
$data[] = array($factoryClass, $definition, $expectedConstructor);
87+
}
88+
89+
return $data;
7290
}
7391

7492
/**
7593
* @test
94+
* @dataProvider getFactoryClassAndFactoryMethodAreDefinedData
7695
*/
77-
public function ifFactoryClassDoesNotExistFails()
96+
public function ifFactoryClassAndFactoryMethodAreDefinedResolvedConstructorIsFactoryMethod(Definition $definition, \ReflectionMethod $expectedConstructor)
7897
{
7998
$containerBuilder = new ContainerBuilder();
8099
$resolver = new ConstructorResolver($containerBuilder, new ResultingClassResolver($containerBuilder));
81100

101+
$this->assertEquals($expectedConstructor, $resolver->resolve($definition));
102+
}
103+
104+
public function getFactoryClassAndFactoryMethodAreDefinedData()
105+
{
106+
$factoryClass = 'Matthias\SymfonyServiceDefinitionValidator\Tests\Fixtures\FactoryClass';
107+
$factoryMethod = 'create';
108+
$expectedConstructor = new \ReflectionMethod($factoryClass, $factoryMethod);
109+
82110
$definition = new Definition();
83-
$factoryClass = 'NonExistingClass';
84111
$definition->setFactoryClass($factoryClass);
85-
$factoryMethod = 'create';
86112
$definition->setFactoryMethod($factoryMethod);
87113

114+
$data = array(array($definition, $expectedConstructor));
115+
116+
if (method_exists($definition, 'setFactory')) {
117+
$definition = new Definition();
118+
$definition->setFactory(array($factoryClass, $factoryMethod));
119+
$data[] = array($definition, $expectedConstructor);
120+
}
121+
122+
return $data;
123+
}
124+
125+
/**
126+
* @test
127+
* @dataProvider getFactoryClassDoesNotExistData
128+
*/
129+
public function ifFactoryClassDoesNotExistFails(Definition $definition)
130+
{
131+
$containerBuilder = new ContainerBuilder();
132+
$resolver = new ConstructorResolver($containerBuilder, new ResultingClassResolver($containerBuilder));
133+
88134
$this->setExpectedException('Matthias\SymfonyServiceDefinitionValidator\Exception\ClassNotFoundException');
89135
$resolver->resolve($definition);
90136
}
91137

138+
public function getFactoryClassDoesNotExistData()
139+
{
140+
$factoryClass = 'NonExistingClass';
141+
$factoryMethod = 'create';
142+
143+
$definition = new Definition();
144+
$definition->setFactoryClass($factoryClass);
145+
$definition->setFactoryMethod($factoryMethod);
146+
147+
$data = array(array($definition));
148+
149+
if (method_exists($definition, 'setFactory')) {
150+
$definition = new Definition();
151+
$definition->setFactory(array($factoryClass, $factoryMethod));
152+
$data[] = array($definition);
153+
}
154+
155+
return $data;
156+
}
157+
92158
/**
93159
* @test
160+
* @dataProvider getFactoryMethodIsNotStaticData
94161
*/
95-
public function ifFactoryMethodIsNotStaticItFails()
162+
public function ifFactoryMethodIsNotStaticItFails(Definition $definition)
96163
{
97164
$containerBuilder = new ContainerBuilder();
98165
$resolver = new ConstructorResolver($containerBuilder, new ResultingClassResolver($containerBuilder));
99166

100-
$definition = new Definition();
167+
$this->setExpectedException('Matthias\SymfonyServiceDefinitionValidator\Exception\NonStaticFactoryMethodException');
168+
$resolver->resolve($definition);
169+
}
170+
171+
public function getFactoryMethodIsNotStaticData()
172+
{
101173
$factoryClass = 'Matthias\SymfonyServiceDefinitionValidator\Tests\Fixtures\FactoryClass';
102-
$definition->setFactoryClass($factoryClass);
103174
$factoryMethod = 'createNonStatic';
175+
176+
$definition = new Definition();
177+
$definition->setFactoryClass($factoryClass);
104178
$definition->setFactoryMethod($factoryMethod);
105179

106-
$this->setExpectedException('Matthias\SymfonyServiceDefinitionValidator\Exception\NonStaticFactoryMethodException');
180+
$data = array(array($definition));
181+
182+
if (method_exists($definition, 'setFactory')) {
183+
$definition = new Definition();
184+
$definition->setFactory(array($factoryClass, $factoryMethod));
185+
$data[] = array($definition);
186+
}
187+
188+
return $data;
189+
}
190+
191+
/**
192+
* @test
193+
*/
194+
public function ifFactoryIsStringIsFactoryCallback()
195+
{
196+
if (!method_exists('Symfony\Component\DependencyInjection\Definition', 'getFactory')) {
197+
$this->markTestSkipped('Support for callables as factories was introduced in Symfony 2.6');
198+
}
199+
200+
$containerBuilder = new ContainerBuilder();
201+
$resolver = new ConstructorResolver($containerBuilder, new ResultingClassResolver($containerBuilder));
202+
203+
$definition = new Definition();
204+
$definition->setFactory('factoryCallback');
205+
206+
$this->assertSame('factoryCallback', $resolver->resolve($definition));
207+
}
208+
209+
/**
210+
* @test
211+
*/
212+
public function ifFactoryFunctionDoesNotExistFails()
213+
{
214+
if (!method_exists('Symfony\Component\DependencyInjection\Definition', 'getFactory')) {
215+
$this->markTestSkipped('Support for callables as factories was introduced in Symfony 2.6');
216+
}
217+
218+
$containerBuilder = new ContainerBuilder();
219+
$resolver = new ConstructorResolver($containerBuilder, new ResultingClassResolver($containerBuilder));
220+
221+
$definition = new Definition();
222+
$definition->setFactory('NotExistingFactoryCallback');
223+
224+
$this->setExpectedException('Matthias\SymfonyServiceDefinitionValidator\Exception\FunctionNotFoundException');
107225
$resolver->resolve($definition);
108226
}
109227
}

Tests/Fixtures/FactoryCallback.php

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
function factoryCallback()
4+
{
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" ?>
2+
<container xmlns="http://symfony.com/schema/dic/services"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
5+
<services>
6+
<service id="service_with_factory"
7+
class="Matthias\SymfonyServiceDefinitionValidator\Tests\Functional\Fixtures\Mailer">
8+
<factory function="factoryCallback" />
9+
</service>
10+
</services>
11+
</container>

Tests/Functional/FunctionalTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ public function testIfAServiceDefinitionWithAnExpressionArgumentIsCorrectTheCont
5454
$this->container->compile();
5555
}
5656

57+
public function testIfAServiceDefinitionWithAFactoryIsCorrectTheContainerWillBeCompiled()
58+
{
59+
if (!method_exists('Symfony\Component\DependencyInjection\Definition', 'getFactory')) {
60+
$this->markTestSkipped('Support for callables as factories was introduced in Symfony 2.6');
61+
}
62+
63+
$loader = new XmlFileLoader($this->container, new FileLocator(__DIR__ . '/Fixtures'));
64+
$loader->load('service_definition_with_factory.xml');
65+
66+
$this->container->compile();
67+
}
68+
5769
public function testIfAServiceDefinitionIsNotCorrectAnExceptionWillBeThrown()
5870
{
5971
$loader = new XmlFileLoader($this->container, new FileLocator(__DIR__ . '/Fixtures'));

composer.json

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
"autoload": {
2424
"psr-4" : { "Matthias\\SymfonyServiceDefinitionValidator\\" : "" }
2525
},
26+
"autoload-dev": {
27+
"files": ["Tests/Fixtures/FactoryCallback.php"]
28+
},
2629
"extra": {
2730
"branch-alias": {
2831
"dev-master": "1.1.x-dev"

0 commit comments

Comments
 (0)