ILIAS  release_8 Revision v8.24
class.ilCtrlStructureReader.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
5/* Copyright (c) 2021 Thibeau Fuhrer <thf@studer-raimann.ch> Extended GPL, see docs/LICENSE */
6
7require_once __DIR__ . '/../../../../libs/composer/vendor/autoload.php';
8
17{
22 public const REGEX_GUI_CLASS_NAME = '/^class\.([A-z0-9]*(GUI))\.php$/';
23
29 private const REGEX_PHPDOC_CALLS = '/(((?i)@ilctrl_calls)\s*({CLASS_NAME}(:\s*|\s*:\s*))\K)([A-z0-9,\s])*/';
30
35 private const REGEX_PHPDOC_CALLED_BYS = '/(((?i)@ilctrl_iscalledby)\s*({CLASS_NAME}(:\s*|\s*:\s*))\K)([A-z0-9,\s])*/';
36
43
50
56 private bool $is_executed = false;
57
63 private string $ilias_path;
64
72 {
73 $this->ilias_path = rtrim(
74 (defined('ILIAS_ABSOLUTE_PATH')) ?
75 ILIAS_ABSOLUTE_PATH : dirname(__FILE__, 5),
76 '/'
77 );
78
79 $this->cid_generator = $cid_generator;
80 $this->iterator = $iterator;
81 }
82
88 public function isExecuted(): bool
89 {
90 return $this->is_executed;
91 }
92
98 public function readStructure(): array
99 {
100 $base_classes = $structure = [];
101 foreach ($this->iterator as $class_name => $path) {
102 // skip iteration if class doesn't meet ILIAS GUI class criteria.
103 if (!$this->isGuiClass($path)) {
104 continue;
105 }
106
107 $lower_class_name = strtolower($class_name);
108 try {
109 // the classes need to be required manually, because
110 // the autoload classmap might not include the plugin
111 // classes when an update is triggered (small structure
112 // reload).
113 require_once $path;
114
115 $reflection = ($this->isNamespaced($class_name)) ?
116 new ReflectionClass("\\$class_name") :
117 new ReflectionClass($class_name)
118 ;
119
120 $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_CID] = $this->cid_generator->getCid();
121 $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_NAME] = $class_name;
122 $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_PATH] = $this->getRelativePath($path);
123 $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_CHILDREN] = $this->getChildren($reflection);
124 $structure[$lower_class_name][ilCtrlStructureInterface::KEY_CLASS_PARENTS] = $this->getParents($reflection);
125
126 // temporarily store base classes in order to filer the
127 // structure afterwards.
128 if (in_array(ilCtrlBaseClassInterface::class, $reflection->getInterfaceNames(), true)) {
129 $base_classes[] = $lower_class_name;
130 }
131 } catch (ReflectionException $e) {
132 continue;
133 }
134 }
135
136 $mapped_structure = (new ilCtrlStructureHelper($base_classes, $structure))
137 ->mapStructureReferences()
138 ->filterUnnecessaryEntries()
139 ->getStructure()
140 ;
141
142 $this->is_executed = true;
143
144 return $mapped_structure;
145 }
146
155 private function getReferencedClassesByReflection(ReflectionClass $reflection, string $regex): array
156 {
157 // abort if the class has no PHPDoc comment.
158 if (!$reflection->getDocComment()) {
159 return [];
160 }
161
162 // replace the classname placeholder with the
163 // actual one and execute the regex search.
164 $name = str_replace('\\', '\\\\', $reflection->getName());
165 $regex = str_replace('{CLASS_NAME}', $name, $regex);
166 preg_match_all($regex, $reflection->getDocComment(), $matches);
167
168 // the first array entry of $matches contains
169 // the list's of statements found.
170 if (empty($matches[0])) {
171 return [];
172 }
173
174 $referenced_classes = [];
175 foreach ($matches[0] as $class_list) {
176 // explode lists and strip all whitespaces.
177 foreach (explode(',', $class_list) as $class) {
178 $class_name = $this->stripWhitespaces($class);
179 if (!empty($class_name)) {
180 $referenced_classes[] = strtolower($class_name);
181 }
182 }
183 }
184
185 return $referenced_classes;
186 }
187
194 private function getRelativePath(string $absolute_path): string
195 {
196 // some paths might contain syntax like '../../../' etc.
197 // and realpath() resolves that in order to cut off the
198 // ilias installation path properly.
199 $absolute_path = realpath($absolute_path);
200
201 return '.' . str_replace($this->ilias_path, '', $absolute_path);
202 }
203
210 private function getChildren(ReflectionClass $reflection): array
211 {
212 return $this->getReferencedClassesByReflection($reflection, self::REGEX_PHPDOC_CALLS);
213 }
214
221 private function getParents(ReflectionClass $reflection): array
222 {
223 return $this->getReferencedClassesByReflection($reflection, self::REGEX_PHPDOC_CALLED_BYS);
224 }
225
233 private function stripWhitespaces(string $string): string
234 {
235 return (string) preg_replace('/\s+/', '', $string);
236 }
237
244 private function isGuiClass(string $path): bool
245 {
246 return (bool) preg_match(self::REGEX_GUI_CLASS_NAME, basename($path));
247 }
248
255 private function isNamespaced(string $class_name): bool
256 {
257 return (false !== strpos($class_name, '\\'));
258 }
259}
Class ilCtrlStructureCidGenerator.
Class ilCtrlStructureHelper.
Class ilCtrlStructureReader is responsible for reading ilCtrl's control structure.
isExecuted()
Returns whether this instance was already executed or not.
__construct(ilCtrlIteratorInterface $iterator, ilCtrlStructureCidGenerator $cid_generator)
ilCtrlStructureReader Constructor
isNamespaced(string $class_name)
Returns if the given classname is namespaced.
getReferencedClassesByReflection(ReflectionClass $reflection, string $regex)
Returns all classes referenced by an ilCtrl_Calls or ilCtrl_isCalledBy statement.
getChildren(ReflectionClass $reflection)
Helper function that returns all children references.
ilCtrlIteratorInterface $iterator
getRelativePath(string $absolute_path)
Returns a given path relative to the ILIAS absolute path.
isGuiClass(string $path)
Returns whether the given file/path matches ILIAS conventions.
readStructure()
Processes all classes within the ILIAS installation.
getParents(ReflectionClass $reflection)
Helper function that returns all parent references.
ilCtrlStructureCidGenerator $cid_generator
stripWhitespaces(string $string)
Helper function that replaces all whitespace characters from the given string.
Interface ilCtrlIteratorInterface.
const KEY_CLASS_CID
array key constants that are used for certain information.
$path
Definition: ltiservices.php:32
if($format !==null) $name
Definition: metadata.php:247