TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
ObjectAccess.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Extbase\Reflection;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
28 {
29  const ACCESS_GET = 0;
30 
31  const ACCESS_SET = 1;
32 
33  const ACCESS_PUBLIC = 2;
34 
53  public static function getProperty($subject, $propertyName, $forceDirectAccess = false)
54  {
55  if (!is_object($subject) && !is_array($subject)) {
56  throw new \InvalidArgumentException('$subject must be an object or array, ' . gettype($subject) . ' given.', 1237301367);
57  }
58  if (!is_string($propertyName) && (!is_array($subject) && !$subject instanceof \ArrayAccess)) {
59  throw new \InvalidArgumentException('Given property name is not of type string.', 1231178303);
60  }
61  return self::getPropertyInternal($subject, $propertyName, $forceDirectAccess);
62  }
63 
79  public static function getPropertyInternal($subject, $propertyName, $forceDirectAccess = false)
80  {
81  // type check and conversion of iterator to numerically indexed array
82  if ($subject === null || is_scalar($subject)) {
83  return null;
84  } elseif (!$forceDirectAccess && ($subject instanceof \SplObjectStorage || $subject instanceof ObjectStorage)) {
85  $subject = iterator_to_array($subject, false);
86  }
87 
88  // value get based on data type of $subject (possibly converted above)
89  if (($subject instanceof \ArrayAccess && $subject->offsetExists($propertyName)) || is_array($subject)) {
90  // isset() is safe; array_key_exists would only be needed to determine
91  // if the value is NULL - and that's already what we return as fallback.
92  if (isset($subject[$propertyName])) {
93  return $subject[$propertyName];
94  }
95  } elseif (is_object($subject)) {
96  if ($forceDirectAccess) {
97  if (property_exists($subject, $propertyName)) {
98  $propertyReflection = new PropertyReflection($subject, $propertyName);
99  return $propertyReflection->getValue($subject);
100  } else {
101  throw new Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1302855001);
102  }
103  }
104  $upperCasePropertyName = ucfirst($propertyName);
105  $getterMethodName = 'get' . $upperCasePropertyName;
106  if (is_callable([$subject, $getterMethodName])) {
107  return $subject->{$getterMethodName}();
108  }
109  $getterMethodName = 'is' . $upperCasePropertyName;
110  if (is_callable([$subject, $getterMethodName])) {
111  return $subject->{$getterMethodName}();
112  }
113  $getterMethodName = 'has' . $upperCasePropertyName;
114  if (is_callable([$subject, $getterMethodName])) {
115  return $subject->{$getterMethodName}();
116  }
117  if (property_exists($subject, $propertyName)) {
118  return $subject->{$propertyName};
119  } else {
120  throw new Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1476109666);
121  }
122  }
123 
124  return null;
125  }
126 
140  public static function getPropertyPath($subject, $propertyPath)
141  {
142  $propertyPathSegments = explode('.', $propertyPath);
143  try {
144  foreach ($propertyPathSegments as $pathSegment) {
145  $subject = self::getPropertyInternal($subject, $pathSegment);
146  }
147  } catch (Exception\PropertyNotAccessibleException $error) {
148  return null;
149  }
150  return $subject;
151  }
152 
172  public static function setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess = false)
173  {
174  if (is_array($subject) || ($subject instanceof \ArrayAccess && !$forceDirectAccess)) {
175  $subject[$propertyName] = $propertyValue;
176  return true;
177  }
178  if (!is_object($subject)) {
179  throw new \InvalidArgumentException('subject must be an object or array, ' . gettype($subject) . ' given.', 1237301368);
180  }
181  if (!is_string($propertyName)) {
182  throw new \InvalidArgumentException('Given property name is not of type string.', 1231178878);
183  }
184  $result = true;
185  if ($forceDirectAccess) {
186  if (property_exists($subject, $propertyName)) {
187  $propertyReflection = new PropertyReflection($subject, $propertyName);
188  $propertyReflection->setAccessible(true);
189  $propertyReflection->setValue($subject, $propertyValue);
190  } else {
191  $subject->{$propertyName} = $propertyValue;
192  }
193  return $result;
194  }
195  $setterMethodName = self::buildSetterMethodName($propertyName);
196  if (is_callable([$subject, $setterMethodName])) {
197  $subject->{$setterMethodName}($propertyValue);
198  } elseif (property_exists($subject, $propertyName)) {
199  $reflection = new PropertyReflection($subject, $propertyName);
200  if ($reflection->isPublic()) {
201  $subject->{$propertyName} = $propertyValue;
202  } else {
203  $result = false;
204  }
205  } else {
206  $result = false;
207  }
208  return $result;
209  }
210 
223  public static function getGettablePropertyNames($object)
224  {
225  if (!is_object($object)) {
226  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1237301369);
227  }
228  if ($object instanceof \stdClass) {
229  $declaredPropertyNames = array_keys((array)$object);
230  } else {
231  $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
232  }
233  foreach (get_class_methods($object) as $methodName) {
234  if (is_callable([$object, $methodName])) {
235  if (substr($methodName, 0, 2) === 'is') {
236  $declaredPropertyNames[] = lcfirst(substr($methodName, 2));
237  }
238  if (substr($methodName, 0, 3) === 'get') {
239  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
240  }
241  if (substr($methodName, 0, 3) === 'has') {
242  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
243  }
244  }
245  }
246  $propertyNames = array_unique($declaredPropertyNames);
247  sort($propertyNames);
248  return $propertyNames;
249  }
250 
263  public static function getSettablePropertyNames($object)
264  {
265  if (!is_object($object)) {
266  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1264022994);
267  }
268  if ($object instanceof \stdClass) {
269  $declaredPropertyNames = array_keys((array)$object);
270  } else {
271  $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
272  }
273  foreach (get_class_methods($object) as $methodName) {
274  if (substr($methodName, 0, 3) === 'set' && is_callable([$object, $methodName])) {
275  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
276  }
277  }
278  $propertyNames = array_unique($declaredPropertyNames);
279  sort($propertyNames);
280  return $propertyNames;
281  }
282 
292  public static function isPropertySettable($object, $propertyName)
293  {
294  if (!is_object($object)) {
295  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828920);
296  }
297  if ($object instanceof \stdClass && array_search($propertyName, array_keys(get_object_vars($object))) !== false) {
298  return true;
299  } elseif (array_search($propertyName, array_keys(get_class_vars(get_class($object)))) !== false) {
300  return true;
301  }
302  return is_callable([$object, self::buildSetterMethodName($propertyName)]);
303  }
304 
314  public static function isPropertyGettable($object, $propertyName)
315  {
316  if (!is_object($object)) {
317  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828921);
318  }
319  if ($object instanceof \ArrayAccess && isset($object[$propertyName])) {
320  return true;
321  } elseif ($object instanceof \stdClass && isset($object->$propertyName)) {
322  return true;
323  }
324  if (is_callable([$object, 'get' . ucfirst($propertyName)])) {
325  return true;
326  }
327  if (is_callable([$object, 'has' . ucfirst($propertyName)])) {
328  return true;
329  }
330  if (is_callable([$object, 'is' . ucfirst($propertyName)])) {
331  return true;
332  }
333  if (property_exists($object, $propertyName)) {
334  $propertyReflection = new PropertyReflection($object, $propertyName);
335  return $propertyReflection->isPublic();
336  }
337  return false;
338  }
339 
350  public static function getGettableProperties($object)
351  {
352  if (!is_object($object)) {
353  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1237301370);
354  }
355  $properties = [];
356  foreach (self::getGettablePropertyNames($object) as $propertyName) {
357  $properties[$propertyName] = self::getPropertyInternal($object, $propertyName);
358  }
359  return $properties;
360  }
361 
370  public static function buildSetterMethodName($propertyName)
371  {
372  return 'set' . ucfirst($propertyName);
373  }
374 }
static getPropertyPath($subject, $propertyPath)
static isPropertyGettable($object, $propertyName)
static isPropertySettable($object, $propertyName)
static getProperty($subject, $propertyName, $forceDirectAccess=false)
static getPropertyInternal($subject, $propertyName, $forceDirectAccess=false)
static setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess=false)