TYPO3 API  SVNRelease
ObjectAccess.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2009 Christopher Hlubek <hlubek@networkteam.com>
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *
00017 *  This script is distributed in the hope that it will be useful,
00018 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 *  GNU General Public License for more details.
00021 *
00022 *  This copyright notice MUST APPEAR in all copies of the script!
00023 ***************************************************************/
00024 
00025 /**
00026  * Provides methods to call appropriate getter/setter on an object given the
00027  * property name. It does this following these rules:
00028  * - if the target object is an instance of ArrayAccess, it gets/sets the property
00029  * - if public getter/setter method exists, call it.
00030  * - if public property exists, return/set the value of it.
00031  * - else, throw exception
00032  *
00033  * @package Extbase
00034  * @subpackage Reflection
00035  * @version $Id: ObjectAccess.php 2149 2010-03-30 09:28:54Z jocrau $
00036  */
00037 class Tx_Extbase_Reflection_ObjectAccess {
00038 
00039     const ACCESS_GET = 0;
00040     const ACCESS_SET = 1;
00041     const ACCESS_PUBLIC = 2;
00042 
00043     /**
00044      * Get a property of a given object.
00045      * Tries to get the property the following ways:
00046      * - if the target is an array, and has this property, we call it.
00047      * - if public getter method exists, call it.
00048      * - if the target object is an instance of ArrayAccess, it gets the property
00049      *   on it if it exists.
00050      * - if public property exists, return the value of it.
00051      * - else, throw exception
00052      *
00053      * @param mixed $subject Object or array to get the property from
00054      * @param string $propertyName name of the property to retrieve
00055      * @return object Value of the property.
00056      * @throws InvalidArgumentException in case $subject was not an object or $propertyName was not a string
00057      * @throws RuntimeException if the property was not accessible
00058      */
00059     static public function getProperty($subject, $propertyName) {
00060         if (!is_object($subject) && !is_array($subject)) throw new InvalidArgumentException('$subject must be an object or array, ' . gettype($subject). ' given.', 1237301367);
00061         if (!is_string($propertyName)) throw new InvalidArgumentException('Given property name is not of type string.', 1231178303);
00062 
00063         if (is_array($subject)) {
00064             if (array_key_exists($propertyName, $subject)) {
00065                 return $subject[$propertyName];
00066             }
00067         } else {
00068             if (is_callable(array($subject, 'get' . ucfirst($propertyName)))) {
00069                 return call_user_func(array($subject, 'get' . ucfirst($propertyName)));
00070             } elseif (is_callable(array($subject, 'is' . ucfirst($propertyName)))) {
00071                 return call_user_func(array($subject, 'is' . ucfirst($propertyName)));
00072             } elseif ($subject instanceof ArrayAccess && isset($subject[$propertyName])) {
00073                 return $subject[$propertyName];
00074             } elseif (array_key_exists($propertyName, get_object_vars($subject))) {
00075                 return $subject->$propertyName;
00076             }
00077         }
00078 
00079         throw new Tx_Extbase_Reflection_Exception_PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject was not accessible.', 1263391473);
00080     }
00081 
00082     /**
00083      * Gets a property path from a given object or array.
00084      * If propertyPath is "bla.blubb", then we first call getProperty($object, 'bla'),
00085      * and on the resulting object we call getProperty(..., 'blubb')
00086      *
00087      * @param mixed $subject Object or array to get the property path from
00088      * @param string $propertyPath
00089      * @return mixed Value of the property
00090      */
00091     static public function getPropertyPath($subject, $propertyPath) {
00092         $propertyPathSegments = explode('.', $propertyPath);
00093         foreach ($propertyPathSegments as $pathSegment) {
00094             if (is_object($subject) && self::isPropertyGettable($subject, $pathSegment)) {
00095                 $subject = self::getProperty($subject, $pathSegment);
00096             } elseif ((is_array($subject) || $subject instanceof ArrayAccess) && isset($subject[$pathSegment])) {
00097                 $subject = $subject[$pathSegment];
00098             } else {
00099                 return NULL;
00100             }
00101         }
00102         return $subject;
00103     }
00104 
00105     /**
00106      * Set a property for a given object.
00107      * Tries to set the property the following ways:
00108      * - if public setter method exists, call it.
00109      * - if public property exists, set it directly.
00110      * - if the target object is an instance of ArrayAccess, it sets the property
00111      *   on it without checking if it existed.
00112      * - else, return FALSE
00113      *
00114      * @param object $object The target object
00115      * @param string $propertyName Name of the property to set
00116      * @param object $propertyValue Value of the property
00117      * @return void
00118      * @throws Tx_Extbase_Reflection_Exception if property was could not be set
00119      */
00120     static public function setProperty(&$object, $propertyName, $propertyValue) {
00121         if (is_array($object)) {
00122             $object[$propertyName] = $propertyValue;
00123             return TRUE;
00124         }
00125         if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1237301368);
00126         if (!is_string($propertyName)) throw new InvalidArgumentException('Given property name is not of type string.', 1231178878);
00127 
00128         if (is_callable(array($object, $setterMethodName = self::buildSetterMethodName($propertyName)))) {
00129             call_user_func(array($object, $setterMethodName), $propertyValue);
00130         } elseif ($object instanceof ArrayAccess) {
00131             $object[$propertyName] = $propertyValue;
00132         } elseif (array_key_exists($propertyName, get_object_vars($object))) {
00133             $object->$propertyName = $propertyValue;
00134         } else {
00135             return FALSE;
00136         }
00137         return TRUE;
00138     }
00139 
00140     /**
00141      * Returns an array of properties which can be get/set with the getProperty
00142      * and setProperty methods.
00143      * Includes the following properties:
00144      * - which can be set through a public setter method.
00145      * - public properties which can be directly set.
00146      *
00147      * @param object $object Object to receive property names for
00148      * @return array Array of all declared property names
00149      * @deprecated since Extbase 1.3.0; will be removed in Extbase 1.5.0. Please use getGettablePropertyNames() instead
00150      */
00151     static public function getAccessiblePropertyNames($object) {
00152         t3lib_div::logDeprecatedFunction();
00153         return self::getGettablePropertyNames($object);
00154     }
00155 
00156     /**
00157      * Returns an array of properties which can be get with the getProperty()
00158      * method.
00159      * Includes the following properties:
00160      * - which can be get through a public getter method.
00161      * - public properties which can be directly get.
00162      *
00163      * @param object $object Object to receive property names for
00164      * @return array Array of all gettable property names
00165      * @author Sebastian Kurfürst <sebastian@typo3.org>
00166      * @author Karsten Dambekalns <karsten@typo3.org>
00167      */
00168     static public function getGettablePropertyNames($object) {
00169         if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1237301369);
00170         if ($object instanceof stdClass) {
00171             $declaredPropertyNames = array_keys(get_object_vars($object));
00172         } else {
00173             $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
00174         }
00175 
00176         foreach (get_class_methods($object) as $methodName) {
00177             if (is_callable(array($object, $methodName))) {
00178                 if (substr($methodName, 0, 2) === 'is') {
00179                     $declaredPropertyNames[] = strtolower(substr($methodName, 2, 1)) . (substr($methodName, 3));
00180                 }
00181                 if (substr($methodName, 0, 3) === 'get') {
00182                     $declaredPropertyNames[] = strtolower(substr($methodName, 3, 1)) . (substr($methodName, 4));
00183                 }
00184             }
00185         }
00186 
00187         $propertyNames = array_unique($declaredPropertyNames);
00188         sort($propertyNames);
00189         return $propertyNames;
00190     }
00191 
00192     /**
00193      * Returns an array of properties which can be set with the setProperty()
00194      * method.
00195      * Includes the following properties:
00196      * - which can be set through a public setter method.
00197      * - public properties which can be directly set.
00198      *
00199      * @param object $object Object to receive property names for
00200      * @return array Array of all settable property names
00201      * @author Karsten Dambekalns <karsten@typo3.org>
00202      */
00203     static public function getSettablePropertyNames($object) {
00204         if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1264022994);
00205         if ($object instanceof stdClass) {
00206             $declaredPropertyNames = array_keys(get_object_vars($object));
00207         } else {
00208             $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
00209         }
00210 
00211         foreach (get_class_methods($object) as $methodName) {
00212             if (substr($methodName, 0, 3) === 'set' && is_callable(array($object, $methodName))) {
00213                 $declaredPropertyNames[] = strtolower(substr($methodName, 3, 1)) . (substr($methodName, 4));
00214             }
00215         }
00216 
00217         $propertyNames = array_unique($declaredPropertyNames);
00218         sort($propertyNames);
00219         return $propertyNames;
00220     }
00221 
00222     /**
00223      * Get all properties (names and their current values) of the current
00224      * $object that are accessible through this class.
00225      *
00226      * @param object $object Object to get all properties from.
00227      * @return array Associative array of all properties.
00228      * @deprecated since Extbase 1.3.0; will be removed in Extbase 1.5.0. Please use getGettableProperties() instead
00229      */
00230     static public function getAccessibleProperties($object) {
00231         t3lib_div::logDeprecatedFunction();
00232         return self::getGettableProperties($object);
00233     }
00234 
00235     /**
00236      * Get all properties (names and their current values) of the current
00237      * $object that are accessible through this class.
00238      *
00239      * @param object $object Object to get all properties from.
00240      * @return array Associative array of all properties.
00241      * @author Sebastian Kurfürst <sebastian@typo3.org>
00242      * @todo What to do with ArrayAccess
00243      */
00244     static public function getGettableProperties($object) {
00245         if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1237301370);
00246         $properties = array();
00247         foreach (self::getGettablePropertyNames($object) as $propertyName) {
00248             $properties[$propertyName] = self::getProperty($object, $propertyName);
00249         }
00250         return $properties;
00251     }
00252 
00253 
00254     /**
00255      * Tells if the value of the specified property can be set by this Object Accessor.
00256      *
00257      * @param object $object Object containting the property
00258      * @param string $propertyName Name of the property to check
00259      * @return boolean
00260      * @author Robert Lemke <robert@typo3.org>
00261      */
00262     static public function isPropertySettable($object, $propertyName) {
00263         if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1259828920);
00264         if ($object instanceof stdClass && array_search($propertyName, array_keys(get_object_vars($object))) !== FALSE) {
00265             return TRUE;
00266         } elseif (array_search($propertyName, array_keys(get_class_vars(get_class($object)))) !== FALSE) {
00267             return TRUE;
00268         }
00269         return is_callable(array($object, self::buildSetterMethodName($propertyName)));
00270     }
00271 
00272     /**
00273      * Tells if the value of the specified property can be retrieved by this Object Accessor.
00274      *
00275      * @param object $object Object containting the property
00276      * @param string $propertyName Name of the property to check
00277      * @return boolean
00278      */
00279     static public function isPropertyGettable($object, $propertyName) {
00280         if (!is_object($object)) throw new InvalidArgumentException('$object must be an object, ' . gettype($object). ' given.', 1259828921);
00281         if ($object instanceof stdClass && array_search($propertyName, array_keys(get_object_vars($object))) !== FALSE) {
00282             return TRUE;
00283         } elseif (array_search($propertyName, array_keys(get_class_vars(get_class($object)))) !== FALSE) {
00284             return TRUE;
00285         } elseif ($object instanceof ArrayAccess && isset($object[$propertyName]) === TRUE) {
00286             return TRUE;
00287         }
00288         if (is_callable(array($object, 'get' . ucfirst($propertyName)))) return TRUE;
00289         return is_callable(array($object, 'is' . ucfirst($propertyName)));
00290     }
00291 
00292     /**
00293      * Build the setter method name for a given property by capitalizing the
00294      * first letter of the property, and prepending it with "set".
00295      *
00296      * @param string $property Name of the property
00297      * @return string Name of the setter method name
00298      */
00299     static protected function buildSetterMethodName($property) {
00300         return 'set' . ucfirst($property);
00301     }
00302 }
00303 
00304 
00305 ?>