ILIAS  trunk Revision v11.0_alpha-1811-gd2d5443e411
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
Reader.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
24 
25 class Reader
26 {
27  protected array $defines;
28  protected array $implements;
29  protected array $uses;
30  protected ?array $uses_temp = [];
31  protected array $contributes;
32  protected array $seeks;
33  protected ?array $seeks_temp = [];
34  protected array $provides;
35  protected array $pulls;
36  protected ?array $pulls_temp = [];
37  protected array $internal_out;
38  protected array $internal_in;
39  protected ?array $internal_in_temp = [];
40 
44  public function read(Component $component): OfComponent
45  {
46  $this->defines = [];
47  $this->implements = [];
48  $this->uses = [];
49  $this->contributes = [];
50  $this->seeks = [];
51  $this->provides = [];
52  $this->pulls = [];
53  $this->internal_out = [];
54  $this->internal_in = [];
55 
56  $probes = [
57  new SetProbe(fn($n, $v) => $this->addDefine($n, $v)),
58  new SetProbe(fn($n, $v) => $this->cacheImplement($n, $v)),
59  new GetProbe(fn($n) => $this->addUse($n)),
60  new SetProbe(fn($n, $v) => $this->cacheContribute($n, $v)),
61  new GetProbe(fn($n) => $this->addSeek($n)),
62  new SetProbe(fn($n, $v) => $this->cacheProvide($n, $v)),
63  new GetProbe(fn($n) => $this->addPull($n)),
64  new SetGetProbe(fn($n, $v) => $this->cacheInternalOut($n, $v), fn($n) => $this->addInternalIn($n))
65  ];
66  $component->init(...$probes);
67 
68  $this->resolveDependencies();
69  return $this->compileResult($component);
70  }
71 
72  protected function addDefine($_, $name)
73  {
74  if (!is_string($name) || !interface_exists($name)) {
75  throw new \LogicException(
76  "Only push interface-names into \$define."
77  );
78  }
79  $d = new Define(new Name($name));
80  $this->defines[] = $d;
81  }
82 
83  protected function addImplement(int $i, string $name, $value)
84  {
85  if (!is_callable($value)) {
86  throw new \LogicException(
87  "\$implements must be set with a callable."
88  );
89  }
90 
91  $this->populateTempArrays();
92  $impl = $value();
93  $dependencies = $this->flushTempArrays();
94 
95  if (!$impl instanceof $name) {
96  throw new \LogicException(
97  "Implementation for $name does not implement the correct interface."
98  );
99  }
100 
101  $aux = [
102  "class" => get_class($impl),
103  "position" => $i
104  ];
105  $d = new Out(OutType::IMPLEMENT, $name, $aux, $dependencies);
106  $this->implements[$i] = $d;
107  }
108 
109  protected function cacheImplement(string $name, $value)
110  {
111  $this->implements[] = [$name, $value];
112  }
113 
114  protected function addUse(string $name)
115  {
116  if (empty($this->uses_temp)) {
117  throw new \LogicException(
118  "\$use is only allowed when defining other dependencies"
119  );
120  }
121 
122  if (array_key_exists($name, $this->uses)) {
123  $d = $this->uses[$name];
124  } else {
125  $d = new In(InType::USE, $name);
126  }
127 
128  $this->uses_temp[0][$name] = $d;
129 
130  return $this->createMock($name);
131  }
132 
133  protected function addContribute(int $i, string $name, $value)
134  {
135  if (!is_callable($value)) {
136  throw new \LogicException(
137  "\$implements must be set with a callable."
138  );
139  }
140 
141  $this->populateTempArrays();
142  $impl = $value();
143  $dependencies = $this->flushTempArrays();
144 
145  if (!$impl instanceof $name) {
146  throw new \LogicException(
147  "Contribution for $name does not implement the correct interface."
148  );
149  }
150 
151  $aux = [
152  "position" => $i
153  ];
154  if ($impl instanceof \ILIAS\Component\EntryPoint) {
155  $aux["entry_point_name"] = $impl->getName();
156  }
157  $d = new Out(OutType::CONTRIBUTE, $name, $aux, $dependencies);
158  $this->contributes[$i] = $d;
159  }
160 
161  protected function cacheContribute(string $name, $value)
162  {
163  $this->contributes[] = [$name, $value];
164  }
165 
166  protected function addSeek(string $name)
167  {
168  if (empty($this->seeks_temp)) {
169  throw new \LogicException(
170  "\$seek is only allowed when defining other dependencies"
171  );
172  }
173 
174  if (array_key_exists($name, $this->seeks)) {
175  $d = $this->seeks[$name];
176  } else {
177  $d = new In(InType::SEEK, $name);
178  }
179 
180  $this->seeks_temp[0][$name] = $d;
181 
182  return [];
183  }
184 
185  protected function addProvide(int $i, string $name, $value)
186  {
187  if (!is_callable($value)) {
188  throw new \LogicException(
189  "\$implements must be set with a callable."
190  );
191  }
192 
193  $this->populateTempArrays();
194  $impl = $value();
195  $dependencies = $this->flushTempArrays();
196 
197  if (!$impl instanceof $name) {
198  throw new \LogicException(
199  "Provision for $name does not implement the correct interface."
200  );
201  }
202 
203  $d = new Out(OutType::PROVIDE, $name, null, $dependencies);
204  $this->provides[$i] = $d;
205  }
206 
207  protected function cacheProvide(string $name, $value)
208  {
209  $this->provides[] = [$name, $value];
210  }
211 
212  protected function addPull(string $name)
213  {
214  if (empty($this->pulls_temp)) {
215  throw new \LogicException(
216  "\$pull is only allowed when defining other dependencies"
217  );
218  }
219 
220  if (array_key_exists($name, $this->pulls)) {
221  $d = $this->pulls[$name];
222  } else {
223  $d = new In(InType::PULL, $name);
224  }
225 
226  $this->pulls_temp[0][$name] = $d;
227 
228  return $this->createMock($name);
229  }
230 
231  protected function addInternalOut(string $name, $value)
232  {
233  if (!is_callable($value)) {
234  throw new \LogicException(
235  "\$internal must be set with a callable."
236  );
237  }
238 
239  $this->populateTempArrays();
240  $impl = $value();
241  $dependencies = $this->flushTempArrays();
242 
243  $d = new Out(OutType::INTERNAL, $name, null, $dependencies);
244  $this->internal_out[$name] = [$d, $impl];
245  }
246 
247  protected function cacheInternalOut(string $name, $value)
248  {
249  $this->internal_out[$name] = [$name, $value];
250  }
251 
252  protected function resolveInternalOut(string $name)
253  {
254  if (!array_key_exists($name, $this->internal_out)) {
255  throw new \LogicException(
256  "Cannot resolve dependency \$internal[$name]. It either does not exist or is defined circular."
257  );
258  }
259 
260  if (!$this->internal_out[$name][0] instanceof Out) {
261  $values = $this->internal_out[$name];
262  unset($this->internal_out[$name]);
263  $this->addInternalOut(...$values);
264  }
265  }
266 
267  protected function addInternalIn(string $name)
268  {
269  if (is_null($this->internal_in_temp)) {
270  throw new \LogicException(
271  "getting from \$internal is only allowed when defining other dependencies"
272  );
273  }
274 
275  if (array_key_exists($name, $this->internal_in)) {
276  $d = $this->internal_in[$name];
277  } else {
278  $d = new In(InType::INTERNAL, $name);
279  }
280 
281  $this->internal_in_temp[0][$name] = $d;
282 
283  $this->resolveInternalOut($name);
284 
285  return $this->internal_out[$name][1];
286  }
287 
288  protected function populateTempArrays(): void
289  {
290  array_unshift($this->uses_temp, []);
291  array_unshift($this->seeks_temp, []);
292  array_unshift($this->pulls_temp, []);
293  array_unshift($this->internal_in_temp, []);
294  }
295 
296  protected function flushTempArrays(): array
297  {
298  $uses_temp = array_shift($this->uses_temp);
299  $seeks_temp = array_shift($this->seeks_temp);
300  $pulls_temp = array_shift($this->pulls_temp);
301  $internal_in_temp = array_shift($this->internal_in_temp);
302 
303 
304  $this->uses = array_merge($this->uses, $uses_temp);
305  $this->seeks = array_merge($this->seeks, $seeks_temp);
306  $this->pulls = array_merge($this->pulls, $pulls_temp);
307  $this->internal_in = array_merge($this->internal_in, $internal_in_temp);
308 
309  $dependencies = array_merge(...array_map("array_values", [$uses_temp, $seeks_temp, $pulls_temp, $internal_in_temp]));
310 
311  return $dependencies;
312  }
313 
314  protected function resolveDependencies(): void
315  {
316  foreach ($this->implements as $i => $v) {
317  $this->addImplement($i, ...$v);
318  }
319  foreach ($this->contributes as $i => $v) {
320  $this->addContribute($i, ...$v);
321  }
322  foreach ($this->provides as $i => $v) {
323  $this->addProvide($i, ...$v);
324  }
325  foreach (array_keys($this->internal_out) as $i) {
326  $this->resolveInternalOut($i);
327  }
328  }
329 
330  protected function compileResult(Component $component): OfComponent
331  {
332  return new OfComponent(
333  $component,
334  ...array_merge(
335  ...array_map(
336  "array_values",
337  [
338  $this->defines,
339  $this->implements,
340  $this->uses,
341  $this->contributes,
342  $this->seeks,
343  $this->provides,
344  $this->pulls,
345  array_map(fn($a) => $a[0], $this->internal_out),
346  $this->internal_in
347  ]
348  )
349  )
350  );
351  }
352 
353  protected function createMock(string $class_name): object
354  {
355  $mock_builder = new \PHPUnit\Framework\MockObject\MockBuilder(new class ('dummy') extends \PHPUnit\Framework\TestCase {
356  public function dummy()
357  {
358  }
359  }, $class_name);
360  return $mock_builder
361  ->disableOriginalConstructor()
362  ->disableOriginalClone()
363  ->disableArgumentCloning()
364  ->disallowMockingUnknownTypes()
365  ->getMock();
366  }
367 }
cacheInternalOut(string $name, $value)
Definition: Reader.php:247
init(array|\ArrayAccess &$define, array|\ArrayAccess &$implement, array|\ArrayAccess &$use, array|\ArrayAccess &$contribute, array|\ArrayAccess &$seek, array|\ArrayAccess &$provide, array|\ArrayAccess &$pull, array|\ArrayAccess &$internal,)
Interface Observer Contains several chained tasks and infos about them.
cacheProvide(string $name, $value)
Definition: Reader.php:207
createMock(string $class_name)
Definition: Reader.php:353
addProvide(int $i, string $name, $value)
Definition: Reader.php:185
compileResult(Component $component)
Definition: Reader.php:330
addInternalOut(string $name, $value)
Definition: Reader.php:231
addContribute(int $i, string $name, $value)
Definition: Reader.php:133
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
cacheContribute(string $name, $value)
Definition: Reader.php:161
An entrypoint is where the programm execution starts.
Definition: EntryPoint.php:27
A dependency where the component needs something from the world.
Definition: In.php:26
read(Component $component)
Definition: Reader.php:44
addImplement(int $i, string $name, $value)
Definition: Reader.php:83
cacheImplement(string $name, $value)
Definition: Reader.php:109
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
A dependency where the component gives something to the world.
Definition: Out.php:26