[+FEATURE] (Reflection): Object Access can now access private properties
authorSebastian Kurfuerst <sebastian@typo3.org>
Wed, 22 Jun 2011 06:33:49 +0000 (08:33 +0200)
committerSebastian Kurfuerst <sebastian@typo3.org>
Thu, 30 Jun 2011 05:29:42 +0000 (07:29 +0200)
Resolves: #27652
Related: #27059
Change-Id: I93a31053f29e18791539033e262f32b41f21222e

typo3/sysext/extbase/Classes/Reflection/ObjectAccess.php
typo3/sysext/extbase/Tests/Unit/Reflection/ObjectAccessTest.php

index d4861c5..4f523dc 100644 (file)
@@ -52,11 +52,12 @@ class Tx_Extbase_Reflection_ObjectAccess {
         *
         * @param mixed $subject Object or array to get the property from
         * @param string $propertyName name of the property to retrieve
+        * @param boolean $forceDirectAccess directly access property using reflection(!)
         * @return object Value of the property.
         * @throws InvalidArgumentException in case $subject was not an object or $propertyName was not a string
         * @throws RuntimeException if the property was not accessible
         */
-       static public function getProperty($subject, $propertyName) {
+       static public function getProperty($subject, $propertyName, $forceDirectAccess = FALSE) {
                if (!is_object($subject) && !is_array($subject)) throw new InvalidArgumentException('$subject must be an object or array, ' . gettype($subject). ' given.', 1237301367);
                if (!is_string($propertyName)) throw new InvalidArgumentException('Given property name is not of type string.', 1231178303);
 
@@ -65,7 +66,16 @@ class Tx_Extbase_Reflection_ObjectAccess {
                                return $subject[$propertyName];
                        }
                } else {
-                       if (is_callable(array($subject, 'get' . ucfirst($propertyName)))) {
+                       if ($forceDirectAccess === TRUE) {
+                               if (property_exists(get_class($subject), $propertyName)) {
+                                       $propertyReflection = new Tx_Extbase_Reflection_PropertyReflection(get_class($subject), $propertyName);
+                                       return $propertyReflection->getValue($subject);
+                               } elseif (property_exists($subject, $propertyName)) {
+                                       return $subject->$propertyName;
+                               } else {
+                                       throw new Tx_Extbase_Reflection_Exception_PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1302855001);
+                               }
+                       } elseif (is_callable(array($subject, 'get' . ucfirst($propertyName)))) {
                                return call_user_func(array($subject, 'get' . ucfirst($propertyName)));
                        } elseif (is_callable(array($subject, 'is' . ucfirst($propertyName)))) {
                                return call_user_func(array($subject, 'is' . ucfirst($propertyName)));
@@ -114,10 +124,11 @@ class Tx_Extbase_Reflection_ObjectAccess {
         * @param object $object The target object
         * @param string $propertyName Name of the property to set
         * @param object $propertyValue Value of the property
+        * @param boolean $forceDirectAccess directly access property using reflection(!)
         * @return void
         * @throws Tx_Extbase_Reflection_Exception if property was could not be set
         */
-       static public function setProperty(&$object, $propertyName, $propertyValue) {
+       static public function setProperty(&$object, $propertyName, $propertyValue, $forceDirectAccess = FALSE) {
                if (is_array($object)) {
                        $object[$propertyName] = $propertyValue;
                        return TRUE;
@@ -125,7 +136,15 @@ class Tx_Extbase_Reflection_ObjectAccess {
                if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1237301368);
                if (!is_string($propertyName)) throw new InvalidArgumentException('Given property name is not of type string.', 1231178878);
 
-               if (is_callable(array($object, $setterMethodName = self::buildSetterMethodName($propertyName)))) {
+               if ($forceDirectAccess === TRUE) {
+                       if (property_exists(get_class($object), $propertyName)) {
+                               $propertyReflection = new Tx_Extbase_Reflection_PropertyReflection(get_class($object), $propertyName);
+                               $propertyReflection->setAccessible(TRUE);
+                               $propertyReflection->setValue($object, $propertyValue);
+                       } else {
+                               $object->$propertyName = $propertyValue;
+                       }
+               } elseif (is_callable(array($object, $setterMethodName = self::buildSetterMethodName($propertyName)))) {
                        call_user_func(array($object, $setterMethodName), $propertyValue);
                } elseif ($object instanceof ArrayAccess) {
                        $object[$propertyName] = $propertyValue;
index 334d72f..de5fc6e 100644 (file)
@@ -56,6 +56,31 @@ class Tx_Extbase_Tests_Unit_Reflection_ObjectAccessTest extends Tx_Extbase_Tests
 
        /**
         * @test
+        */
+       public function getPropertyReturnsExpectedValueForUnexposedPropertyIfForceDirectAccessIsTrue() {
+               $property = Tx_Extbase_Reflection_ObjectAccess::getProperty($this->dummyObject, 'unexposedProperty', TRUE);
+               $this->assertEquals($property, 'unexposed', 'A property of a given object was not returned correctly.');
+       }
+
+       /**
+        * @test
+        */
+       public function getPropertyReturnsExpectedValueForUnknownPropertyIfForceDirectAccessIsTrue() {
+               $this->dummyObject->unknownProperty = 'unknown';
+               $property = Tx_Extbase_Reflection_ObjectAccess::getProperty($this->dummyObject, 'unknownProperty', TRUE);
+               $this->assertEquals($property, 'unknown', 'A property of a given object was not returned correctly.');
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_Reflection_Exception_PropertyNotAccessibleException
+        */
+       public function getPropertyReturnsPropertyNotAccessibleExceptionForNotExistingPropertyIfForceDirectAccessIsTrue() {
+               $property = Tx_Extbase_Reflection_ObjectAccess::getProperty($this->dummyObject, 'notExistingProperty', TRUE);
+       }
+
+       /**
+        * @test
         * @expectedException Tx_Extbase_Reflection_Exception_PropertyNotAccessibleException
         */
        public function getPropertyReturnsThrowsExceptionIfPropertyDoesNotExist() {
@@ -104,6 +129,22 @@ class Tx_Extbase_Tests_Unit_Reflection_ObjectAccessTest extends Tx_Extbase_Tests
        /**
         * @test
         */
+       public function setPropertySetsValueIfPropertyIsNotAccessibleWhenForceDirectAccessIsTrue() {
+               $this->assertTrue(Tx_Extbase_Reflection_ObjectAccess::setProperty($this->dummyObject, 'unexposedProperty', 'was set anyway', TRUE));
+               $this->assertAttributeEquals('was set anyway', 'unexposedProperty', $this->dummyObject);
+       }
+
+       /**
+        * @test
+        */
+       public function setPropertySetsValueIfPropertyDoesNotExistWhenForceDirectAccessIsTrue() {
+               $this->assertTrue(Tx_Extbase_Reflection_ObjectAccess::setProperty($this->dummyObject, 'unknownProperty', 'was set anyway', TRUE));
+               $this->assertAttributeEquals('was set anyway', 'unknownProperty', $this->dummyObject);
+       }
+
+       /**
+        * @test
+        */
        public function setPropertyCallsASetterMethodToSetThePropertyValueIfOneIsAvailable() {
                Tx_Extbase_Reflection_ObjectAccess::setProperty($this->dummyObject, 'property', 4242);
                $this->assertEquals($this->dummyObject->getProperty(), 4242, 'setProperty does not work with setter.');