[BUGFIX] Allow accessing object from `ObjectStorage` with numeric value 72/58972/7
authorRomain Canon <romain.hydrocanon@gmail.com>
Wed, 28 Nov 2018 16:52:38 +0000 (17:52 +0100)
committerGeorg Ringer <georg.ringer@gmail.com>
Mon, 3 Dec 2018 21:09:55 +0000 (22:09 +0100)
The following code now works:

```php
$objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$objectStorage->attach(new \stdClass());
$myObject = $objectStorage->offsetGet(0);
```

And more importantly, the following Fluid code works as well:

<f:image image="{myObject.resources.0}" alt="My image!" />

Resolves: #87028
Releases: master, 8.7
Change-Id: I15890a16540ff2e39a5e48ed83f96a1443bc98ac
Reviewed-on: https://review.typo3.org/58972
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
typo3/sysext/core/Documentation/Changelog/9.5.x/Important-87028-AccessObjectsFromObjectStorageUsingNumericValue.rst [new file with mode: 0644]
typo3/sysext/extbase/Classes/Persistence/Generic/LazyObjectStorage.php
typo3/sysext/extbase/Classes/Persistence/ObjectStorage.php
typo3/sysext/extbase/Tests/Unit/Persistence/ObjectStorageTest.php

diff --git a/typo3/sysext/core/Documentation/Changelog/9.5.x/Important-87028-AccessObjectsFromObjectStorageUsingNumericValue.rst b/typo3/sysext/core/Documentation/Changelog/9.5.x/Important-87028-AccessObjectsFromObjectStorageUsingNumericValue.rst
new file mode 100644 (file)
index 0000000..017c607
--- /dev/null
@@ -0,0 +1,35 @@
+.. include:: ../../Includes.txt
+
+===========================================================================
+Important: #87028 - Access objects from `ObjectStorage` using numeric value
+===========================================================================
+
+See :issue:`87028`
+
+Description
+===========
+
+It is now possible to access the objects of an instance of `ObjectStorage` using a numeric value.
+
+The following code now works:
+
+
+.. code-block:: php
+
+       $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+       $objectStorage->attach(new \stdClass());
+       $myObject = $objectStorage->offsetGet(0);
+
+And more importantly, the following Fluid code works as well:
+
+.. code-block:: html
+
+       <f:image image="{myObject.resources.0}" alt="My image!" />
+
+
+Impact
+======
+
+The old way of getting information of an object in the storage still works as before.
+
+.. index:: Fluid, PHP-API, ext:extbase, NotScanned
index 2978b2a..bbb41ff 100644 (file)
@@ -243,27 +243,27 @@ class LazyObjectStorage extends \TYPO3\CMS\Extbase\Persistence\ObjectStorage imp
     }
 
     /**
-     * @param object $object The object to look for.
+     * @param object $value The object to look for, or the key in the storage.
      * @return bool
      *
      * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetExists
      */
-    public function offsetExists($object)
+    public function offsetExists($value)
     {
         $this->initialize();
-        return parent::offsetExists($object);
+        return parent::offsetExists($value);
     }
 
     /**
-     * @param object $object The object to look for.
+     * @param object $value The object to look for, or its key in the storage.
      * @return mixed
      *
      * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetGet
      */
-    public function offsetGet($object)
+    public function offsetGet($value)
     {
         $this->initialize();
-        return parent::offsetGet($object);
+        return parent::offsetGet($value);
     }
 
     /**
@@ -279,14 +279,14 @@ class LazyObjectStorage extends \TYPO3\CMS\Extbase\Persistence\ObjectStorage imp
     }
 
     /**
-     * @param object $object The object to remove.
+     * @param object $value The object to remove, or its key in the storage.
      *
      * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetUnset
      */
-    public function offsetUnset($object)
+    public function offsetUnset($value)
     {
         $this->initialize();
-        parent::offsetUnset($object);
+        parent::offsetUnset($value);
     }
 
     /**
index 7cc46df..dd4ad16 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Extbase\Persistence;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\MathUtility;
+
 /**
  * The storage for objects. It ensures the uniqueness of an object in the storage. It's a remake of the
  * SplObjectStorage introduced in PHP 5.3.
@@ -156,22 +158,30 @@ class ObjectStorage implements \Countable, \Iterator, \ArrayAccess, ObjectMonito
     /**
      * Checks whether an object exists in the storage.
      *
-     * @param object $object The object to look for.
+     * @param object|int $value The object to look for, or the key in the storage.
      * @return bool
      */
-    public function offsetExists($object)
+    public function offsetExists($value)
     {
-        return is_object($object) && isset($this->storage[spl_object_hash($object)]);
+        return is_object($value) && isset($this->storage[spl_object_hash($value)])
+            || MathUtility::canBeInterpretedAsInteger($value) && isset(array_values($this->storage)[$value]);
     }
 
     /**
      * Removes an object from the storage. offsetUnset() is an alias of detach().
      *
-     * @param object $object The object to remove.
+     * @param object|int $value The object to remove, or its key in the storage.
      */
-    public function offsetUnset($object)
+    public function offsetUnset($value)
     {
         $this->isModified = true;
+
+        $object = $value;
+
+        if (MathUtility::canBeInterpretedAsInteger($value)) {
+            $object = $this->offsetGet($value);
+        }
+
         unset($this->storage[spl_object_hash($object)]);
 
         if (empty($this->storage)) {
@@ -183,14 +193,19 @@ class ObjectStorage implements \Countable, \Iterator, \ArrayAccess, ObjectMonito
     }
 
     /**
-     * Returns the data associated with an object.
+     * Returns the data associated with an object, or the object itself if an
+     * integer is passed.
      *
-     * @param object $object The object to look for.
-     * @return mixed The data associated with an object in the storage.
+     * @param object|int $value The object to look for, or its key in the storage.
+     * @return mixed The data associated with an object in the storage, or the object itself if an integer is passed.
      */
-    public function offsetGet($object)
+    public function offsetGet($value)
     {
-        return $this->storage[spl_object_hash($object)]['inf'];
+        if (MathUtility::canBeInterpretedAsInteger($value)) {
+            return array_values($this->storage)[$value]['obj'];
+        }
+
+        return $this->storage[spl_object_hash($value)]['inf'];
     }
 
     /**
index 7c743b5..8526369 100644 (file)
@@ -86,6 +86,23 @@ class ObjectStorageTest extends UnitTestCase
     /**
      * @test
      */
+    public function offsetUnsetKeyRemovesAnObjectFromTheStorage()
+    {
+        $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+        $object1 = new \stdClass();
+        $object2 = new \stdClass();
+        $objectStorage->attach($object1);
+        $objectStorage->attach($object2, 'foo');
+        $this->assertEquals(count($objectStorage), 2);
+        $objectStorage->offsetUnset(0);
+        $this->assertEquals(count($objectStorage), 1);
+        $objectStorage->offsetUnset(0);
+        $this->assertEquals(count($objectStorage), 0);
+    }
+
+    /**
+     * @test
+     */
     public function offsetGetReturnsTheDataAssociatedWithAnObject()
     {
         $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
@@ -100,6 +117,20 @@ class ObjectStorageTest extends UnitTestCase
     /**
      * @test
      */
+    public function offsetGetKeyReturnsTheObject()
+    {
+        $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+        $object1 = new \stdClass();
+        $object2 = new \stdClass();
+        $objectStorage->attach($object1);
+        $objectStorage->attach($object2);
+        $this->assertSame($object1, $objectStorage->offsetGet(0));
+        $this->assertSame($object2, $objectStorage->offsetGet(1));
+    }
+
+    /**
+     * @test
+     */
     public function offsetExistsChecksWhetherAnObjectExistsInTheStorage()
     {
         $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
@@ -113,6 +144,17 @@ class ObjectStorageTest extends UnitTestCase
     /**
      * @test
      */
+    public function offsetExistsChecksWhetherKeyExistsInTheStorage()
+    {
+        $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+        $objectStorage->attach(new \stdClass());
+        $this->assertTrue($objectStorage->offsetExists(0));
+        $this->assertFalse($objectStorage->offsetExists(1));
+    }
+
+    /**
+     * @test
+     */
     public function offsetExistsWorksWithEmptyStorageAndIntegerKey()
     {
         $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();