‪TYPO3CMS  9.5
ObjectAccess.php
Go to the documentation of this file.
1 <?php
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 
29 {
30  const ‪ACCESS_GET = 0;
31 
32  const ‪ACCESS_SET = 1;
33 
34  const ‪ACCESS_PUBLIC = 2;
35 
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  return ‪self::getPropertyInternal($subject, $propertyName, $forceDirectAccess);
63  }
64 
80  public static function ‪getPropertyInternal($subject, $propertyName, $forceDirectAccess = false)
81  {
82  // type check and conversion of iterator to numerically indexed array
83  if ($subject === null || is_scalar($subject)) {
84  return null;
85  }
86  if (!$forceDirectAccess && ($subject instanceof \SplObjectStorage || $subject instanceof ‪ObjectStorage)) {
87  $subject = iterator_to_array(clone $subject, false);
88  }
89 
90  // value get based on data type of $subject (possibly converted above)
91  if (($subject instanceof \ArrayAccess && $subject->offsetExists($propertyName)) || is_array($subject)) {
92  // isset() is safe; array_key_exists would only be needed to determine
93  // if the value is NULL - and that's already what we return as fallback.
94  if (isset($subject[$propertyName])) {
95  return $subject[$propertyName];
96  }
97  } elseif (is_object($subject)) {
98  if ($forceDirectAccess) {
99  if (property_exists($subject, $propertyName)) {
100  $propertyReflection = new \ReflectionProperty($subject, $propertyName);
101  if ($propertyReflection->isPublic()) {
102  return $propertyReflection->getValue($subject);
103  }
104  $propertyReflection->setAccessible(true);
105  return $propertyReflection->getValue($subject);
106  }
107  throw new Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1302855001);
108  }
109  $upperCasePropertyName = ucfirst($propertyName);
110  $getterMethodName = 'get' . $upperCasePropertyName;
111  if (is_callable([$subject, $getterMethodName])) {
112  return $subject->{$getterMethodName}();
113  }
114  $getterMethodName = 'is' . $upperCasePropertyName;
115  if (is_callable([$subject, $getterMethodName])) {
116  return $subject->{$getterMethodName}();
117  }
118  $getterMethodName = 'has' . $upperCasePropertyName;
119  if (is_callable([$subject, $getterMethodName])) {
120  return $subject->{$getterMethodName}();
121  }
122  if (property_exists($subject, $propertyName)) {
123  return $subject->{$propertyName};
124  }
125  throw new Exception\PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1476109666);
126  }
127 
128  return null;
129  }
130 
144  public static function ‪getPropertyPath($subject, $propertyPath)
145  {
146  $propertyPathSegments = explode('.', $propertyPath);
147  try {
148  foreach ($propertyPathSegments as $pathSegment) {
149  $subject = self::getPropertyInternal($subject, $pathSegment);
150  }
151  } catch (‪Exception\PropertyNotAccessibleException $error) {
152  return null;
153  }
154  return $subject;
155  }
156 
176  public static function ‪setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess = false)
177  {
178  if (is_array($subject) || ($subject instanceof \ArrayAccess && !$forceDirectAccess)) {
179  $subject[$propertyName] = $propertyValue;
180  return true;
181  }
182  if (!is_object($subject)) {
183  throw new \InvalidArgumentException('subject must be an object or array, ' . gettype($subject) . ' given.', 1237301368);
184  }
185  if (!is_string($propertyName)) {
186  throw new \InvalidArgumentException('Given property name is not of type string.', 1231178878);
187  }
188  $result = true;
189  if ($forceDirectAccess) {
190  if (property_exists($subject, $propertyName)) {
191  $propertyReflection = new \ReflectionProperty($subject, $propertyName);
192  $propertyReflection->setAccessible(true);
193  $propertyReflection->setValue($subject, $propertyValue);
194  } else {
195  $subject->{$propertyName} = $propertyValue;
196  }
197  return $result;
198  }
199  $setterMethodName = self::buildSetterMethodName($propertyName);
200  if (is_callable([$subject, $setterMethodName])) {
201  $subject->{$setterMethodName}($propertyValue);
202  } elseif (property_exists($subject, $propertyName)) {
203  $reflection = new \ReflectionProperty($subject, $propertyName);
204  if ($reflection->isPublic()) {
205  $subject->{$propertyName} = $propertyValue;
206  } else {
207  $result = false;
208  }
209  } else {
210  $result = false;
211  }
212  return $result;
213  }
214 
227  public static function ‪getGettablePropertyNames($object)
228  {
229  if (!is_object($object)) {
230  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1237301369);
231  }
232  if ($object instanceof \stdClass) {
233  $properties = array_keys((array)$object);
234  sort($properties);
235  return $properties;
236  }
237 
238  $reflection = new \ReflectionClass($object);
239  $declaredPropertyNames = array_map(
240  function (\ReflectionProperty $property) {
241  return $property->getName();
242  },
243  $reflection->getProperties(\ReflectionProperty::IS_PUBLIC)
244  );
245  foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
246  $methodParameters = $method->getParameters();
247  if (!empty($methodParameters)) {
248  foreach ($methodParameters as $parameter) {
249  if (!$parameter->isOptional()) {
250  continue 2;
251  }
252  }
253  }
254  $methodName = $method->getName();
255  if (strpos($methodName, 'is') === 0) {
256  $declaredPropertyNames[] = lcfirst(substr($methodName, 2));
257  }
258  if (strpos($methodName, 'get') === 0) {
259  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
260  }
261  if (strpos($methodName, 'has') === 0) {
262  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
263  }
264  }
265  $propertyNames = array_unique($declaredPropertyNames);
266  sort($propertyNames);
267 
268  return $propertyNames;
269  }
270 
283  public static function ‪getSettablePropertyNames($object)
284  {
285  if (!is_object($object)) {
286  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1264022994);
287  }
288  if ($object instanceof \stdClass) {
289  $declaredPropertyNames = array_keys((array)$object);
290  } else {
291  $declaredPropertyNames = array_keys(get_class_vars(get_class($object)));
292  }
293  foreach (get_class_methods($object) as $methodName) {
294  if (strpos($methodName, 'set') === 0 && is_callable([$object, $methodName])) {
295  $declaredPropertyNames[] = lcfirst(substr($methodName, 3));
296  }
297  }
298  $propertyNames = array_unique($declaredPropertyNames);
299  sort($propertyNames);
300  return $propertyNames;
301  }
302 
312  public static function ‪isPropertySettable($object, $propertyName)
313  {
314  if (!is_object($object)) {
315  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828920);
316  }
317  if ($object instanceof \stdClass && array_key_exists($propertyName, get_object_vars($object))) {
318  return true;
319  }
320  if (array_key_exists($propertyName, get_class_vars(get_class($object)))) {
321  return true;
322  }
323  return is_callable([$object, self::buildSetterMethodName($propertyName)]);
324  }
325 
335  public static function ‪isPropertyGettable($object, $propertyName)
336  {
337  if (!is_object($object)) {
338  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828921);
339  }
340  if ($object instanceof \ArrayAccess && isset($object[$propertyName])) {
341  return true;
342  }
343  if ($object instanceof \stdClass && isset($object->$propertyName)) {
344  return true;
345  }
346  if (is_callable([$object, 'get' . ucfirst($propertyName)])) {
347  return true;
348  }
349  if (is_callable([$object, 'has' . ucfirst($propertyName)])) {
350  return true;
351  }
352  if (is_callable([$object, 'is' . ucfirst($propertyName)])) {
353  return true;
354  }
355  if (property_exists($object, $propertyName)) {
356  $propertyReflection = new \ReflectionProperty($object, $propertyName);
357  return $propertyReflection->isPublic();
358  }
359  return false;
360  }
361 
372  public static function ‪getGettableProperties($object)
373  {
374  if (!is_object($object)) {
375  throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1237301370);
376  }
377  $properties = [];
378  foreach (self::getGettablePropertyNames($object) as $propertyName) {
379  $properties[$propertyName] = self::getPropertyInternal($object, $propertyName);
380  }
381  return $properties;
382  }
383 
392  public static function ‪buildSetterMethodName($propertyName)
393  {
394  return 'set' . ucfirst($propertyName);
395  }
396 }
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\isPropertySettable
‪static bool isPropertySettable($object, $propertyName)
Definition: ObjectAccess.php:312
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\setProperty
‪static bool setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess=false)
Definition: ObjectAccess.php:176
‪TYPO3\CMS\Extbase\Reflection\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\ACCESS_GET
‪const ACCESS_GET
Definition: ObjectAccess.php:30
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getSettablePropertyNames
‪static array getSettablePropertyNames($object)
Definition: ObjectAccess.php:283
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\ACCESS_PUBLIC
‪const ACCESS_PUBLIC
Definition: ObjectAccess.php:34
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess
Definition: ObjectAccess.php:29
‪TYPO3\CMS\Extbase\Persistence\ObjectStorage
Definition: ObjectStorage.php:26
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getGettableProperties
‪static array getGettableProperties($object)
Definition: ObjectAccess.php:372
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\isPropertyGettable
‪static bool isPropertyGettable($object, $propertyName)
Definition: ObjectAccess.php:335
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\buildSetterMethodName
‪static string buildSetterMethodName($propertyName)
Definition: ObjectAccess.php:392
‪TYPO3\CMS\Extbase\Reflection
Definition: ClassSchema.php:2
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getPropertyInternal
‪static mixed getPropertyInternal($subject, $propertyName, $forceDirectAccess=false)
Definition: ObjectAccess.php:80
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getProperty
‪static mixed getProperty($subject, $propertyName, $forceDirectAccess=false)
Definition: ObjectAccess.php:54
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getPropertyPath
‪static mixed getPropertyPath($subject, $propertyPath)
Definition: ObjectAccess.php:144
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\ACCESS_SET
‪const ACCESS_SET
Definition: ObjectAccess.php:32
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getGettablePropertyNames
‪static array getGettablePropertyNames($object)
Definition: ObjectAccess.php:227