ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
ObjectiveIterator.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 2019 Richard Klees <richard.klees@concepts-and-training.de> Extended GPL, see docs/LICENSE */
4 
5 namespace ILIAS\Setup;
6 
13 class ObjectiveIterator implements \Iterator
14 {
18  protected $environment;
19 
23  protected $objective;
24 
28  protected $stack;
29 
33  protected $current;
34 
38  protected $returned;
39 
43  protected $failed;
44 
49 
50 
52  {
53  $this->environment = $environment;
54  $this->objective = $objective;
55  $this->rewind();
56  }
57 
58  public function setEnvironment(Environment $environment) : void
59  {
60  $this->environment = $environment;
61  }
62 
64  {
65  if (!isset($this->returned[$objective->getHash()])) {
66  throw new \LogicException(
67  "You may only mark objectives as failed that have been returned by this iterator."
68  );
69  }
70 
71  $this->failed[$objective->getHash()] = true;
72  }
73 
74  public function rewind()
75  {
76  $this->stack = [$this->objective];
77  $this->current = null;
78  $this->returned = [];
79  $this->failed = [];
80  $this->reverse_dependencies = [];
81  $this->next();
82  }
83 
84  public function current()
85  {
86  if ($this->current === null) {
87  throw new \LogicException(
88  "Iterator is finished or wasn't initialized correctly internally."
89  );
90  }
91  return $this->current;
92  }
93 
94  public function key()
95  {
96  return $this->current()->getHash();
97  }
98 
99  public function next()
100  {
101  if (count($this->stack) === 0) {
102  $this->current = null;
103  return;
104  }
105 
106  $cur = array_pop($this->stack);
107  $hash = $cur->getHash();
108 
109  if (isset($this->returned[$hash]) || isset($this->failed[$hash])) {
110  $this->next();
111  return;
112  }
113 
114  $preconditions = [];
115  $failed_preconditions = [];
116  foreach ($cur->getPreconditions($this->environment) as $p) {
117  $h = $p->getHash();
118  if (!isset($this->returned[$h]) || isset($this->failed[$h])) {
119  $preconditions[] = $p;
120  }
121 
122  if (isset($this->failed[$h])) {
123  $failed_preconditions[] = $p;
124  }
125  }
126 
127  // We only have preconditions left that we know to have failed.
128  if (
129  count($preconditions) !== 0 &&
130  count($preconditions) === count($failed_preconditions)
131  ) {
132  $this->returned[$hash] = true;
133  $this->markAsFailed($cur);
134  if (count($this->stack) === 0) {
135  throw new UnachievableException(
136  "Objective '" . $cur->getLabel() . "' had failed preconditions:\n - " .
137  implode("\n - ", array_map(function ($o) {
138  return $o->getLabel();
139  }, $failed_preconditions))
140  );
141  }
142  $this->next();
143  return;
144  }
145 
146  // No preconditions open, we can proceed with the objective.
147  if (count($preconditions) === 0) {
148  $this->returned[$hash] = true;
149  $this->current = $cur;
150  return;
151  }
152 
153  $this->stack[] = $cur;
154  $this->detectDependencyCycles($hash, $hash);
155  foreach (array_reverse($preconditions) as $p) {
156  $this->stack[] = $p;
157  $this->setReverseDependency($p->getHash(), $hash);
158  }
159  $this->next();
160  }
161 
162  public function valid()
163  {
164  return $this->current !== null;
165  }
166 
167  protected function detectDependencyCycles(string $cur, string $next)
168  {
169  if (!isset($this->reverse_dependencies[$next])) {
170  return;
171  }
172  if (in_array($cur, $this->reverse_dependencies[$next])) {
173  throw new UnachievableException(
174  "The objectives contain a dependency cycle and won't all be achievable."
175  );
176  }
177  foreach ($this->reverse_dependencies[$next] as $d) {
178  $this->detectDependencyCycles($cur, $d);
179  }
180  }
181 
182  protected function setReverseDependency(string $other, string $cur)
183  {
184  if (!isset($this->reverse_dependencies[$other])) {
185  $this->reverse_dependencies[$other] = [];
186  }
187  $this->reverse_dependencies[$other][] = $cur;
188  }
189 }
An objective is a desired state of the system that is supposed to be created by the setup...
Definition: Objective.php:14
setReverseDependency(string $other, string $cur)
getHash()
Get a hash for this objective.
__construct(Environment $environment, Objective $objective)
Signals that some goal won&#39;t be achievable by actions of the system ever.
markAsFailed(Objective $objective)
detectDependencyCycles(string $cur, string $next)
setEnvironment(Environment $environment)
environment()
Definition: environment.php:3
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
An environment holds resources to be used in the setup process.
Definition: Environment.php:11
Tries to enumerate all preconditions for the given objective, where the ones that can be achieved (i...
for($i=6; $i< 13; $i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296