ILIAS  trunk Revision v11.0_alpha-2645-g16283d3b3f8
class.ilCtrlStructureReader.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 require_once __DIR__ . '/../../../../../vendor/composer/vendor/autoload.php';
22 
31 {
36  public const REGEX_GUI_CLASS_NAME = '/^class\.([A-z0-9]*(GUI))\.php$/';
37 
43  private const REGEX_PHPDOC_CALLS = '/(((?i)@ilctrl_calls)\s*({CLASS_NAME}(:\s*|\s*:\s*))\K)([A-z0-9,\s])*/';
44 
49  private const REGEX_PHPDOC_CALLED_BYS = '/(((?i)@ilctrl_iscalledby)\s*({CLASS_NAME}(:\s*|\s*:\s*))\K)([A-z0-9,\s])*/';
50 
57 
64 
70  private bool $is_executed = false;
71 
77  private string $ilias_path;
78 
85  public function __construct(ilCtrlIteratorInterface $iterator, ilCtrlStructureCidGenerator $cid_generator)
86  {
87  $this->ilias_path = rtrim(
88  (defined('ILIAS_ABSOLUTE_PATH')) ?
89  ILIAS_ABSOLUTE_PATH : dirname(__FILE__, 6),
90  '/'
91  );
92 
93  $this->cid_generator = $cid_generator;
94  $this->iterator = $iterator;
95  }
96 
102  public function isExecuted(): bool
103  {
104  return $this->is_executed;
105  }
106 
112  public function readStructure(): array
113  {
114  $base_classes = $structure = [];
115  foreach ($this->iterator as $class_name => $path) {
116  // skip iteration if class doesn't meet ILIAS GUI class criteria.
117  if (!$this->isGuiClass($path)) {
118  continue;
119  }
120 
121  $lower_class_name = strtolower($class_name);
122  try {
123  // the classes need to be required manually, because
124  // the autoload classmap might not include the plugin
125  // classes when an update is triggered (small structure
126  // reload).
127  require_once $path;
128 
129  $reflection = ($this->isNamespaced($class_name)) ?
130  new ReflectionClass("\\$class_name") :
131  new ReflectionClass($class_name)
132  ;
133 
134  $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_CID] = $this->cid_generator->getCid();
135  $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_NAME] = $class_name;
136  $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_PATH] = $this->getRelativePath($path);
137  $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_CHILDREN] = $this->getChildren($reflection);
138  $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_PARENTS] = $this->getParents($reflection);
139 
140  // temporarily store base classes in order to filer the
141  // structure afterwards.
142  if (in_array(ilCtrlBaseClassInterface::class, $reflection->getInterfaceNames(), true)) {
143  $base_classes[] = $lower_class_name;
144  }
145  } catch (ReflectionException $e) {
146  continue;
147  }
148  }
149 
150  $mapped_structure = (new ilCtrlStructureHelper($base_classes, $structure))
151  ->mapStructureReferences()
152  ->filterUnnecessaryEntries()
153  ->getStructure()
154  ;
155 
156  $this->is_executed = true;
157 
158  return $mapped_structure;
159  }
160 
169  private function getReferencedClassesByReflection(ReflectionClass $reflection, string $regex): array
170  {
171  // abort if the class has no PHPDoc comment.
172  if (!$reflection->getDocComment()) {
173  return [];
174  }
175 
176  // replace the classname placeholder with the
177  // actual one and execute the regex search.
178  $name = str_replace('\\', '\\\\', $reflection->getName());
179  $regex = str_replace('{CLASS_NAME}', $name, $regex);
180  preg_match_all($regex, $reflection->getDocComment(), $matches);
181 
182  // the first array entry of $matches contains
183  // the list's of statements found.
184  if (empty($matches[0])) {
185  return [];
186  }
187 
188  $referenced_classes = [];
189  foreach ($matches[0] as $class_list) {
190  // explode lists and strip all whitespaces.
191  foreach (explode(',', $class_list) as $class) {
192  $class_name = $this->stripWhitespaces($class);
193  if (!empty($class_name)) {
194  $referenced_classes[] = strtolower($class_name);
195  }
196  }
197  }
198 
199  return $referenced_classes;
200  }
201 
208  private function getRelativePath(string $absolute_path): string
209  {
210  // some paths might contain syntax like '../../../' etc.
211  // and realpath() resolves that in order to cut off the
212  // ilias installation path properly.
213  $absolute_path = realpath($absolute_path);
214 
215  return '.' . str_replace($this->ilias_path, '', $absolute_path);
216  }
217 
224  private function getChildren(ReflectionClass $reflection): array
225  {
226  return $this->getReferencedClassesByReflection($reflection, self::REGEX_PHPDOC_CALLS);
227  }
228 
235  private function getParents(ReflectionClass $reflection): array
236  {
237  return $this->getReferencedClassesByReflection($reflection, self::REGEX_PHPDOC_CALLED_BYS);
238  }
239 
247  private function stripWhitespaces(string $string): string
248  {
249  return (string) preg_replace('/\s+/', '', $string);
250  }
251 
258  private function isGuiClass(string $path): bool
259  {
260  return (bool) preg_match(self::REGEX_GUI_CLASS_NAME, basename($path));
261  }
262 
269  private function isNamespaced(string $class_name): bool
270  {
271  return (false !== strpos($class_name, '\\'));
272  }
273 }
readStructure()
Processes all classes within the ILIAS installation.
ilCtrlIteratorInterface $iterator
Class ilCtrlStructureHelper.
__construct(ilCtrlIteratorInterface $iterator, ilCtrlStructureCidGenerator $cid_generator)
ilCtrlStructureReader Constructor
Class ilCtrlStructureCidGenerator.
isNamespaced(string $class_name)
Returns if the given classname is namespaced.
isExecuted()
Returns whether this instance was already executed or not.
stripWhitespaces(string $string)
Helper function that replaces all whitespace characters from the given string.
getReferencedClassesByReflection(ReflectionClass $reflection, string $regex)
Returns all classes referenced by an ilCtrl_Calls or ilCtrl_isCalledBy statement. ...
ilCtrlStructureCidGenerator $cid_generator
getChildren(ReflectionClass $reflection)
Helper function that returns all children references.
$path
Definition: ltiservices.php:29
Class ilCtrlStructureReader is responsible for reading ilCtrl&#39;s control structure.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const KEY_CLASS_CID
array key constants that are used for certain information.
getRelativePath(string $absolute_path)
Returns a given path relative to the ILIAS absolute path.
$structure
TOTAL STRUCTURE.
getParents(ReflectionClass $reflection)
Helper function that returns all parent references.
isGuiClass(string $path)
Returns whether the given file/path matches ILIAS conventions.