[TASK] FrontendContentAdapterService processes record repeatedly 86/26786/4
authorSteffen Ritter <info@rs-websystems.de>
Mon, 13 Jan 2014 15:40:05 +0000 (16:40 +0100)
committerBenjamin Mack <benni@typo3.org>
Wed, 15 Jan 2014 12:55:17 +0000 (13:55 +0100)
The FrontendContentAdapterService rewrites records so legacy
TypoScript is able to work on the files to. To do so it queries
the objects regarding the relations and fills the properties of
the record new line separated as known from pre-6.x records.

This change adds a runtime cache, so already processed records
of are not processed again, if the next cObject for the same
record is started.

Resolves: #54953
Releases: 6.2, 6.1
Change-Id: I1f632f175075c9d85079ea83e343e35867a1fcca
Reviewed-on: https://review.typo3.org/26786
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
Reviewed-by: Benjamin Mack
Tested-by: Benjamin Mack
typo3/sysext/core/Classes/Resource/Service/FrontendContentAdapterService.php
typo3/sysext/core/Tests/Unit/Resource/Service/FrontendContentAdapterServiceTest.php

index 4e38085..9b8cadd 100644 (file)
@@ -66,6 +66,11 @@ class FrontendContentAdapterService {
        );
 
        /**
+        * @var array
+        */
+       protected static $migrationCache = array();
+
+       /**
         * Modifies the DB row in the CONTENT cObj of tslib_content for supplying
         * backwards compatibility for some file fields which have switched to using
         * the new File API instead of the old uploads/ folder for storing files.
@@ -78,62 +83,77 @@ class FrontendContentAdapterService {
         * @return void
         */
        static public function modifyDBRow(&$row, $table) {
-               if (isset($row['_MIGRATED']) && $row['_MIGRATED'] === TRUE) {
+               // Only consider records with uid set, that have
+               // not been processed yet ("migrated")
+               if (!isset($row['uid']) || isset($row['_MIGRATED']) && $row['_MIGRATED'] === TRUE) {
                        return;
                }
-               if (array_key_exists($table, static::$migrateFields)) {
-                       foreach (static::$migrateFields[$table] as $migrateFieldName => $oldFieldNames) {
-                               if ($row !== NULL && isset($row[$migrateFieldName]) && self::fieldIsInType($migrateFieldName, $table, $row)) {
-                                       /** @var $fileRepository \TYPO3\CMS\Core\Resource\FileRepository */
-                                       $fileRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
-                                       if ($table === 'pages' && isset($row['_LOCALIZED_UID']) && intval($row['sys_language_uid']) > 0) {
-                                               $table = 'pages_language_overlay';
-                                       }
-                                       $files = $fileRepository->findByRelation($table, $migrateFieldName, isset($row['_LOCALIZED_UID']) ? intval($row['_LOCALIZED_UID']) : intval($row['uid']));
-                                       $fileFieldContents = array(
-                                               'paths' => array(),
-                                               'titleTexts' => array(),
-                                               'captions' => array(),
-                                               'links' => array(),
-                                               'alternativeTexts' => array(),
-                                               $migrateFieldName . '_fileUids' => array(),
-                                               $migrateFieldName . '_fileReferenceUids' => array(),
-                                       );
-                                       $oldFieldNames[$migrateFieldName . '_fileUids'] = $migrateFieldName . '_fileUids';
-                                       $oldFieldNames[$migrateFieldName . '_fileReferenceUids'] = $migrateFieldName . '_fileReferenceUids';
+               // Only consider records of table pages and tt_content
+               if ($table !== 'pages' && $table !== 'tt_content') {
+                       return;
+               }
+               // Use cached result, if available
+               if (!empty(static::$migrationCache[$table][$row['uid']])) {
+                       $row = static::$migrationCache[$table][$row['uid']];
+                       return;
+               }
+               // Process fields and execute "migration"
+               if (!isset(static::$migrationCache[$table])) {
+                       static::$migrationCache[$table] = array();
+               }
+               foreach (static::$migrateFields[$table] as $migrateFieldName => $oldFieldNames) {
+                       if (isset($row[$migrateFieldName]) && self::fieldIsInType($migrateFieldName, $table, $row)) {
+                               /** @var $fileRepository \TYPO3\CMS\Core\Resource\FileRepository */
+                               $fileRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
+                               if ($table === 'pages' && isset($row['_LOCALIZED_UID']) && intval($row['sys_language_uid']) > 0) {
+                                       $table = 'pages_language_overlay';
+                               }
+                               $files = $fileRepository->findByRelation($table, $migrateFieldName, isset($row['_LOCALIZED_UID']) ? intval($row['_LOCALIZED_UID']) : intval($row['uid']));
+                               $fileFieldContents = array(
+                                       'paths' => array(),
+                                       'titleTexts' => array(),
+                                       'captions' => array(),
+                                       'links' => array(),
+                                       'alternativeTexts' => array(),
+                                       $migrateFieldName . '_fileUids' => array(),
+                                       $migrateFieldName . '_fileReferenceUids' => array(),
+                               );
+                               $oldFieldNames[$migrateFieldName . '_fileUids'] = $migrateFieldName . '_fileUids';
+                               $oldFieldNames[$migrateFieldName . '_fileReferenceUids'] = $migrateFieldName . '_fileReferenceUids';
 
-                                       foreach ($files as $file) {
-                                               /** @var $file \TYPO3\CMS\Core\Resource\FileReference */
-                                               $fileProperties = $file->getProperties();
-                                               $fileFieldContents['paths'][] = '../../' . $file->getPublicUrl();
-                                               $fileFieldContents['titleTexts'][] = $fileProperties['title'];
-                                               $fileFieldContents['captions'][] = $fileProperties['description'];
-                                               $fileFieldContents['links'][] = $fileProperties['link'];
-                                               $fileFieldContents['alternativeTexts'][] = $fileProperties['alternative'];
-                                               $fileFieldContents[$migrateFieldName .  '_fileUids'][] = $file->getOriginalFile()->getUid();
-                                               $fileFieldContents[$migrateFieldName .  '_fileReferenceUids'][] = $file->getUid();
+                               foreach ($files as $file) {
+                                       /** @var $file \TYPO3\CMS\Core\Resource\FileReference */
+                                       $fileProperties = $file->getProperties();
+                                       $fileFieldContents['paths'][] = '../../' . $file->getPublicUrl();
+                                       $fileFieldContents['titleTexts'][] = $fileProperties['title'];
+                                       $fileFieldContents['captions'][] = $fileProperties['description'];
+                                       $fileFieldContents['links'][] = $fileProperties['link'];
+                                       $fileFieldContents['alternativeTexts'][] = $fileProperties['alternative'];
+                                       $fileFieldContents[$migrateFieldName .  '_fileUids'][] = $file->getOriginalFile()->getUid();
+                                       $fileFieldContents[$migrateFieldName .  '_fileReferenceUids'][] = $file->getUid();
+                               }
+                               foreach ($oldFieldNames as $oldFieldType => $oldFieldName) {
+                                       if ($oldFieldType === '__typeMatch') {
+                                               continue;
                                        }
-                                       foreach ($oldFieldNames as $oldFieldType => $oldFieldName) {
-                                               if ($oldFieldType === '__typeMatch') {
-                                                       continue;
-                                               }
-                                               if ($oldFieldType === 'paths' || substr($oldFieldType, -9) == '_fileUids' || substr($oldFieldType, -18) == '_fileReferenceUids') {
-                                                       // For paths and uids, make comma separated list
-                                                       $fieldContents = implode(',', $fileFieldContents[$oldFieldType]);
-                                               } else {
-                                                       // For all other fields, separate by newline
-                                                       $fieldContents = implode(chr(10), $fileFieldContents[$oldFieldType]);
-                                               }
-                                               $row[$oldFieldName] = $fieldContents;
+                                       if ($oldFieldType === 'paths' || substr($oldFieldType, -9) == '_fileUids' || substr($oldFieldType, -18) == '_fileReferenceUids') {
+                                               // For paths and uids, make comma separated list
+                                               $fieldContents = implode(',', $fileFieldContents[$oldFieldType]);
+                                       } else {
+                                               // For all other fields, separate by newline
+                                               $fieldContents = implode(chr(10), $fileFieldContents[$oldFieldType]);
                                        }
+                                       $row[$oldFieldName] = $fieldContents;
                                }
                        }
                }
+
                $row['_MIGRATED'] = TRUE;
+               static::$migrationCache[$table][$row['uid']] = $row;
        }
 
        /**
-        * Check if fieldis in type
+        * Checks whether field is in type
         *
         * @param string $fieldName
         * @param string $table
@@ -145,7 +165,10 @@ class FrontendContentAdapterService {
                if (empty($fieldConfiguration['__typeMatch'])) {
                        return TRUE;
                } else {
-                       return in_array($row[$fieldConfiguration['__typeMatch']['typeField']], $fieldConfiguration['__typeMatch']['types']);
+                       return in_array(
+                               $row[$fieldConfiguration['__typeMatch']['typeField']],
+                               $fieldConfiguration['__typeMatch']['types']
+                       );
                }
        }
 }
index 9f8e6db..62bf8cd 100644 (file)
@@ -38,9 +38,15 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
        protected $singletonInstances = array();
 
        /**
+        * @var string
+        */
+       protected $accessibleFixtureName;
+
+       /**
         * Saving the singletons
         */
        public function setUp() {
+               $this->accessibleFixtureName = $this->buildAccessibleProxy('TYPO3\\CMS\\Core\\Resource\\Service\\FrontendContentAdapterService');
                $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
                $this->fileRepositoryMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\FileRepository');
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository', $this->fileRepositoryMock);
@@ -50,6 +56,7 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
         * Restoring the singletons
         */
        public function tearDown() {
+               call_user_func_array($this->accessibleFixtureName . '::_setStatic', array('migrationCache', array()));
                \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
                unset($this->fileRepositoryMock);
        }
@@ -57,22 +64,77 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
        /**
         * @test
         */
+       public function customTableIsNotConsidered() {
+               $dbRow = array(
+                       'uid' => uniqid(),
+               );
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               $result = call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, uniqid('tx_testtable')));
+               $this->assertNull($result);
+       }
+
+       /**
+        * @test
+        */
+       public function recordWithoutUidIsNotConsidered() {
+               $dbRow = array();
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               $result = call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, 'tt_content'));
+               $this->assertNull($result);
+       }
+
+       /**
+        * @test
+        */
        public function emptyRelationResetsLegacyFields() {
                $this->fileRepositoryMock->expects($this->any())
                        ->method('findByRelation')
                        ->will($this->returnValue(array()));
                $dbRow = array(
+                       'uid' => uniqid(),
                        'CType' => 'image',
                        'image' => '1'
                );
 
-               \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow($dbRow, 'tt_content');
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, 'tt_content'));
                $this->assertEmpty($dbRow['image']);
        }
 
        /**
         * @test
         */
+       public function processedRecordsAreCached() {
+               // Asserting that this is only called once,
+               // since second call shall be delivered from cache
+               $this->fileRepositoryMock->expects($this->once())
+                       ->method('findByRelation')
+                       ->will($this->returnValue(array()));
+
+               $testUid = uniqid();
+
+               $dbRow = array(
+                       'uid' => $testUid,
+                       'CType' => 'image',
+                       'image' => '1',
+               );
+
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, 'tt_content'));
+
+               $dbRow = array(
+                       'uid' => $testUid,
+                       'CType' => 'image',
+                       'image' => '1',
+               );
+
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, 'tt_content'));
+       }
+
+       /**
+        * @test
+        */
        public function imageFieldIsFilledWithPathOfImage() {
                $fileReference = $this->getMock('TYPO3\\CMS\\Core\\Resource\\FileReference', array(), array(), '', FALSE);
                $fileReference->expects($this->any())
@@ -85,15 +147,17 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
                        ->method('findByRelation')
                        ->will($this->returnValue(array($fileReference)));
                $dbRow = array(
+                       'uid' => uniqid(),
                        'CType' => 'image',
                        'image' => '1'
                );
 
-               \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow($dbRow, 'tt_content');
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, 'tt_content'));
                $this->assertSame('../../path/to/file', $dbRow['image']);
        }
 
-       public function conteRowsOfDifferentTypesDataProvider() {
+       public function contentRowsOfDifferentTypesDataProvider() {
                $filePropertiesImage = array(
                        'title' => 'Image',
                        'description' => 'IMAGE DESCRIPTION',
@@ -107,6 +171,7 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
                return array(
                        'Image Element' => array(
                                array(
+                                       'uid' => uniqid(),
                                        'CType' => 'image',
                                        'image' => '',
                                        'media' => '',
@@ -116,6 +181,7 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
                        ),
                        'Textpic Element' => array(
                                array(
+                                       'uid' => uniqid(),
                                        'CType' => 'textpic',
                                        'image' => '',
                                        'media' => '',
@@ -125,6 +191,7 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
                        ),
                        'Uploads Element' => array(
                                array(
+                                       'uid' => uniqid(),
                                        'CType' => 'uploads',
                                        'image' => '',
                                        'media' => '',
@@ -137,7 +204,7 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
 
        /**
         * @test
-        * @dataProvider conteRowsOfDifferentTypesDataProvider
+        * @dataProvider contentRowsOfDifferentTypesDataProvider
         */
        public function migrationOfLegacyFieldsIsOnlyDoneWhenRelationFieldIsVisibleInType($dbRow, $expectedCaption, $fileProperties) {
                $fileReference = $this->getMock('TYPO3\\CMS\\Core\\Resource\\FileReference', array(), array(), '', FALSE);
@@ -154,7 +221,8 @@ class FrontendContentAdapterServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCa
                        ->method('findByRelation')
                        ->will($this->returnValue(array($fileReference)));
 
-               \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow($dbRow, 'tt_content');
+               /* @see \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow */
+               call_user_func_array($this->accessibleFixtureName . '::modifyDBRow', array(&$dbRow, 'tt_content'));
                $this->assertSame($expectedCaption, $dbRow['imagecaption']);
        }