[BUGFIX] Omit constructor injection for optional parameters 28/24128/15
authorAnja Leichsenring <aleichsenring@ab-softlab.de>
Sat, 28 Sep 2013 15:38:22 +0000 (17:38 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Thu, 10 Oct 2013 10:58:17 +0000 (12:58 +0200)
ObjectManager tries to resolve and, in case of objects, inject all
constructor parameters, no matter what the calling function passes
to the constructor.

If the constructor value is optional, and no value or NULL is given
to the call, no constructor injection must take place for this parameter.

Change-Id: I646e6928cbadb486b1e2734efbe1ea5fbd953765
Resolves: #52349
Releases: 6.2
Reviewed-on: https://review.typo3.org/24128
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
typo3/sysext/extbase/Classes/Object/Container/ClassInfoFactory.php
typo3/sysext/extbase/Classes/Object/Container/Container.php
typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php
typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerConstructorInjectionTestFixtures.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/NamespaceTestclasses.php [deleted file]

index cb51ebb..530b271 100644 (file)
@@ -77,9 +77,11 @@ class ClassInfoFactory {
                        if ($reflectionParameter->getClass()) {
                                $info['dependency'] = $reflectionParameter->getClass()->getName();
                        }
-                       if ($reflectionParameter->isOptional()) {
+
+                       try {
                                $info['defaultValue'] = $reflectionParameter->getDefaultValue();
-                       }
+                       } catch (\ReflectionException $e) {}
+
                        $result[] = $info;
                }
                return $result;
index 24aa53e..c1225fe 100644 (file)
@@ -27,6 +27,7 @@ namespace TYPO3\CMS\Extbase\Object\Container;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
 /**
  * Internal TYPO3 Dependency Injection container
  *
@@ -270,29 +271,21 @@ class Container implements \TYPO3\CMS\Core\SingletonInterface {
        private function getConstructorArguments($className, \TYPO3\CMS\Extbase\Object\Container\ClassInfo $classInfo, array $givenConstructorArguments) {
                $parameters = array();
                $constructorArgumentInformation = $classInfo->getConstructorArguments();
-               foreach ($constructorArgumentInformation as $argumentInformation) {
-                       // We have a dependency we can automatically wire,
-                       // AND the class has NOT been explicitely passed in
-                       if (isset($argumentInformation['dependency']) && !(count($givenConstructorArguments) && is_a($givenConstructorArguments[0], $argumentInformation['dependency']))) {
-                               // Inject parameter
-                               $parameter = $this->getInstanceInternal($argumentInformation['dependency']);
-                               if ($classInfo->getIsSingleton() && !$parameter instanceof \TYPO3\CMS\Core\SingletonInterface) {
-                                       $this->log('The singleton "' . $className . '" needs a prototype in the constructor. This is often a bad code smell; often you rather want to inject a singleton.', 1);
-                               }
-                       } elseif (count($givenConstructorArguments)) {
-                               // EITHER:
-                               // No dependency injectable anymore, but we still have
-                               // an explicit constructor argument
-                               // OR:
-                               // the passed constructor argument matches the type for the dependency
-                               // injection, and thus the passed constructor takes precendence over
-                               // autowiring.
-                               $parameter = array_shift($givenConstructorArguments);
-                       } elseif (array_key_exists('defaultValue', $argumentInformation)) {
-                               // no value to set anymore, we take default value
-                               $parameter = $argumentInformation['defaultValue'];
+               foreach ($constructorArgumentInformation as $index => $argumentInformation) {
+                       // Constructor argument given AND argument is a simple type OR instance of argument type
+                       if (array_key_exists($index, $givenConstructorArguments) && (!isset($argumentInformation['dependency']) || is_a($givenConstructorArguments[$index], $argumentInformation['dependency']))) {
+                               $parameter = $givenConstructorArguments[$index];
                        } else {
-                               throw new \InvalidArgumentException('not a correct info array of constructor dependencies was passed!');
+                               if (isset($argumentInformation['dependency']) && !array_key_exists('defaultValue', $argumentInformation)) {
+                                       $parameter = $this->getInstanceInternal($argumentInformation['dependency']);
+                                       if ($classInfo->getIsSingleton() && !$parameter instanceof \TYPO3\CMS\Core\SingletonInterface) {
+                                               $this->log('The singleton "' . $className . '" needs a prototype in the constructor. This is often a bad code smell; often you rather want to inject a singleton.', 1);
+                                       }
+                               } elseif (array_key_exists('defaultValue', $argumentInformation)) {
+                                       $parameter = $argumentInformation['defaultValue'];
+                               } else {
+                                       throw new \InvalidArgumentException('not a correct info array of constructor dependencies was passed!');
+                               }
                        }
                        $parameters[] = $parameter;
                }
index 3972cf2..c7b23ad 100644 (file)
@@ -23,8 +23,9 @@ namespace TYPO3\CMS\Extbase\Tests\Unit\Object\Container;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
-require_once \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('extbase') . 'Tests/Unit/Object/Container/Fixtures/Testclasses.php';
-require_once \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('extbase') . 'Tests/Unit/Object/Container/Fixtures/NamespaceTestclasses.php';
+
+require_once 'Fixtures/Testclasses.php';
+require_once 'Fixtures/ContainerConstructorInjectionTestFixtures.php';
 
 /**
  * Testcase for class t3lib_object_Container.
@@ -326,4 +327,588 @@ class ContainerTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $this->assertFalse($this->container->isPrototype('TYPO3\CMS\Extbase\Object\Container\Container'));
                $this->assertTrue($this->container->isPrototype('TYPO3\CMS\Extbase\Core\Bootstrap'));
        }
+
+       /************************************************
+        * Test regarding constructor argument injection
+        ************************************************/
+
+       /**
+        * test class SimpleTypeConstructorArgument
+        * @test
+        */
+       public function getInstanceGivesSimpleConstructorArgumentToClassInstance() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\SimpleTypeConstructorArgument',
+                       array(TRUE)
+               );
+               $this->assertTrue($object->foo);
+       }
+
+       /**
+        * test class SimpleTypeConstructorArgument
+        * @test
+        */
+       public function getInstanceDoesNotInfluenceSimpleTypeConstructorArgumentIfNotGiven() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\SimpleTypeConstructorArgument'
+               );
+               $this->assertFalse($object->foo);
+       }
+
+       /**
+        * test class MandatoryConstructorArgument
+        * @test
+        */
+       public function getInstanceGivesExistingConstructorArgumentToClassInstance() {
+               $argumentTestClass = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgument',
+                       array($argumentTestClass)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgument',
+                       $object
+               );
+               $this->assertSame($argumentTestClass, $object->argumentTestClass);
+       }
+
+       /**
+        * test class MandatoryConstructorArgument
+        * @test
+        */
+       public function getInstanceInjectsNewInstanceOfClassToClassIfArgumentIsMandatory() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgument'
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgument',
+                       $object
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClass
+               );
+       }
+
+       /**
+        * test class OptionalConstructorArgument
+        * @test
+        */
+       public function getInstanceDoesNotInjectAnOptionalArgumentIfNotGiven() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\OptionalConstructorArgument'
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\OptionalConstructorArgument',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+       }
+
+       /**
+        * test class OptionalConstructorArgument
+        * @test
+        */
+       public function getInstanceDoesNotInjectAnOptionalArgumentIfGivenArgumentIsNull() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\OptionalConstructorArgument',
+                       array(NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\OptionalConstructorArgument',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+       }
+
+       /**
+        * test class OptionalConstructorArgument
+        * @test
+        */
+       public function getInstanceGivesExistingConstructorArgumentToClassInstanceIfArgumentIsGiven() {
+               $argumentTestClass = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\OptionalConstructorArgument',
+                       array($argumentTestClass)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\OptionalConstructorArgument',
+                       $object
+               );
+               $this->assertSame($argumentTestClass, $object->argumentTestClass);
+       }
+
+       /**
+        * test class MandatoryConstructorArgumentTwo
+        * @test
+        */
+       public function getInstanceGivesTwoArgumentsToClassConstructor() {
+               $firstArgument = new Fixtures\ArgumentTestClass();
+               $secondArgument = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       array($firstArgument, $secondArgument)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       $object
+               );
+               $this->assertSame(
+                       $firstArgument,
+                       $object->argumentTestClass
+               );
+               $this->assertSame(
+                       $secondArgument,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class MandatoryConstructorArgumentTwo
+        * @test
+        */
+       public function getInstanceInjectsTwoMandatoryArguments() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo'
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       $object
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClass
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+               $this->assertNotSame(
+                       $object->argumentTestClass,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class MandatoryConstructorArgumentTwo
+        * @test
+        */
+       public function getInstanceInjectsSecondMandatoryArgumentIfFirstIsGiven() {
+               $firstArgument = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       array($firstArgument)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       $object
+               );
+               $this->assertSame(
+                       $firstArgument,
+                       $object->argumentTestClass
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+               $this->assertNotSame(
+                       $object->argumentTestClass,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class MandatoryConstructorArgumentTwo
+        * @test
+        */
+       public function getInstanceInjectsFirstMandatoryArgumentIfSecondIsGiven() {
+               $secondArgument = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       array(NULL, $secondArgument)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\MandatoryConstructorArgumentTwo',
+                       $object
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClass
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+               $this->assertSame(
+                       $secondArgument,
+                       $object->argumentTestClassTwo
+               );
+               $this->assertNotSame(
+                       $object->argumentTestClass,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsSecondOptional
+        * @test
+        */
+       public function getInstanceGivesTwoArgumentsToClassConstructorIfSecondIsOptional() {
+               $firstArgument = new Fixtures\ArgumentTestClass();
+               $secondArgument = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       array($firstArgument, $secondArgument)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $firstArgument,
+                       $object->argumentTestClass
+               );
+               $this->assertSame(
+                       $secondArgument,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsSecondOptional
+        * @test
+        */
+       public function getInstanceInjectsFirstMandatoryArgumentIfSecondIsOptionalAndNoneAreGiven() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional'
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       $object
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClass
+               );
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsSecondOptional
+        * @test
+        */
+       public function getInstanceInjectsFirstMandatoryArgumentIfSecondIsOptionalAndBothAreGivenAsNull() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       array(NULL, NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       $object
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClass
+               );
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsSecondOptional
+        * @test
+        */
+       public function getInstanceGivesFirstArgumentToConstructorIfSecondIsOptionalAndFirstIsGiven() {
+               $firstArgument = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       array($firstArgument)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $firstArgument,
+                       $object->argumentTestClass
+               );
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsSecondOptional
+        * @test
+        */
+       public function getInstanceGivesFirstArgumentToConstructorIfSecondIsOptionalFirstIsGivenAndSecondIsGivenNull() {
+               $firstArgument = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       array($firstArgument, NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsSecondOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $firstArgument,
+                       $object->argumentTestClass
+               );
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsFirstOptional
+        *
+        * @test
+        */
+       public function getInstanceOnFirstOptionalAndSecondMandatoryInjectsOnlySecondArgumentAndFirstArgumentIsNullIfNoArgumentsGiven() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional'
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsFirstOptional
+        *
+        * @test
+        */
+       public function getInstanceOnFirstOptionalAndSecondMandatoryInjectsSecondArgumentIfFirstIsGivenAsNull() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       array(NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsFirstOptional
+        * @test
+        */
+       public function getInstanceOnFirstOptionalAndSecondMandatoryGivesTwoGivenArgumentsToConstructor() {
+               $first = new Fixtures\ArgumentTestClass();
+               $second = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       array($first, $second)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $first,
+                       $object->argumentTestClass
+               );
+               $this->assertSame(
+                       $second,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsFirstOptional
+        * @test
+        */
+       public function getInstanceOnFirstOptionalAndSecondMandatoryInjectsSecondArgumentIfFirstIsGiven() {
+               $first = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       array($first)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $first,
+                       $object->argumentTestClass
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+               $this->assertNotSame(
+                       $object->argumentTestClass,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsFirstOptional
+        *
+        * @test
+        */
+       public function getInstanceOnFirstOptionalAndSecondMandatoryGivesSecondArgumentAsIsIfFirstIsGivenAsNullAndSecondIsGiven() {
+               $second = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       array(NULL, $second)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertSame(
+                       $second,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsFirstOptional
+        *
+        * @test
+        */
+       public function getInstanceOnFirstOptionalAndSecondMandatoryInjectsSecondArgumentIfFirstIsGivenAsNullAndSecondIsNull() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       array(NULL, NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsFirstOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\ArgumentTestClass',
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsBothOptional
+        * @test
+        */
+       public function getInstanceOnTwoOptionalGivesTwoGivenArgumentsToConstructor() {
+               $first = new Fixtures\ArgumentTestClass();
+               $second = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       array($first, $second)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $first,
+                       $object->argumentTestClass
+               );
+               $this->assertSame(
+                       $second,
+                       $object->argumentTestClassTwo
+               );
+       }
+
+       /**
+        * test class TwoConstructorArgumentsBothOptional
+        * @test
+        */
+       public function getInstanceOnTwoOptionalGivesNoArgumentsToConstructorIfArgumentsAreNull() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       array(NULL, NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsBothOptional
+        * @test
+        */
+       public function getInstanceOnTwoOptionalGivesNoArgumentsToConstructorIfNoneAreGiven() {
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional');
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsBothOptional
+        * @test
+        */
+       public function getInstanceOnTwoOptionalGivesOneArgumentToConstructorIfFirstIsObjectAndSecondIsNotGiven() {
+               $first = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       array($first)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $first,
+                       $object->argumentTestClass
+               );
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsBothOptional
+        * @test
+        */
+       public function getInstanceOnTwoOptionalGivesOneArgumentToConstructorIfFirstIsObjectAndSecondIsNull() {
+               $first = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       array($first, NULL)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       $object
+               );
+               $this->assertSame(
+                       $first,
+                       $object->argumentTestClass
+               );
+               $this->assertNull($object->argumentTestClassTwo);
+       }
+
+       /**
+        * test class TwoConstructorArgumentsBothOptional
+        * @test
+        */
+       public function getInstanceOnTwoOptionalGivesOneArgumentToConstructorIfFirstIsNullAndSecondIsObject() {
+               $second = new Fixtures\ArgumentTestClass();
+               $object = $this->container->getInstance(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       array(NULL, $second)
+               );
+               $this->assertInstanceOf(
+                       'TYPO3\\CMS\\Extbase\\Tests\\Unit\\Object\\Container\\Fixtures\\TwoConstructorArgumentsBothOptional',
+                       $object
+               );
+               $this->assertNull($object->argumentTestClass);
+               $this->assertSame(
+                       $second,
+                       $object->argumentTestClassTwo
+               );
+       }
 }
diff --git a/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerConstructorInjectionTestFixtures.php b/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerConstructorInjectionTestFixtures.php
new file mode 100644 (file)
index 0000000..62c2f18
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures;
+
+
+class SimpleTypeConstructorArgument {
+
+       /**
+        * @var boolean
+        */
+       public $foo;
+
+       /**
+        * @param boolean $foo
+        */
+       public function __construct($foo = FALSE) {
+               $this->foo = $foo;
+       }
+}
+
+
+class ArgumentTestClass {
+
+}
+
+
+class MandatoryConstructorArgument {
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClass;
+
+       public $allArguments;
+
+       /**
+        * @param ArgumentTestClass $argumentTestClass
+        */
+       public function __construct(ArgumentTestClass $argumentTestClass) {
+               $this->argumentTestClass = $argumentTestClass;
+               $this->allArguments = func_get_args();
+       }
+}
+
+
+class OptionalConstructorArgument {
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClass;
+
+       /**
+        * @param ArgumentTestClass $argumentTestClass
+        */
+       public function __construct(ArgumentTestClass $argumentTestClass = NULL) {
+               $this->argumentTestClass = $argumentTestClass;
+       }
+}
+
+
+class MandatoryConstructorArgumentTwo {
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClass;
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClassTwo;
+
+       /**
+        * @param ArgumentTestClass $argumentTestClass
+        * @param ArgumentTestClass $argumentTestClassTwo
+        */
+       public function __construct(ArgumentTestClass $argumentTestClass, ArgumentTestClass $argumentTestClassTwo) {
+               $this->argumentTestClass = $argumentTestClass;
+               $this->argumentTestClassTwo = $argumentTestClassTwo;
+       }
+}
+
+
+class TwoConstructorArgumentsSecondOptional {
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClass;
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClassTwo;
+
+       /**
+        * @param ArgumentTestClass $argumentTestClass
+        * @param ArgumentTestClass $argumentTestClassTwo
+        */
+       public function __construct(ArgumentTestClass $argumentTestClass, ArgumentTestClass $argumentTestClassTwo = NULL) {
+               $this->argumentTestClass = $argumentTestClass;
+               $this->argumentTestClassTwo = $argumentTestClassTwo;
+       }
+}
+
+
+class TwoConstructorArgumentsFirstOptional {
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClass;
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClassTwo;
+
+       /**
+        * This can not be handled correctly at the moment since the underlying
+        * reflection API of PHP marks the first parameter as required!
+        *
+        * @param ArgumentTestClass $argumentTestClass
+        * @param ArgumentTestClass $argumentTestClassTwo
+        */
+       public function __construct(ArgumentTestClass $argumentTestClass = NULL, ArgumentTestClass $argumentTestClassTwo) {
+               $this->argumentTestClass = $argumentTestClass;
+               $this->argumentTestClassTwo = $argumentTestClassTwo;
+       }
+}
+
+
+class TwoConstructorArgumentsBothOptional {
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClass;
+
+       /**
+        * @var ArgumentTestClass
+        */
+       public $argumentTestClassTwo;
+
+       /**
+        * @param ArgumentTestClass $argumentTestClass
+        * @param ArgumentTestClass $argumentTestClassTwo
+        */
+       public function __construct(ArgumentTestClass $argumentTestClass = NULL, ArgumentTestClass $argumentTestClassTwo = NULL) {
+               $this->argumentTestClass = $argumentTestClass;
+               $this->argumentTestClassTwo = $argumentTestClassTwo;
+       }
+}
diff --git a/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/NamespaceTestclasses.php b/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/NamespaceTestclasses.php
deleted file mode 100644 (file)
index d60bd35..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-namespace Tx\Extbase\Object\Container\Fixtures;