[BUGFIX] Make object access work with ObjectStorage 23/29923/6
authorHelmut Hummel <helmut.hummel@typo3.org>
Wed, 7 May 2014 17:30:57 +0000 (19:30 +0200)
committerGeorg Ringer <georg.ringer@gmail.com>
Mon, 2 Jun 2014 10:41:19 +0000 (12:41 +0200)
ObjectAccess->getPropertyPath() does not work with
ObjectStorage and numerical indexes, but it should be
because without it form fluid fields cannot be
properly handled as the value is always null.

Fixing fetching objects from ObjectStorage by index
will also enable shorter access of single objects in Fluid.

Imagine you want to render the first image in your
template. Previously you had to write this:

<f:for each="{object.images}" as="image" iteration="iterator">
<f:if condition="{iterator.isFirst}">
<f:image image="{image}" alt="" width="50"/>
</f:if>
</f:for>

Now you can just write:

<f:image image="{object.images.0}" alt="" width="50"/>

Resolves: #37126
Related: #37000
Releases: 6.2
Change-Id: I45122bd145b5a179ad3e9e3894520f9a614906c8
Reviewed-on: https://review.typo3.org/29923
Reviewed-by: Markus Klein
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
Reviewed-by: Fabien Udriot
Reviewed-by: Tymoteusz Motylewski
Tested-by: Tymoteusz Motylewski
Reviewed-by: Georg Ringer
Tested-by: Georg Ringer
typo3/sysext/extbase/Classes/Reflection/ObjectAccess.php
typo3/sysext/extbase/Tests/Unit/Reflection/ObjectAccessTest.php

index d74a8e6..99f1cb3 100644 (file)
@@ -27,6 +27,8 @@ namespace TYPO3\CMS\Extbase\Reflection;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+use TYPO3\CMS\Core\Utility\MathUtility;
+
 /**
  * Provides methods to call appropriate getter/setter on an object given the
  * property name. It does this following these rules:
@@ -115,11 +117,19 @@ class ObjectAccess {
                                throw new \TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1302855001);
                        }
                }
-               if (
-                       $subject instanceof \ArrayAccess
-                       && !($subject instanceof \SplObjectStorage || $subject instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage)
-                       && isset($subject[$propertyName])
-               ) {
+               if ($subject instanceof \SplObjectStorage || $subject instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
+                       if (MathUtility::canBeInterpretedAsInteger($propertyName)) {
+                               $index = 0;
+                               foreach ($subject as $value) {
+                                       if ($index === (int)$propertyName) {
+                                               return $value;
+                                       }
+                                       $index++;
+                               }
+                       }
+                       $propertyExists = FALSE;
+                       return NULL;
+               } elseif ($subject instanceof \ArrayAccess && isset($subject[$propertyName])) {
                        return $subject[$propertyName];
                }
                $getterMethodName = 'get' . ucfirst($propertyName);
@@ -154,20 +164,9 @@ class ObjectAccess {
                $propertyPathSegments = explode('.', $propertyPath);
                foreach ($propertyPathSegments as $pathSegment) {
                        $propertyExists = FALSE;
-                       $propertyValue = self::getPropertyInternal($subject, $pathSegment, FALSE, $propertyExists);
-                       if (
-                               $propertyExists !== TRUE
-                               && ($subject instanceof \SplObjectStorage || $subject instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage)
-                       ) {
-                               $subject = NULL;
-                       } elseif (
-                               $propertyExists !== TRUE
-                               && (is_array($subject) || $subject instanceof \ArrayAccess)
-                               && isset($subject[$pathSegment])
-                       ) {
-                               $subject = $subject[$pathSegment];
-                       } else {
-                               $subject = $propertyValue;
+                       $subject = self::getPropertyInternal($subject, $pathSegment, FALSE, $propertyExists);
+                       if (!$propertyExists || $subject === NULL) {
+                               return $subject;
                        }
                }
                return $subject;
index 17b8580..dd087a0 100644 (file)
@@ -220,15 +220,37 @@ class ObjectAccessTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        /**
         * @test
         */
-       public function getPropertyPathCanNotAccessPropertiesOfAnSplObjectStorageObject() {
+       public function getPropertyPathCanAccessPropertiesOfAnExtbaseObjectStorageObject() {
                $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
                $exampleObject = new \stdClass();
                $exampleObject->key = 'value';
+               $exampleObject2 = new \stdClass();
+               $exampleObject2->key = 'value2';
                $objectStorage->attach($exampleObject);
+               $objectStorage->attach($exampleObject2);
                $array = array(
                        'parent' => $objectStorage,
                );
-               $this->assertNull(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.0.key'));
+               $this->assertSame('value', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.0.key'));
+               $this->assertSame('value2', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.1.key'));
+       }
+
+       /**
+        * @test
+        */
+       public function getPropertyPathCanAccessPropertiesOfAnSplObjectStorageObject() {
+               $objectStorage = new \SplObjectStorage();
+               $exampleObject = new \stdClass();
+               $exampleObject->key = 'value';
+               $exampleObject2 = new \stdClass();
+               $exampleObject2->key = 'value2';
+               $objectStorage->attach($exampleObject);
+               $objectStorage->attach($exampleObject2);
+               $array = array(
+                       'parent' => $objectStorage,
+               );
+               $this->assertSame('value', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.0.key'));
+               $this->assertSame('value2', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.1.key'));
        }
 
        /**