[+FEATURE] Extbase: Enable Dependency Injection for Domain Models
authorBastian Waidelich <bastian@typo3.org>
Tue, 8 Mar 2011 17:45:21 +0000 (18:45 +0100)
committerBastian Waidelich <bastian@typo3.org>
Tue, 8 Mar 2011 17:45:21 +0000 (18:45 +0100)
In order to avoid the constructor to be called,
domain objects are created by using PHPs unserialize() function.
This has the side-effect, that we need to inject
dependencies "manually" for those.
This is accomplished by adding a helper function
getEmptyObject() to the Object Container.
Thanks to Pascal Jungblut for the patches!

Change-Id: I49edab54eb810abc894f3f59fe8c46cf4ddfa464
Fixes: #11311

typo3/sysext/extbase/Classes/Object/Container/Container.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapFactory.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapper.php
typo3/sysext/extbase/Classes/Property/Mapper.php
typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php

index fe1ffe3..1e3a15d 100644 (file)
@@ -96,6 +96,21 @@ class Tx_Extbase_Object_Container_Container implements t3lib_Singleton {
        }
 
        /**
+        * Create an instance of $className without calling its constructor
+        *
+        * @param string $className
+        * @return object
+        */
+       public function getEmptyObject($className) {
+               $className = $this->getImplementationClassName($className);
+               $classInfo = $this->getClassInfo($className);
+               // get an object and avoid calling __construct()
+               $object = unserialize('O:' . strlen($className) . ':"' . $className . '":0:{};');
+               $this->injectDependencies($object, $classInfo);
+               return $object;
+       }
+
+       /**
         * Internal implementation for getting a class.
         *
         * @param string $className
index b6629b8..af264c3 100644 (file)
@@ -42,6 +42,13 @@ class Tx_Extbase_Persistence_Mapper_DataMapFactory implements t3lib_Singleton {
        protected $configurationManager;
 
        /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+
+
+       /**
         * Injects the reflection service
         *
         * @param Tx_Extbase_Reflection_Service $reflectionService
@@ -60,6 +67,14 @@ class Tx_Extbase_Persistence_Mapper_DataMapFactory implements t3lib_Singleton {
        }
 
        /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
         * Builds a data map by adding column maps for all the configured columns in the $TCA.
         * It also resolves the type of values the column is holding and the typo of relation the column
         * represents.
@@ -103,7 +118,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapFactory implements t3lib_Singleton {
                        }
                }
 
-               $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap($className, $tableName, $recordType, $subclasses);
+               $dataMap = $this->objectManager->create('Tx_Extbase_Persistence_Mapper_DataMap', $className, $tableName, $recordType, $subclasses);
                $dataMap = $this->addMetaDataColumnNames($dataMap, $tableName);
 
                // $classPropertyNames = $this->reflectionService->getClassPropertyNames($className);
index 24ebc91..ea8171e 100644 (file)
@@ -88,6 +88,11 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        protected $objectManager;
 
        /**
+        * @var Tx_Extbase_Object_Container_Container
+        */
+       protected $objectContainer;
+
+       /**
         * Injects the identity map
         *
         * @param Tx_Extbase_Persistence_IdentityMap $identityMap
@@ -155,6 +160,14 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        }
 
        /**
+        * @param Tx_Extbase_Object_Container_Container $objectContainer
+        * @return void
+        */
+       public function injectObjectContainer(Tx_Extbase_Object_Container_Container $objectContainer) {
+               $this->objectContainer = $objectContainer;
+       }
+
+       /**
         * Maps the given rows on objects
         *
         * @param string $className The name of the class
@@ -221,7 +234,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                // Note: The class_implements() function also invokes autoload to assure that the interfaces
                // and the class are loaded. Would end up with __PHP_Incomplete_Class without it.
                if (!in_array('Tx_Extbase_DomainObject_DomainObjectInterface', class_implements($className))) throw new Tx_Extbase_Object_Exception_CannotReconstituteObject('Cannot create empty instance of the class "' . $className . '" because it does not implement the Tx_Extbase_DomainObject_DomainObjectInterface.', 1234386924);
-               $object = unserialize('O:' . strlen($className) . ':"' . $className . '":0:{};');
+               $object = $this->objectContainer->getEmptyObject($className);
                return $object;
        }
 
index 211c50a..ed09b2c 100644 (file)
@@ -74,6 +74,11 @@ class Tx_Extbase_Property_Mapper implements t3lib_Singleton {
        protected $persistenceManager;
 
        /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
         * @var Tx_Extbase_Persistence_QueryFactory
         */
        protected $queryFactory;
@@ -104,9 +109,7 @@ class Tx_Extbase_Property_Mapper implements t3lib_Singleton {
        }
 
        /**
-        * Injects the Reflection Service
-        *
-        * @param Tx_Extbase_Reflection_Service
+        * @param Tx_Extbase_Reflection_Service $reflectionService
         * @return void
         */
        public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
@@ -114,6 +117,14 @@ class Tx_Extbase_Property_Mapper implements t3lib_Singleton {
        }
 
        /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
         * Maps the given properties to the target object and validates the properties according to the defined
         * validators. If the result object is not valid, the operation will be undone (the target object remains
         * unchanged) and this method returns FALSE.
@@ -267,7 +278,7 @@ class Tx_Extbase_Property_Mapper implements t3lib_Singleton {
                                $propertyValue = NULL;
                        } else {
                                try {
-                                       $propertyValue = new $targetType($propertyValue);
+                                       $propertyValue = $this->objectManager->create($targetType, $propertyValue);
                                } catch (Exception $e) {
                                        $propertyValue = NULL;
                                }
@@ -294,7 +305,7 @@ class Tx_Extbase_Property_Mapper implements t3lib_Singleton {
                                                }
                                        }
                                } else {
-                                       $newObject = new $targetType;
+                                       $newObject = $this->objectManager->create($targetType);
                                        if ($this->map(array_keys($propertyValue), $propertyValue, $newObject)) {
                                                $propertyValue = $newObject;
                                        } else {
index 6716ea7..8ddd91d 100644 (file)
@@ -160,6 +160,14 @@ class Tx_Extbase_Tests_Unit_Object_Container_ContainerTest extends Tx_Extbase_Te
        /**
         * @test
         */
+       public function getEmptyObjectReturnsInstanceOfSimpleClass() {
+               $object = $this->container->getEmptyObject('t3lib_object_tests_c');
+               $this->assertType('t3lib_object_tests_c', $object);
+       }
+
+       /**
+        * @test
+        */
        public function test_canGetChildClass() {
                $object = $this->container->getInstance('t3lib_object_tests_b_child');
                $this->assertType('t3lib_object_tests_b_child', $object);