diff --git a/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/ContainerInjector.php b/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/ContainerInjector.php index 2cde53e..f1460cc 100644 --- a/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/ContainerInjector.php +++ b/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/ContainerInjector.php @@ -52,6 +52,12 @@ public function injectService(\ReflectionClass $class) return $this->doInject($class); } + /** + * Does the injection. + * + * @param \ReflectionClass $class + * @return String $service_Id: The services id´s. + */ protected function doInject(\ReflectionClass $class) { if($this->hasAnnotation(Injector::ANNOTATION_SERVICE)) @@ -158,6 +164,8 @@ protected function doInject(\ReflectionClass $class) */ protected function createDefinition(\ReflectionClass $class) { + $definition = null; + if(false !== ($parentClass = $class->getParentClass())) { $parent_service_id = $this->injectService($parentClass); diff --git a/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/MethodInjector.php b/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/MethodInjector.php index 40fa74d..1070037 100644 --- a/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/MethodInjector.php +++ b/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/MethodInjector.php @@ -92,7 +92,7 @@ public function guessArgumentsForMethodSignature(\ReflectionMethod $method) if($annotationsMap->hasHint($i)) { $is_optional = $annotationsMap->getIsOptional($i); - + $resource_name = $annotationsMap->getResourceName($i); // NO MATCHING SERVICE PARAMETER FOUND, CHECK FOR SCALAR VALUE @@ -104,7 +104,10 @@ public function guessArgumentsForMethodSignature(\ReflectionMethod $method) } catch(\InvalidArgumentException $e) { - throw new UnresolvedReferenceException(sprintf('Argument "$%s" on method "%s::%s()" could not be resolved: Service definition "%s" not found. Please provide a valid service id.', $parameter->getName(), $method->getDeclaringClass()->getName(), $method->getName(), $resource_name), null, $e); + if( ! $is_optional) + { + throw new UnresolvedReferenceException(sprintf('Argument "$%s" on method "%s::%s()" could not be resolved: Service definition "%s" not found. Please provide a valid service id.', $parameter->getName(), $method->getDeclaringClass()->getName(), $method->getName(), $resource_name), null, $e); + } } $arguments[] = $this->createReference($resource_name, $this->getBehaviour($parameter, $is_optional), true); @@ -153,17 +156,17 @@ public function guessArgumentsForMethodSignature(\ReflectionMethod $method) else { $service_id = $this->classnameMapper->resolveService($type->getName()); - - if (null === $service_id) - { - throw new UnresolvedReferenceException(sprintf('Argument "$%s" at method signature of "%s::%s()" could not be resolved: There is no service that matches the arguments typename. Please provide a valid service id.', $parameter->getName(), $method->getDeclaringClass()->getName(), $method->getName(), $type->getName())); - } - + if (false === $service_id) { throw new AmbiguousServiceReferenceException(sprintf('Argument "$%s" of type "%s" at method signature of "%s::%s()" could not be distinctly allocated: There is more than on services that rely on the given type. Please provide a valid, distinct service id.', $parameter->getName(), $type->getName(), $method->getDeclaringClass()->getName(), $method->getName())); } + if (null === $service_id && ! $parameter->isOptional()) + { + throw new UnresolvedReferenceException(sprintf('Argument "$%s" at method signature of "%s::%s()" could not be resolved: There is no service that matches the arguments typename. Please provide a valid service id.', $parameter->getName(), $method->getDeclaringClass()->getName(), $method->getName(), $type->getName())); + } + $arguments[] = $this->createReference($service_id, $this->getBehaviour($parameter), true); } } @@ -185,7 +188,7 @@ protected function getBehaviour(\ReflectionParameter $parameter, $is_optional = { if(null === $is_optional || $is_optional) { - if($parameter->isOptional() || $parameter->isDefaultValueAvailable()) + if($parameter->isOptional()) { return Container::IGNORE_ON_INVALID_REFERENCE; } diff --git a/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/PropertyInjector.php b/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/PropertyInjector.php index 021e5e7..17135cb 100644 --- a/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/PropertyInjector.php +++ b/src/Ifschleife/Bundle/AutowiringBundle/Autowiring/Injector/PropertyInjector.php @@ -139,20 +139,26 @@ protected function process(Definition $definition, \Reflector $property) } catch(\InvalidArgumentException $e) { - throw new UnresolvedReferenceException(sprintf('Instance property "%s::$%s" could not be resolved: Service definition "%s" not found. Please provide a valid service id.', $property->getDeclaringClass()->getName(), $property->getName(), $resource_name), null, $e); + if( ! $is_optional) + { + throw new UnresolvedReferenceException(sprintf('Instance property "%s::$%s" could not be resolved: Service definition "%s" not found. Please provide a valid service id.', $property->getDeclaringClass()->getName(), $property->getName(), $resource_name), null, $e); + } } $inject = $this->createReference($resource_name, $is_optional, true); } elseif($annotationMap->getIsParameter(0)) { - if($this->container->hasParameter($resource_name) && ! $is_optional) + if($this->container->hasParameter($resource_name)) { $inject = new Parameter($resource_name); } else { - throw new UnresolvedParamterException(sprintf('Instance property "%s::$%s" could not be resolved: Container parameter "%s" not found. Please provide a valid parameter name.', $property->getDeclaringClass()->getName(), $property->getName(), $resource_name)); + if( ! $is_optional) + { + throw new UnresolvedParamterException(sprintf('Instance property "%s::$%s" could not be resolved: Container parameter "%s" not found. Please provide a valid parameter name.', $property->getDeclaringClass()->getName(), $property->getName(), $resource_name)); + } } } diff --git a/src/Ifschleife/Bundle/AutowiringBundle/Tests/Autowiring/DependencyResolverTest.php b/src/Ifschleife/Bundle/AutowiringBundle/Tests/Autowiring/DependencyResolverTest.php index f6eebd0..d0efba4 100644 --- a/src/Ifschleife/Bundle/AutowiringBundle/Tests/Autowiring/DependencyResolverTest.php +++ b/src/Ifschleife/Bundle/AutowiringBundle/Tests/Autowiring/DependencyResolverTest.php @@ -233,6 +233,119 @@ public function testDependencyResolving(array $files) ); } + /** + * + */ + public function failOptionalArguments() + { + $container = new \Symfony\Component\DependencyInjection\ContainerBuilder(); + + $reader = new \Ifschleife\Bundle\AutowiringBundle\Annotation\AnnotationReaderDecorator; + + $serviceBuilder = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\ServiceBuilder( + new \Ifschleife\Bundle\AutowiringBundle\DependencyInjection\Loader\AnnotatedFileLoader( + $container, + new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\ContainerInjector($container, + $reader + ), + new \Symfony\Component\Config\FileLocator(), + new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Parser\PhpParser() + )); + + $serviceBuilder->setFiles(array(__DIR__ . '/../Fixtures/OptionalInjectionFailclass.php')); + + $serviceBuilder->build(); + + $classnameMapper = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\ClassnameMapper($container); + + $propertyInjector = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\PropertyInjector($container, $reader); + $propertyInjector->setWireByName(true); + $propertyInjector->setServiceNameSuffix('Service'); + + $constructorInjector = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\ConstructorInjector($container, $reader, $classnameMapper); + $constructorInjector->setWireByType(true); + + $setterInjector = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\SetterInjector($container, $reader, $classnameMapper); + $setterInjector->setWireByType(true); + + // ContainerBuilder $container, ClassnameMapper $classname_mapper, PropertyInjector $property_injector, ConstructorInjector $constructor_injector, SetterInjector $setter_injector + $dependencyResolver = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\DependencyResolver( + $container, + $classnameMapper, + $propertyInjector, + $constructorInjector, + $setterInjector + ); + + try + { + $dependencyResolver->resolve(); + } + catch(Exception $e) + { + $this->assertInstanceOf('Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\UnresolvedReferenceException', $e); + } + + } + + /** + * @dataProvider optionalFiles + */ + public function testOptionalArguments($file) + { + $container = new \Symfony\Component\DependencyInjection\ContainerBuilder(); + + $reader = new \Ifschleife\Bundle\AutowiringBundle\Annotation\AnnotationReaderDecorator; + + $serviceBuilder = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\ServiceBuilder( + new \Ifschleife\Bundle\AutowiringBundle\DependencyInjection\Loader\AnnotatedFileLoader( + $container, + new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\ContainerInjector($container, + $reader + ), + new \Symfony\Component\Config\FileLocator(), + new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Parser\PhpParser() + )); + + $serviceBuilder->setFiles(array($file)); + + $serviceBuilder->build(); + + $classnameMapper = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\ClassnameMapper($container); + + $propertyInjector = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\PropertyInjector($container, $reader); + $propertyInjector->setWireByName(true); + $propertyInjector->setServiceNameSuffix('Service'); + + $constructorInjector = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\ConstructorInjector($container, $reader, $classnameMapper); + $constructorInjector->setWireByType(true); + + $setterInjector = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\Injector\SetterInjector($container, $reader, $classnameMapper); + $setterInjector->setWireByType(true); + + // ContainerBuilder $container, ClassnameMapper $classname_mapper, PropertyInjector $property_injector, ConstructorInjector $constructor_injector, SetterInjector $setter_injector + $dependencyResolver = new \Ifschleife\Bundle\AutowiringBundle\Autowiring\DependencyResolver( + $container, + $classnameMapper, + $propertyInjector, + $constructorInjector, + $setterInjector + ); + + $dependencyResolver->resolve(); + + $this->assertInstanceOf('Ifschleife\Bundle\AutowiringBundle\Tests\Fixtures\OptionalInjectionTestclass', $container->get('autowiring.optional_injection_testclass')); + } + + function optionalFiles() + { + return array( + array( + __DIR__ . '/../Fixtures/OptionalInjectionTestclass.php' + ) + ); + } + function files() { return array( diff --git a/src/Ifschleife/Bundle/AutowiringBundle/Tests/Fixtures/OptionalInjectionFailclass.php b/src/Ifschleife/Bundle/AutowiringBundle/Tests/Fixtures/OptionalInjectionFailclass.php new file mode 100644 index 0000000..53edae1 --- /dev/null +++ b/src/Ifschleife/Bundle/AutowiringBundle/Tests/Fixtures/OptionalInjectionFailclass.php @@ -0,0 +1,45 @@ + + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Ifschleife\Bundle\AutowiringBundle\Tests\Fixtures; + +use Ifschleife\Bundle\AutowiringBundle\Annotations\Service; +use Ifschleife\Bundle\AutowiringBundle\Annotations\Inject; + +/** + * OptionalInjectionTestclass + * + * @author joshi + * @Service("autowiring.optional_injection_testclass") + */ +class OptionalInjectionFailclass +{ + /** + * @param Testservice $testservice + * @Inject + */ + public function __construct(Testservice $testservice) + { + + } +} diff --git a/src/Ifschleife/Bundle/AutowiringBundle/Tests/Fixtures/OptionalInjectionTestclass.php b/src/Ifschleife/Bundle/AutowiringBundle/Tests/Fixtures/OptionalInjectionTestclass.php new file mode 100644 index 0000000..1faf4f2 --- /dev/null +++ b/src/Ifschleife/Bundle/AutowiringBundle/Tests/Fixtures/OptionalInjectionTestclass.php @@ -0,0 +1,69 @@ + + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Ifschleife\Bundle\AutowiringBundle\Tests\Fixtures; + +use Ifschleife\Bundle\AutowiringBundle\Annotations\Service; +use Ifschleife\Bundle\AutowiringBundle\Annotations\Inject; + +/** + * OptionalInjectionTestclass + * + * @author joshi + * @Service("autowiring.optional_injection_testclass") + */ +class OptionalInjectionTestclass +{ + /** + * @Inject("@?does.not.exist") + */ + protected $testService; + + /** + * @param Testservice $testservice + * @Inject + */ + public function __construct(Testservice $testservice = null) + { + + } + + /** + * + * @param Testservice $testservice + * @Inject + */ + public function setOptionalService(Testservice $testservice = null) + { + + } + + /** + * @param Testservice $testservice + * @Inject("@?Does.Not.Exist") + */ + public function setOptionalService2(Testservice $testservice = null) + { + + } +}