TYPO3  7.6
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 
54  public static function getProperty($subject, $propertyName, $forceDirectAccess = false)
55  {
56  if (!is_object($subject) && !is_array($subject)) {
57  throw new \InvalidArgumentException('$subject must be an object or array, ' . gettype($subject) . ' given.', 1237301367);
58  }
59  if (!is_string($propertyName) && (!is_array($subject) && !$subject instanceof \ArrayAccess)) {
60  throw new \InvalidArgumentException('Given property name is not of type string.', 1231178303);
61  }
62  $propertyExists = false;
63  $propertyValue = self::getPropertyInternal($subject, $propertyName, $forceDirectAccess, $propertyExists);
64  if ($propertyExists === true) {
65  return $propertyValue;
66  }
67  throw new Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject was not accessible.', 1263391473);
68  }
69 
86  public static function getPropertyInternal($subject, $propertyName, $forceDirectAccess, &$propertyExists)
87  {
88  if ($subject === null || is_scalar($subject)) {
89  return null;
90  }
91  $propertyExists = true;
92  if (is_array($subject)) {
93  if (array_key_exists($propertyName, $subject)) {
94  return $subject[$propertyName];
95  }
96  $propertyExists = false;
97  return null;
98  }
99  if ($forceDirectAccess === true) {
100  if (property_exists(get_class($subject), $propertyName)) {
101  $propertyReflection = new PropertyReflection(get_class($subject), $propertyName);
102  return $propertyReflection->getValue($subject);
103  } elseif (property_exists($subject, $propertyName)) {
104  return $subject->{$propertyName};
105  } else {
106  throw new Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1302855001);
107  }
108  }
109  if ($subject instanceof \SplObjectStorage || $subject instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
110  if (MathUtility::canBeInterpretedAsInteger($propertyName)) {
111  $index = 0;
112  foreach ($subject as $value) {
113  if ($index === (int)$propertyName) {
114  return $value;
115  }
116  $index++;
117  }
118  $propertyExists = false;
119  return null;
120  }
121  } elseif ($subject instanceof \ArrayAccess && isset($subject[$propertyName])) {
122  return $subject[$propertyName];
123  }
124  $getterMethodName = 'get' . ucfirst($propertyName);
125  if (is_callable(array($subject, $getterMethodName))) {
126  return $subject->{$getterMethodName}();
127  }
128  $getterMethodName = 'is' . ucfirst($propertyName);
129  if (is_callable(array($subject, $getterMethodName))) {
130  return $subject->{$getterMethodName}();
131  }
132  $getterMethodName = 'has' . ucfirst($propertyName);
133  if (is_callable(array($subject, $getterMethodName))) {
134  return $subject->{$getterMethodName}();
135  }
136  if (is_object($subject) && array_key_exists($propertyName, get_object_vars($subject))) {
137  return $subject->{$propertyName};
138  }
139  $propertyExists = false;
140  return null;
141  }
142 
156  public static function getPropertyPath($subject, $propertyPath)
157  {
158  $propertyPathSegments = explode('.', $propertyPath);
159  foreach ($propertyPathSegments as $pathSegment) {
160  $propertyExists = false;
161  $subject = self::getPropertyInternal($subject, $pathSegment, false, $propertyExists);
162  if (!$propertyExists || $subject === null) {
163  return $subject;
164  }
165  }
166  return $subject;
167  }
168 
188  public static function setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess = false)
189  {
190  if (is_array($subject)) {
191  $subject[$propertyName] = $propertyValue;
192  return true;
193  }
194  if (!is_object($subject)) {
195  throw new \InvalidArgumentException('subject must be an object or array, ' . gettype($subject) . ' given.', 1237301368);
196  }
197  if (!is_string($propertyName)) {
198  throw new \InvalidArgumentException('Given property name is not of type string.', 1231178878);
199  }
200  if ($forceDirectAccess === true) {
201  if (property_exists(get_class($subject), $propertyName)) {
202  $propertyReflection = new PropertyReflection(get_class($subject), $propertyName);
203  $propertyReflection->setAccessible(true);
204  $propertyReflection->setValue($subject, $propertyValue);
205  } else {
206  $subject->{$propertyName} = $propertyValue;
207  }
208  } elseif (is_callable(array($subject, $setterMethodName = self::buildSetterMethodName($propertyName)))) {
209  $subject->{$setterMethodName}($propertyValue);
210  } elseif ($subject instanceof \ArrayAccess) {
211  $subject[$propertyName] = $propertyValue;
212  } elseif (array_key_exists($propertyName, get_object_vars($subject))) {
213  $subject->{$propertyName} = $propertyValue;
214  } else {
215  return false;
216  }
217  return true;
218  }
219 
232  public static function getGettablePropertyNames($object)
233  {
234  if (!is_object($object)) {
235  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1237301369);
236  }
237  if ($object instanceof \stdClass) {
238  $declaredPropertyNames = array_keys(get_object_vars($object));
239  } else {
240  $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
241  }
242  foreach (get_class_methods($object) as $methodName) {
243  if (is_callable(array($object, $methodName))) {
244  if (substr($methodName, 0, 2) === 'is') {
245  $declaredPropertyNames[] = lcfirst(substr($methodName, 2));
246  }
247  if (substr($methodName, 0, 3) === 'get') {
248  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
249  }
250  if (substr($methodName, 0, 3) === 'has') {
251  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
252  }
253  }
254  }
255  $propertyNames = array_unique($declaredPropertyNames);
256  sort($propertyNames);
257  return $propertyNames;
258  }
259 
272  public static function getSettablePropertyNames($object)
273  {
274  if (!is_object($object)) {
275  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1264022994);
276  }
277  if ($object instanceof \stdClass) {
278  $declaredPropertyNames = array_keys(get_object_vars($object));
279  } else {
280  $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
281  }
282  foreach (get_class_methods($object) as $methodName) {
283  if (substr($methodName, 0, 3) === 'set' && is_callable(array($object, $methodName))) {
284  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
285  }
286  }
287  $propertyNames = array_unique($declaredPropertyNames);
288  sort($propertyNames);
289  return $propertyNames;
290  }
291 
301  public static function isPropertySettable($object, $propertyName)
302  {
303  if (!is_object($object)) {
304  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828920);
305  }
306  if ($object instanceof \stdClass && array_search($propertyName, array_keys(get_object_vars($object))) !== false) {
307  return true;
308  } elseif (array_search($propertyName, array_keys(get_class_vars(get_class($object)))) !== false) {
309  return true;
310  }
311  return is_callable(array($object, self::buildSetterMethodName($propertyName)));
312  }
313 
323  public static function isPropertyGettable($object, $propertyName)
324  {
325  if (!is_object($object)) {
326  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828921);
327  }
328  if ($object instanceof \ArrayAccess && isset($object[$propertyName]) === true) {
329  return true;
330  } elseif ($object instanceof \stdClass && array_search($propertyName, array_keys(get_object_vars($object))) !== false) {
331  return true;
332  } elseif ($object instanceof \ArrayAccess && isset($object[$propertyName]) === true) {
333  return true;
334  }
335  if (is_callable(array($object, 'get' . ucfirst($propertyName)))) {
336  return true;
337  }
338  if (is_callable(array($object, 'has' . ucfirst($propertyName)))) {
339  return true;
340  }
341  if (is_callable(array($object, 'is' . ucfirst($propertyName)))) {
342  return true;
343  }
344  return array_search($propertyName, array_keys(get_class_vars(get_class($object)))) !== false;
345  }
346 
357  public static function getGettableProperties($object)
358  {
359  if (!is_object($object)) {
360  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1237301370);
361  }
362  $properties = array();
363  foreach (self::getGettablePropertyNames($object) as $propertyName) {
364  $propertyExists = false;
365  $propertyValue = self::getPropertyInternal($object, $propertyName, false, $propertyExists);
366  if ($propertyExists === true) {
367  $properties[$propertyName] = $propertyValue;
368  }
369  }
370  return $properties;
371  }
372 
381  public static function buildSetterMethodName($propertyName)
382  {
383  return 'set' . ucfirst($propertyName);
384  }
385 }