ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
MainMenuMainCollector.php
Go to the documentation of this file.
2 
18 
29 {
30 
34  private static $constructed = false;
38  private static $items = [];
42  private static $topitems = [];
50  private $information;
54  protected $providers;
58  private $loaded = false;
59 
60 
69  public function __construct(array $providers, ItemInformation $information = null)
70  {
71  if (self::$constructed === true) {
72  throw new \LogicException("only one Instance of MainMenuMainCollector Collector is possible");
73  }
74  self::$constructed = true;
75  $this->information = $information;
76  $this->providers = $providers;
77  $this->type_information_collection = new TypeInformationCollection();
78  $this->load();
79  }
80 
81 
91  public function getStackedTopItemsForPresentation() : array
92  {
93  return $this->getStackedTopItems();
94  }
95 
96 
101  private function getStackedTopItems() : array
102  {
103  $this->load();
104  $top_items = [];
105  foreach (self::$topitems as $top_item) {
106  if (!$this->checkAvailability($top_item)) {
107  continue;
108  }
109  if ($top_item instanceof isTopItem && $this->information) {
110  if ($top_item instanceof isParent) {
111  $has_always_available_item = false;
112  $children = [];
117  foreach ($top_item->getChildren() as $child) {
118  $child = $this->applyTypeHandler($child);
119  if (!$this->checkAvailability($child)) {
120  continue;
121  }
122  $position_of_sub_item = $this->information->getPositionOfSubItem($child);
123  if (isset($children[$position_of_sub_item])) {
124  $position_of_sub_item = max(array_keys($children)) + 1;
125  }
126  $children[$position_of_sub_item] = $child;
127  if ($child->isAlwaysAvailable() === true) {
128  $has_always_available_item = true;
129  }
130  }
131  ksort($children);
132  $children = $this->handleDoubleDividers($children);
133  // bugfix mantis 25577
134  $children = $this->handleSolitaryDividers($children, $top_item);
135 
136  // https://mantis.ilias.de/view.php?id=24061
137  if (count($children) === 0) {
138  unset($top_item);
139  continue;
140  }
141 
142  $top_item = $top_item->withChildren($children);
143  if ($has_always_available_item === true) {
144  $top_item = $top_item->withAlwaysAvailable(true);
145  }
146  }
147  $top_item = $this->applyTypeHandler($top_item);
148  $position_of_top_item = $this->information->getPositionOfTopItem($top_item);
149  if (isset($top_items[$position_of_top_item])) {
150  $position_of_top_item = max(array_keys($top_items)) + 1;
151  }
152  $top_items[$position_of_top_item] = $top_item;
153  }
154  }
155  ksort($top_items);
156 
157  return $top_items;
158  }
159 
160 
167  private function checkAvailability(isItem $item) : bool
168  {
169  $is_visible = $item->isVisible();
170  $is_item_active = $this->information->isItemActive($item);
171  $is_always_available = $item->isAlwaysAvailable();
172 
173  return !(!$is_visible || !$is_item_active && !$is_always_available);
174  }
175 
176 
183  public function getSingleItem(IdentificationInterface $identification) : isItem
184  {
185  $this->load();
186  try {
187  return self::$items[$identification->serialize()];
188  } catch (\Throwable $e) {
189  return $this->getLostItem($identification);
190  }
191  }
192 
193 
199  private function getLostItem(IdentificationInterface $identification) : Lost
200  {
201  global $DIC;
202 
203  return $DIC->globalScreen()->mainmenu()->custom(Lost::class, new NullIdentification($identification))
204  ->withAlwaysAvailable(true)
205  ->setTypeInformation($this->type_information_collection->get(Lost::class))
206  ->withNonAvailableReason($DIC->ui()->factory()->legacy("{$DIC->language()->txt('mme_lost_item_reason')}"))
207  ->withVisibilityCallable(
208  function () use ($DIC) {
209  return (bool) ($DIC->rbac()->system()->checkAccess("visible", SYSTEM_FOLDER_ID));
210  }
211  )->withTitle($DIC->language()->txt("mme_lost_item_title"));
212  }
213 
214 
219  private function load() : bool
220  {
221  if ($this->loaded === false || $this->loaded === null) {
227  try {
228  $this->loaded = true;
229  $this->loadTypeInformation();
230  $this->loadTopItems();
231  $this->loadSubItems();
232  } catch (\Throwable $e) {
233  throw $e;
234  }
235  }
236 
237  return $this->loaded;
238  }
239 
240 
241  private function loadTopItems()
242  {
243  foreach ($this->providers as $provider) {
244  foreach ($provider->getStaticTopItems() as $top_item) {
245  if ($top_item instanceof hasTitle && $this->information) {
246  $top_item = $this->information->translateItemForUser($top_item);
247  }
248  $this->addItemToMap($top_item);
249  }
250  }
251  }
252 
253 
254  private function loadSubItems()
255  {
256  foreach ($this->providers as $provider) {
257  foreach ($provider->getStaticSubItems() as $sub_item) {
258  if ($sub_item instanceof hasTitle && $this->information) {
259  $sub_item = $this->information->translateItemForUser($sub_item);
260  }
261  if ($sub_item instanceof isChild && $sub_item->hasParent()) {
262  $new_parent_identification = $this->information->getParent($sub_item);
263  $parent_item = $this->getSingleItem($new_parent_identification);
264  if ($parent_item->getProviderIdentification() instanceof NullIdentification) {
265  $this->addItemToMap($parent_item);
266  // self::$items[$parent_item->getProviderIdentification()->serialize()] = $parent_item;
267  // self::$topitems[$parent_item->getProviderIdentification()->serialize()] = $parent_item;
268  $sub_item->overrideParent($parent_item->getProviderIdentification());
269  } else {
270  $sub_item->overrideParent($new_parent_identification);
271  }
272  if ($this->itemExistsInMap($sub_item->getParent()) && $this->getItemFromMap($sub_item->getParent()) instanceof isParent) {
273  $this->getItemFromMap($sub_item->getParent())->appendChild($sub_item);
274  // self::$topitems[$sub_item->getParent()->serialize()]->appendChild($sub_item);
275  if ($sub_item->isAlwaysAvailable()) {
276  $parent = $this->getItemFromMap($sub_item->getParent())->withAlwaysAvailable(true);
277  $this->addItemToMap($parent);
278  // self::$topitems[$sub_item->getParent()->serialize()] = self::$topitems[$sub_item->getParent()->serialize()]->withAlwaysAvailable(true);
279  }
280  }
281  }
282  $this->addItemToMap($sub_item);
283  // self::$items[$sub_item->getProviderIdentification()->serialize()] = $sub_item; // register them always since they could be lost
284  }
285  }
286  }
287 
288 
294  private function applyTypeHandler(isItem $item) : isItem
295  {
296  $item = $this->getHandlerForItem($item)->enrichItem($item);
297 
298  return $item;
299  }
300 
301 
307  public function getHandlerForItem(isItem $item) : TypeHandler
308  {
312  $type = get_class($item);
313  $type_information = $this->type_information_collection->get($type);
314  if (is_null($type_information)) {
315  return new BaseTypeHandler();
316  }
317  $handler = $type_information->getTypeHandler();
318 
319  return $handler;
320  }
321 
322 
328  private function handleDoubleDividers($children) : array
329  {
330  $separators = 0;
331  foreach ($children as $position => $child) {
332  if ($child instanceof Separator) {
333  $separators++;
334  } else {
335  $separators = 0;
336  }
337  if ($separators > 1) {
338  unset($children[$position]);
339  }
340  }
341 
342  return $children;
343  }
344 
345 
354  private function handleSolitaryDividers($children, $top_item) : array
355  {
356  foreach ($children as $position => $child) {
357  if ($child instanceof Separator) {
358  // remove dividers that are the only item of the item-list and remove their top-item as well
359  if (count($children) === 1) {
360  unset($children[$position]);
361  unset($top_item);
362  continue;
363  }
364  // remove dividers that stand alone at the beginning of the item-list
365  if ($position == min(array_keys($children))) {
366  unset($children[$position]);
367  continue;
368  }
369  // remove dividers that stand alone at the end of the item-list
370  if ($position == max(array_keys($children))) {
371  unset($children[$position]);
372  continue;
373  }
374  }
375  }
376 
377  return $children;
378  }
379 
380 
385  {
387  }
388 
389 
390  private function loadTypeInformation()
391  {
392  foreach ($this->providers as $provider) {
393  if ($provider instanceof StaticMainMenuProvider) {
394  $this->type_information_collection->append($provider->provideTypeInformation());
395  }
396  }
397  }
398 
399 
403  private function addItemToMap(isItem $item)
404  {
405  if ($item instanceof isItem) {
406  $item->setTypeInformation($this->type_information_collection->get(get_class($item)));
407  }
408 
409  if ($item instanceof isTopItem) {
410  self::$topitems[$item->getProviderIdentification()->serialize()] = $item;
411  }
412  self::$items[$item->getProviderIdentification()->serialize()] = $item;
413  }
414 
415 
421  private function itemExistsInMap(IdentificationInterface $identification) : bool
422  {
423  return isset(self::$items[$identification->serialize()]);
424  }
425 
426 
432  private function getItemFromMap(IdentificationInterface $identification)
433  {
434  if (!$this->itemExistsInMap($identification)) {
435  // Exception?
436  }
437 
438  return self::$items[$identification->serialize()];
439  }
440 }
$type
global $DIC
Definition: saml.php:7
handleSolitaryDividers($children, $top_item)
bugfix mantis 25577: prevent solitary dividers from being shown
setTypeInformation(TypeInformation $information)
getStackedTopItemsForPresentation()
This will return all available topitems, stacked based on the configuration in "Administration" and f...
__construct(array $providers, ItemInformation $information=null)
MainMenuMainCollector constructor.
$handler