TYPO3 CMS  TYPO3_6-2
ReflectionService.php
Go to the documentation of this file.
1 <?php
3 
18 
26 
31  protected $objectManager;
32 
38  protected $initialized = FALSE;
39 
43  protected $dataCache;
44 
50  protected $detectClassChanges = FALSE;
51 
58  protected $reflectedClassNames = array();
59 
65  protected $taggedClasses = array();
66 
72  protected $classTagsValues = array();
73 
79  protected $methodTagsValues = array();
80 
87  protected $methodParameters = array();
88 
94  protected $classPropertyNames = array();
95 
101  protected $classMethodNames = array();
102 
108  protected $propertyTagsValues = array();
109 
115  protected $ignoredTags = array('package', 'subpackage', 'license', 'copyright', 'author', 'version', 'const');
116 
127  protected $dataCacheNeedsUpdate = FALSE;
128 
134  protected $classSchemata = array();
135 
141 
145  protected $cacheIdentifier;
146 
152  protected $methodReflections = array();
153 
162  public function setDataCache(\TYPO3\CMS\Core\Cache\Frontend\VariableFrontend $dataCache) {
163  $this->dataCache = $dataCache;
164  }
165 
172  public function initialize() {
173  if ($this->initialized) {
174  throw new \TYPO3\CMS\Extbase\Reflection\Exception('The Reflection Service can only be initialized once.', 1232044696);
175  }
176  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
177  $this->cacheIdentifier = 'ReflectionData_' . $frameworkConfiguration['extensionName'];
178  $this->loadFromCache();
179  $this->initialized = TRUE;
180  }
181 
187  public function isInitialized() {
188  return $this->initialized;
189  }
190 
196  public function shutdown() {
197  if ($this->dataCacheNeedsUpdate) {
198  $this->saveToCache();
199  }
200  $this->initialized = FALSE;
201  }
202 
209  public function getClassPropertyNames($className) {
210  if (!isset($this->reflectedClassNames[$className])) {
211  $this->reflectClass($className);
212  }
213  return isset($this->classPropertyNames[$className]) ? $this->classPropertyNames[$className] : array();
214  }
215 
222  public function getClassSchema($classNameOrObject) {
223  $className = is_object($classNameOrObject) ? get_class($classNameOrObject) : $classNameOrObject;
224  if (isset($this->classSchemata[$className])) {
225  return $this->classSchemata[$className];
226  } else {
227  return $this->buildClassSchema($className);
228  }
229  }
230 
239  public function hasMethod($className, $methodName) {
240  try {
241  if (!array_key_exists($className, $this->classMethodNames) || !array_key_exists($methodName, $this->classMethodNames[$className])) {
242  $this->getMethodReflection($className, $methodName);
243  $this->classMethodNames[$className][$methodName] = TRUE;
244  }
245  } catch (\ReflectionException $e) {
246  // Method does not exist. Store this information in cache.
247  $this->classMethodNames[$className][$methodName] = NULL;
248  }
249  return isset($this->classMethodNames[$className][$methodName]);
250  }
251 
259  public function getMethodTagsValues($className, $methodName) {
260  if (!isset($this->methodTagsValues[$className][$methodName])) {
261  $method = $this->getMethodReflection($className, $methodName);
262  $this->methodTagsValues[$className][$methodName] = array();
263  foreach ($method->getTagsValues() as $tag => $values) {
264  if (array_search($tag, $this->ignoredTags) === FALSE) {
265  $this->methodTagsValues[$className][$methodName][$tag] = $values;
266  }
267  }
268  }
269  return $this->methodTagsValues[$className][$methodName];
270  }
271 
280  public function getMethodParameters($className, $methodName) {
281  if (!isset($this->methodParameters[$className][$methodName])) {
282  $method = $this->getMethodReflection($className, $methodName);
283  $this->methodParameters[$className][$methodName] = array();
284  foreach ($method->getParameters() as $parameterPosition => $parameter) {
285  $this->methodParameters[$className][$methodName][$parameter->getName()] = $this->convertParameterReflectionToArray($parameter, $parameterPosition, $method);
286  }
287  }
288  return $this->methodParameters[$className][$methodName];
289  }
290 
298  public function getPropertyTagsValues($className, $propertyName) {
299  if (!isset($this->reflectedClassNames[$className])) {
300  $this->reflectClass($className);
301  }
302  if (!isset($this->propertyTagsValues[$className])) {
303  return array();
304  }
305  return isset($this->propertyTagsValues[$className][$propertyName]) ? $this->propertyTagsValues[$className][$propertyName] : array();
306  }
307 
317  public function getPropertyTagValues($className, $propertyName, $tag) {
318  if (!isset($this->reflectedClassNames[$className])) {
319  $this->reflectClass($className);
320  }
321  if (!isset($this->propertyTagsValues[$className][$propertyName])) {
322  return array();
323  }
324  return isset($this->propertyTagsValues[$className][$propertyName][$tag]) ? $this->propertyTagsValues[$className][$propertyName][$tag] : array();
325  }
326 
335  public function isClassReflected($className) {
336  return isset($this->reflectedClassNames[$className]);
337  }
338 
347  public function isClassTaggedWith($className, $tag) {
348  if ($this->initialized === FALSE) {
349  return FALSE;
350  }
351  if (!isset($this->reflectedClassNames[$className])) {
352  $this->reflectClass($className);
353  }
354  if (!isset($this->classTagsValues[$className])) {
355  return FALSE;
356  }
357  return isset($this->classTagsValues[$className][$tag]);
358  }
359 
369  public function isPropertyTaggedWith($className, $propertyName, $tag) {
370  if (!isset($this->reflectedClassNames[$className])) {
371  $this->reflectClass($className);
372  }
373  if (!isset($this->propertyTagsValues[$className])) {
374  return FALSE;
375  }
376  if (!isset($this->propertyTagsValues[$className][$propertyName])) {
377  return FALSE;
378  }
379  return isset($this->propertyTagsValues[$className][$propertyName][$tag]);
380  }
381 
388  protected function reflectClass($className) {
389  $class = new \TYPO3\CMS\Extbase\Reflection\ClassReflection($className);
390  $this->reflectedClassNames[$className] = time();
391  foreach ($class->getTagsValues() as $tag => $values) {
392  if (array_search($tag, $this->ignoredTags) === FALSE) {
393  $this->taggedClasses[$tag][] = $className;
394  $this->classTagsValues[$className][$tag] = $values;
395  }
396  }
397  foreach ($class->getProperties() as $property) {
398  $propertyName = $property->getName();
399  $this->classPropertyNames[$className][] = $propertyName;
400  foreach ($property->getTagsValues() as $tag => $values) {
401  if (array_search($tag, $this->ignoredTags) === FALSE) {
402  $this->propertyTagsValues[$className][$propertyName][$tag] = $values;
403  }
404  }
405  }
406  foreach ($class->getMethods() as $method) {
407  $methodName = $method->getName();
408  foreach ($method->getTagsValues() as $tag => $values) {
409  if (array_search($tag, $this->ignoredTags) === FALSE) {
410  $this->methodTagsValues[$className][$methodName][$tag] = $values;
411  }
412  }
413  foreach ($method->getParameters() as $parameterPosition => $parameter) {
414  $this->methodParameters[$className][$methodName][$parameter->getName()] = $this->convertParameterReflectionToArray($parameter, $parameterPosition, $method);
415  }
416  }
417  ksort($this->reflectedClassNames);
418  $this->dataCacheNeedsUpdate = TRUE;
419  }
420 
428  protected function buildClassSchema($className) {
429  if (!class_exists($className)) {
430  throw new \TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException('The classname "' . $className . '" was not found and thus can not be reflected.', 1278450972);
431  }
432  $classSchema = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Reflection\\ClassSchema', $className);
433  if (is_subclass_of($className, 'TYPO3\\CMS\\Extbase\\DomainObject\\AbstractEntity')) {
434  $classSchema->setModelType(\TYPO3\CMS\Extbase\Reflection\ClassSchema::MODELTYPE_ENTITY);
435  $possibleRepositoryClassName = ClassNamingUtility::translateModelNameToRepositoryName($className);
436  if (class_exists($possibleRepositoryClassName)) {
437  $classSchema->setAggregateRoot(TRUE);
438  }
439  } elseif (is_subclass_of($className, 'TYPO3\\CMS\\Extbase\\DomainObject\\AbstractValueObject')) {
440  $classSchema->setModelType(\TYPO3\CMS\Extbase\Reflection\ClassSchema::MODELTYPE_VALUEOBJECT);
441  }
442  foreach ($this->getClassPropertyNames($className) as $propertyName) {
443  if (!$this->isPropertyTaggedWith($className, $propertyName, 'transient') && $this->isPropertyTaggedWith($className, $propertyName, 'var')) {
444  $cascadeTagValues = $this->getPropertyTagValues($className, $propertyName, 'cascade');
445  $classSchema->addProperty($propertyName, implode(' ', $this->getPropertyTagValues($className, $propertyName, 'var')), $this->isPropertyTaggedWith($className, $propertyName, 'lazy'), $cascadeTagValues[0]);
446  }
447  if ($this->isPropertyTaggedWith($className, $propertyName, 'uuid')) {
448  $classSchema->setUuidPropertyName($propertyName);
449  }
450  if ($this->isPropertyTaggedWith($className, $propertyName, 'identity')) {
451  $classSchema->markAsIdentityProperty($propertyName);
452  }
453  }
454  $this->classSchemata[$className] = $classSchema;
455  $this->dataCacheNeedsUpdate = TRUE;
456  return $classSchema;
457  }
458 
467  protected function convertParameterReflectionToArray(\ReflectionParameter $parameter, $parameterPosition, \ReflectionMethod $method = NULL) {
468  $parameterInformation = array(
469  'position' => $parameterPosition,
470  'byReference' => $parameter->isPassedByReference(),
471  'array' => $parameter->isArray(),
472  'optional' => $parameter->isOptional(),
473  'allowsNull' => $parameter->allowsNull()
474  );
475  $parameterClass = $parameter->getClass();
476  $parameterInformation['class'] = $parameterClass !== NULL ? $parameterClass->getName() : NULL;
477  if ($parameter->isDefaultValueAvailable()) {
478  $parameterInformation['defaultValue'] = $parameter->getDefaultValue();
479  }
480  if ($parameterClass !== NULL) {
481  $parameterInformation['type'] = $parameterClass->getName();
482  } elseif ($method !== NULL) {
483  $methodTagsAndValues = $this->getMethodTagsValues($method->getDeclaringClass()->getName(), $method->getName());
484  if (isset($methodTagsAndValues['param']) && isset($methodTagsAndValues['param'][$parameterPosition])) {
485  $explodedParameters = explode(' ', $methodTagsAndValues['param'][$parameterPosition]);
486  if (count($explodedParameters) >= 2) {
487  $parameterInformation['type'] = $explodedParameters[0];
488  }
489  }
490  }
491  if (isset($parameterInformation['type']) && $parameterInformation['type'][0] === '\\') {
492  $parameterInformation['type'] = substr($parameterInformation['type'], 1);
493  }
494  return $parameterInformation;
495  }
496 
504  protected function getMethodReflection($className, $methodName) {
505  $this->dataCacheNeedsUpdate = TRUE;
506  if (!isset($this->methodReflections[$className][$methodName])) {
507  $this->methodReflections[$className][$methodName] = new \TYPO3\CMS\Extbase\Reflection\MethodReflection($className, $methodName);
508  }
509  return $this->methodReflections[$className][$methodName];
510  }
511 
517  protected function loadFromCache() {
518  $data = $this->dataCache->get($this->cacheIdentifier);
519  if ($data !== FALSE) {
520  foreach ($data as $propertyName => $propertyValue) {
521  $this->{$propertyName} = $propertyValue;
522  }
523  }
524  }
525 
532  protected function saveToCache() {
533  if (!is_object($this->dataCache)) {
534  throw new \TYPO3\CMS\Extbase\Reflection\Exception('A cache must be injected before initializing the Reflection Service.', 1232044697);
535  }
536  $data = array();
537  $propertyNames = array(
538  'reflectedClassNames',
539  'classPropertyNames',
540  'classMethodNames',
541  'classTagsValues',
542  'methodTagsValues',
543  'methodParameters',
544  'propertyTagsValues',
545  'taggedClasses',
546  'classSchemata'
547  );
548  foreach ($propertyNames as $propertyName) {
549  $data[$propertyName] = $this->{$propertyName};
550  }
551  $this->dataCache->set($this->cacheIdentifier, $data);
552  $this->dataCacheNeedsUpdate = FALSE;
553  }
554 }
getPropertyTagValues($className, $propertyName, $tag)
setDataCache(\TYPO3\CMS\Core\Cache\Frontend\VariableFrontend $dataCache)
isPropertyTaggedWith($className, $propertyName, $tag)
convertParameterReflectionToArray(\ReflectionParameter $parameter, $parameterPosition, \ReflectionMethod $method=NULL)