ILIAS  release_8 Revision v8.24
ObjectiveIterator.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
21namespace ILIAS\Setup;
22
29class ObjectiveIterator implements \Iterator
30{
33
37 protected array $stack;
38
39 protected ?Objective $current = null;
40
44 protected array $returned;
45
49 protected array $failed;
50
54 protected array $reverse_dependencies;
55
56
58 {
60 $this->objective = $objective;
61 $this->rewind();
62 }
63
65 {
67 }
68
69 public function markAsFailed(Objective $objective): void
70 {
71 if (!isset($this->returned[$objective->getHash()])) {
72 throw new \LogicException(
73 "You may only mark objectives as failed that have been returned by this iterator."
74 );
75 }
76
77 $this->failed[$objective->getHash()] = true;
78 }
79
80 public function rewind(): void
81 {
82 $this->stack = [$this->objective];
83 $this->current = null;
84 $this->returned = [];
85 $this->failed = [];
86 $this->reverse_dependencies = [];
87 $this->next();
88 }
89
90 public function current(): \ILIAS\Setup\Objective
91 {
92 if ($this->current === null) {
93 throw new \LogicException(
94 "Iterator is finished or wasn't initialized correctly internally."
95 );
96 }
97 return $this->current;
98 }
99
100 public function key()
101 {
102 return $this->current()->getHash();
103 }
104
105 public function next(): void
106 {
107 if ($this->stack === []) {
108 $this->current = null;
109 return;
110 }
111
112 $cur = array_pop($this->stack);
113 $hash = $cur->getHash();
114
115 if (isset($this->returned[$hash]) || isset($this->failed[$hash])) {
116 $this->next();
117 return;
118 }
119
120 $preconditions = [];
121 $failed_preconditions = [];
122 foreach ($cur->getPreconditions($this->environment) as $p) {
123 $h = $p->getHash();
124 if (!isset($this->returned[$h]) || isset($this->failed[$h])) {
125 $preconditions[] = $p;
126 }
127
128 if (isset($this->failed[$h])) {
129 $failed_preconditions[] = $p;
130 }
131 }
132
133 // We only have preconditions left that we know to have failed.
134 if (
135 $preconditions !== [] &&
136 count($preconditions) === count($failed_preconditions)
137 ) {
138 $this->returned[$hash] = true;
139 $this->markAsFailed($cur);
140 if ($this->stack === []) {
141 // Since the current objective doesn't need to be achieved,
142 // we are fine and can simply stop here.
143 if ($cur instanceof Objective\Tentatively) {
144 return;
145 }
146 throw new UnachievableException(
147 "Objective '" . $cur->getLabel() . "' had failed preconditions:\n - " .
148 implode("\n - ", array_map(fn ($o) => $o->getLabel(), $failed_preconditions))
149 );
150 }
151 $this->next();
152 return;
153 }
154
155 // No preconditions open, we can proceed with the objective.
156 if ($preconditions === []) {
157 $this->returned[$hash] = true;
158 $this->current = $cur;
159 return;
160 }
161
162 $this->stack[] = $cur;
163 $this->detectDependencyCycles($hash, $hash);
164 foreach (array_reverse($preconditions) as $p) {
165 $this->stack[] = $p;
166 $this->setReverseDependency($p->getHash(), $hash);
167 }
168 $this->next();
169 }
170
171 public function valid(): bool
172 {
173 return $this->current !== null;
174 }
175
176 protected function detectDependencyCycles(string $cur, string $next): void
177 {
178 if (!isset($this->reverse_dependencies[$next])) {
179 return;
180 }
181 if (in_array($cur, $this->reverse_dependencies[$next])) {
182 throw new UnachievableException(
183 "The objectives contain a dependency cycle and won't all be achievable."
184 );
185 }
186 foreach ($this->reverse_dependencies[$next] as $d) {
187 $this->detectDependencyCycles($cur, $d);
188 }
189 }
190
191 protected function setReverseDependency(string $other, string $cur): void
192 {
193 if (!isset($this->reverse_dependencies[$other])) {
194 $this->reverse_dependencies[$other] = [];
195 }
196 $this->reverse_dependencies[$other][] = $cur;
197 }
198}
Tries to enumerate all preconditions for the given objective, where the ones that can be achieved (i....
setEnvironment(Environment $environment)
markAsFailed(Objective $objective)
setReverseDependency(string $other, string $cur)
detectDependencyCycles(string $cur, string $next)
__construct(Environment $environment, Objective $objective)
Signals that some goal won't be achievable by actions of the system ever.
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
An environment holds resources to be used in the setup process.
Definition: Environment.php:28
An objective is a desired state of the system that is supposed to be created by the setup.
Definition: Objective.php:31
getHash()
Get a hash for this objective.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ChatMainBarProvider \MainMenu\Provider.