[BUGFIX] Respect all subclasses (single table inheritance)
authorDennis Ahrens <dennis.ahrens@fh-hannover.de>
Tue, 10 Apr 2012 11:07:32 +0000 (13:07 +0200)
committerDennis Ahrens <dennis.ahrens@fh-hannover.de>
Wed, 11 Apr 2012 16:05:43 +0000 (18:05 +0200)
If you ask a repository that have subclasses, that have subsubclasses,
than just the subclasses of the first level get respected and not the
subsubclasses.

Change-Id: I62b0219316a7f1fbc49cba6909d317b0a237bbe8
Fixes: #35855
Releases: 4.8, 4.7, 1.4, 1.3

typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapFactory.php
typo3/sysext/extbase/Tests/Unit/Persistence/Mapper/DataMapFactoryTest.php

index 1a577c5..9d86d60 100644 (file)
@@ -96,7 +96,9 @@ class Tx_Extbase_Persistence_Mapper_DataMapFactory implements t3lib_Singleton {
                $classSettings = $frameworkConfiguration['persistence']['classes'][$className];
                if ($classSettings !== NULL) {
                        if (isset($classSettings['subclasses']) && is_array($classSettings['subclasses'])) {
-                               $subclasses = $classSettings['subclasses'];
+                               $subclasses = $this->resolveSubclassesRecursive(
+                                       $frameworkConfiguration['persistence']['classes'], $classSettings['subclasses']
+                               );
                        }
                        if (isset($classSettings['mapping']['recordType']) && strlen($classSettings['mapping']['recordType']) > 0) {
                                $recordType = $classSettings['mapping']['recordType'];
@@ -142,6 +144,28 @@ class Tx_Extbase_Persistence_Mapper_DataMapFactory implements t3lib_Singleton {
        }
 
        /**
+        * Resolves all subclasses for the given set of (sub-)classes.
+        * The whole classes configuration is used to determine all subclasses recursively.
+        *
+        * @param array $classes The framework configuration part [persistence][classes].
+        * @param array $subclasses An array of subclasses defined via TypoScript
+        * @return array An numeric array that contains all available subclasses-strings as values.
+        */
+       protected function resolveSubclassesRecursive(array $classesConfiguration, array $subclasses) {
+               $allSubclasses = array();
+
+               foreach ($subclasses as $subclass) {
+                       $allSubclasses[] = $subclass;
+                       if (isset($classesConfiguration[$subclass]['subclasses']) && is_array($classesConfiguration[$subclass]['subclasses'])) {
+                               $childSubclasses = $this->resolveSubclassesRecursive($classesConfiguration, $classesConfiguration[$subclass]['subclasses']);
+                               $allSubclasses = array_merge($allSubclasses,$childSubclasses);
+                       }
+               }
+
+               return $allSubclasses;
+       }
+
+       /**
         * Returns the TCA ctrl section of the specified table; or NULL if not set
         *
         * @param string $tableName An optional table name to fetch the columns definition from
index f75d560..dc88b81 100644 (file)
@@ -338,5 +338,53 @@ class Tx_Extbase_Tests_Unit_Persistence_Mapper_DataMapFactoryTest extends Tx_Ext
                $mockDataMapFactory->buildDataMap('UnknownObject');
        }
 
+       /**
+        * @test
+        */
+       public function buildDataMapFetchesSubclassesRecursively() {
+               $configuration = array(
+                       'persistence' => array(
+                               'classes' => array(
+                                       'Tx_Extbase_Domain_Model_FrontendUser' => array(
+                                               'subclasses' => array(
+                                                       'Tx_SampleExt_Domain_Model_LevelOne1' => 'Tx_SampleExt_Domain_Model_LevelOne1',
+                                                       'Tx_SampleExt_Domain_Model_LevelOne2' => 'Tx_SampleExt_Domain_Model_LevelOne2',
+                                               )
+                                       ),
+                                       'Tx_SampleExt_Domain_Model_LevelOne1' => array(
+                                               'subclasses' => array(
+                                                       'Tx_SampleExt_Domain_Model_LevelTwo1' => 'Tx_SampleExt_Domain_Model_LevelTwo1',
+                                                       'Tx_SampleExt_Domain_Model_LevelTwo2' => 'Tx_SampleExt_Domain_Model_LevelTwo2',
+                                               )
+                                       ),
+                                       'Tx_SampleExt_Domain_Model_LevelOne2' => array(
+                                               'subclasses' => array(),
+                                       ),
+                               ),
+                       ),
+               );
+               $expectedSubclasses = array(
+                       'Tx_SampleExt_Domain_Model_LevelOne1',
+                       'Tx_SampleExt_Domain_Model_LevelTwo1',
+                       'Tx_SampleExt_Domain_Model_LevelTwo2',
+                       'Tx_SampleExt_Domain_Model_LevelOne2',
+               );
+
+               /** @var $configurationManager Tx_Extbase_Configuration_ConfigurationManager|PHPUnit_Framework_MockObject_MockObject  */
+               $configurationManager = $this->getMock('Tx_Extbase_Configuration_ConfigurationManager');
+               $configurationManager->expects($this->once())->method('getConfiguration')->with('Framework')
+                       ->will($this->returnValue($configuration));
+
+               $dataMapFactory = new Tx_Extbase_Persistence_Mapper_DataMapFactory();
+               $dataMapFactory->injectReflectionService(new Tx_Extbase_Reflection_Service());
+               $dataMapFactory->injectObjectManager(new Tx_Extbase_Object_ObjectManager());
+               $dataMapFactory->injectConfigurationManager($configurationManager);
+               $dataMap = $dataMapFactory->buildDataMap('Tx_Extbase_Domain_Model_FrontendUser');
+
+               $this->assertSame(
+                       $dataMap->getSubclasses(),
+                       $expectedSubclasses
+               );
+       }
 }
 ?>
\ No newline at end of file