ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
ContentAssembler.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
24use ILIAS\UI\Factory as UIFactory;
27use ILIAS\UI\Component\Modal\Interruptive as InterruptiveModal;
40
42{
51 public const string GENERAL = 'general';
52 public const string KEYWORDS = 'keywords';
53
54 public const string CLASSIFICATION = 'classification';
55 public const string LEARNING_RESOURCE_TYPE = 'learning_resource_type';
56 public const string DISCIPLINE = 'discipline';
57
58 public const string AUTHORS = 'authors';
59 public const string FIRST_AUTHOR = 'first_author';
60 public const string SECOND_AUTHOR = 'second_author';
61 public const string THIRD_AUTHOR = 'third_author';
62 public const string PUBLISHER = 'publisher';
63
64 public const string RIGHTS = 'rights';
65 public const string CUSTOM_CP = 'custom_cp';
66 public const string CUSTOM_CP_DESCRIPTION = 'custom_cp_description';
67 public const string OER_BLOCKED = 'oer_blocked_';
68
69 protected PathFactory $path_factory;
71 protected UIFactory $ui_factory;
78 protected VocabularyAdapter $vocabulary_adapter;
79
80 public function __construct(
81 PathFactory $path_factory,
83 UIFactory $factory,
90 VocabularyAdapter $vocabulary_adapter
91 ) {
92 $this->path_factory = $path_factory;
93 $this->navigator_factory = $navigator_factory;
94 $this->ui_factory = $factory;
95 $this->refinery = $refinery;
96 $this->presenter = $presenter;
97 $this->path_collection = $path_collection;
98 $this->link_factory = $link_factory;
99 $this->copyright_handler = $copyright_handler;
100 $this->data_helper = $data_helper;
101 $this->vocabulary_adapter = $vocabulary_adapter;
102 }
103
107 public function get(
108 SetInterface $set,
109 ?RequestForFormInterface $request = null
110 ): \Generator {
111 $sections = [
112 self::GENERAL => $this->getGeneralSection($set),
113 self::CLASSIFICATION => $this->getClassificationSection($set),
114 self::AUTHORS => $this->getAuthorsSection($set)
115 ];
116 foreach ($this->getCopyrightContent($set) as $type => $entity) {
117 if ($type === ContentType::FORM) {
118 $sections[self::RIGHTS] = $entity;
119 continue;
120 }
121 yield $type => $entity;
122 }
123 $form = $this->ui_factory->input()->container()->form()->standard(
124 (string) $this->link_factory->custom(Command::UPDATE_DIGEST)->get(),
125 $sections
126 );
127
128 if (isset($request)) {
129 $form = $request->applyRequestToForm($form);
130 }
131 yield ContentType::FORM => $form;
132 }
133
134 protected function getGeneralSection(
135 SetInterface $set
136 ): Section {
137 $ff = $this->ui_factory->input()->field();
138 $root = $set->getRoot();
139 $inputs = [];
140
141 $title_el = $this->navigator_factory->navigator(
142 $path = $this->path_collection->title(),
143 $root
144 )->lastElementAtFinalStep();
145 $inputs[$path->toString()] = $ff
146 ->text($this->presenter->utilities()->txt('meta_title'))
147 ->withRequired(true)
148 ->withValue($title_el?->getData()?->value() ?? '');
149
150 $descr_els = $this->navigator_factory->navigator(
151 $descr_path = $this->path_collection->descriptions(),
152 $root
153 )->elementsAtFinalStep();
154 $descr_els = iterator_to_array($descr_els);
155 $label = $this->presenter->utilities()->txt('meta_description');
156 $empty_descr = true;
157 foreach ($descr_els as $el) {
158 $empty_descr = false;
159 $label_with_lang = $label;
160 foreach ($el->getSuperElement()->getSubElements() as $sub) {
161 if (
162 $sub->getDefinition()->name() !== 'language' ||
163 ($value = $sub->getData()->value()) === ''
164 ) {
165 continue;
166 }
167 $label_with_lang .= ' (' . $this->presenter->data()->language($value) . ')';
168 }
169 $inputs[$this->path_factory->toElement($el, true)->toString()] = $ff
170 ->textarea($label_with_lang)
171 ->withValue($el->getData()->value());
172 }
173 if ($empty_descr) {
174 $inputs[$descr_path->toString()] = $ff
175 ->textarea($label);
176 }
177
178 $langs = [];
179 foreach ($this->data_helper->getAllLanguages() as $key) {
180 $langs[$key] = $this->presenter->data()->language($key);
181 }
182 $lang_input = $ff->select(
183 $this->presenter->utilities()->txt('meta_language'),
184 $langs
185 );
186 $lang_els = $this->navigator_factory->navigator(
187 $langs_path = $this->path_collection->languages(),
188 $root
189 )->elementsAtFinalStep();
190 $empty_langs = true;
191 foreach ($lang_els as $el) {
192 $empty_langs = false;
193 $inputs[$this->path_factory->toElement($el, true)->toString()] = (clone $lang_input)
194 ->withValue($el->getData()->value());
195 }
196 if ($empty_langs) {
197 $inputs[$langs_path->toString()] = clone $lang_input;
198 }
199
200 $keywords = [];
201 $keyword_els = $this->navigator_factory->navigator(
202 $keywords_path = $this->path_collection->keywords(),
203 $root
204 )->elementsAtFinalStep();
205 foreach ($keyword_els as $el) {
206 if (!$el->isScaffold()) {
207 $keywords[] = $el->getData()->value();
208 }
209 }
210 $inputs[self::KEYWORDS] = $ff->tag(
211 $this->presenter->utilities()->txt('keywords'),
212 $keywords
213 )->withValue($keywords);
214
215 return $ff->section(
216 $inputs,
217 $this->presenter->utilities()->txt('meta_general')
218 );
219 }
220
221 protected function getClassificationSection(
222 SetInterface $set
223 ): Section {
224 $ff = $this->ui_factory->input()->field();
225 $inputs = [];
226
227 $type_el = $this->navigator_factory->navigator(
228 $this->path_collection->firstLearningResourceType(),
229 $set->getRoot()
230 )->lastElementAtFinalStep();
231 $data = !$type_el?->isScaffold() ? $type_el?->getData()?->value() : null;
232 $values = [];
233 $raw_values = $this->vocabulary_adapter->valuesInVocabulariesForSlot(
234 SlotIdentifier::EDUCATIONAL_LEARNING_RESOURCE_TYPE,
235 $data
236 );
237 foreach ($this->presenter->data()->vocabularyValues(
238 SlotIdentifier::EDUCATIONAL_LEARNING_RESOURCE_TYPE,
239 ...$raw_values
240 ) as $labelled_value) {
241 $values[$labelled_value->value()] = $labelled_value->label();
242 }
243 $input = $this->ui_factory->input()->field()->select(
244 $this->presenter->utilities()->txt('meta_learning_resource_type'),
245 $values
246 );
247 if (isset($data)) {
248 $input = $input->withValue($data);
249 }
250 $inputs[self::LEARNING_RESOURCE_TYPE] = $input;
251
252 $discipline_el = $this->navigator_factory->navigator(
253 $this->path_collection->firstDiscipline(),
254 $set->getRoot()
255 )->lastElementAtFinalStep();
256 $inputs[self::DISCIPLINE] = $this->buildStringFromControlledVocabInput(
257 $this->presenter->utilities()->txt('meta_discipline'),
259 !$discipline_el?->isScaffold() ? $discipline_el?->getData()?->value() : null
260 );
261
262 return $ff->section(
263 $inputs,
264 $this->presenter->utilities()->txt('meta_classification')
265 );
266 }
267
268 protected function getAuthorsSection(
269 SetInterface $set
270 ): Section {
271 $ff = $this->ui_factory->input()->field();
272 $inputs = [];
273
274 $paths = [
275 $this->path_collection->firstAuthor(),
276 $this->path_collection->secondAuthor(),
277 $this->path_collection->thirdAuthor()
278 ];
279 $labels = [
280 $this->presenter->utilities()->txt('meta_first_author'),
281 $this->presenter->utilities()->txt('meta_second_author'),
282 $this->presenter->utilities()->txt('meta_third_author')
283 ];
284 $post_keys = [
285 self::FIRST_AUTHOR,
286 self::SECOND_AUTHOR,
287 self::THIRD_AUTHOR,
288 self::PUBLISHER
289 ];
290 foreach ($paths as $path) {
291 $el = $this->navigator_factory->navigator(
292 $path,
293 $set->getRoot()
294 )->lastElementAtFinalStep();
295 $inputs[array_shift($post_keys)] = $ff
296 ->text(array_shift($labels))
297 ->withValue($el?->getData()?->value() ?? '');
298 }
299
300 $publisher_el = $this->navigator_factory->navigator(
301 $this->path_collection->firstPublisher(),
302 $set->getRoot()
303 )->lastElementAtFinalStep();
304 $inputs[self::PUBLISHER] = $this->buildStringFromControlledVocabInput(
305 $this->presenter->utilities()->txt('meta_publisher'),
306 SlotIdentifier::LIFECYCLE_CONTRIBUTE_PUBLISHER,
307 $publisher_el?->getData()?->value()
308 );
309
310 return $ff->section(
311 $inputs,
312 $this->presenter->utilities()->txt('meta_authors')
313 );
314 }
315
319 protected function getCopyrightContent(
320 SetInterface $set
321 ): \Generator {
322 if (!$this->copyright_handler->isCPSelectionActive()) {
323 return;
324 }
325 $modal = $this->getChangeCopyrightModal(false);
326 $modal_with_oer_warning = $this->getChangeCopyrightModal(true);
327 $signal = $modal->getShowSignal();
328 $signal_with_oer_warning = $modal_with_oer_warning->getShowSignal();
329
330 yield ContentType::MODAL => $modal;
331 yield ContentType::MODAL => $modal_with_oer_warning;
332 yield ContentType::JS_SOURCE => 'assets/js/ilMetaCopyrightListener.js';
333 yield ContentType::FORM => $this->getCopyrightSection(
334 $set,
335 $signal,
336 $signal_with_oer_warning
337 );
338 }
339
340 protected function getChangeCopyrightModal(bool $with_oer_warning): InterruptiveModal
341 {
342 $message = $this->presenter->utilities()->txt("meta_copyright_change_info");
343 if ($with_oer_warning) {
344 $message .= "<br/><br/>" . $this->presenter->utilities()->txt("meta_copyright_change_oer_info");
345 }
346 $modal = $this->ui_factory->modal()->interruptive(
347 $this->presenter->utilities()->txt("meta_copyright_change_warning_title"),
348 $message,
349 (string) $this->link_factory->custom(Command::UPDATE_DIGEST)->get()
350 );
351
352 return $modal;
353 }
354
355 protected function getCopyrightSection(
356 SetInterface $set,
357 Signal $signal,
358 Signal $signal_with_oer_warning
359 ): Section {
360 $ff = $this->ui_factory->input()->field();
361
362 $cp_description_el = $this->navigator_factory->navigator(
363 $this->path_collection->copyright(),
364 $set->getRoot()
365 )->lastElementAtFinalStep();
366 $cp_description = $cp_description_el?->getData()->value();
367
368 $current_id = $this->copyright_handler->extractCPEntryID((string) $cp_description);
369 $default_id = 0;
370 $options = [];
371 $outdated = [];
372 $potential_oer_values = [];
373 $current_id_exists = false;
374 $is_custom = !is_null($cp_description) && !$current_id;
375
376 foreach ($this->copyright_handler->getCPEntries() as $entry) {
377 if ($entry->isDefault()) {
378 $default_id = $entry->id();
379 }
380 if ($current_id === $entry->id()) {
381 $current_id_exists = true;
382 }
383
384 $identifier = $this->copyright_handler->createIdentifierForID($entry->id());
385
386 //give the option to block harvesting
387 $sub_inputs = [];
388 if (
389 $this->copyright_handler->isObjectTypeHarvested($set->getRessourceID()->type()) &&
390 $this->copyright_handler->isCopyrightTemplateActive($entry)
391 ) {
392 $sub_inputs[self::OER_BLOCKED] = $ff
393 ->checkbox(
394 $this->presenter->utilities()->txt('meta_oer_blocked'),
395 $this->presenter->utilities()->txt('meta_oer_blocked_info')
396 )
397 ->withValue(
398 $this->copyright_handler->isOerHarvesterBlocked($set->getRessourceID()->objID())
399 );
400 $potential_oer_values[] = $identifier;
401 }
402
403 $option = $ff->group($sub_inputs, $entry->title(), $entry->description());
404
405 // outdated entries throw an error when selected
406 if ($entry->isOutdated()) {
407 $option = $option->withLabel(
408 '(' . $this->presenter->utilities()->txt('meta_copyright_outdated') .
409 ') ' . $entry->title()
410 )->withDisabled(true);
411 $outdated[] = $identifier;
412 }
413 $options[$identifier] = $option;
414 }
415
416 //custom input as the last option
417 $custom_text = $ff
418 ->textarea($this->presenter->utilities()->txt('meta_description'))
419 ->withValue($is_custom ? (string) $cp_description : '');
420 $custom = $ff->group(
421 [self::CUSTOM_CP_DESCRIPTION => $custom_text],
422 $this->presenter->utilities()->txt('meta_cp_own')
423 );
424 $options[self::CUSTOM_CP] = $custom;
425
426 $value = self::CUSTOM_CP;
427 if (!$is_custom) {
428 $id = ($current_id && $current_id_exists) ? $current_id : $default_id;
429 $value = $this->copyright_handler->createIdentifierForID($id);
430 }
431
432 $copyright = $ff
433 ->switchableGroup(
434 $options,
435 $this->presenter->utilities()->txt('meta_copyright')
436 )
437 ->withValue($value)
438 ->withAdditionalOnLoadCode(
439 function ($id) use ($signal, $signal_with_oer_warning, $potential_oer_values) {
440 return 'il.MetaDataCopyrightListener.init(\'' .
441 $signal . '\',\'' .
442 $signal_with_oer_warning . '\',\'' .
443 json_encode($potential_oer_values) . '\',\'' .
444 $id . '\');';
445 }
446 )->withAdditionalTransformation(
447 $this->refinery->custom()->constraint(
448 function ($v) use ($outdated) {
449 if (in_array($v[0], $outdated, true)) {
450 return false;
451 }
452 return true;
453 },
454 $this->presenter->utilities()->txt('meta_copyright_outdated_error')
455 )
456 );
457
458 return $ff->section(
459 [$copyright],
460 $this->presenter->utilities()->txt('meta_rights')
461 );
462 }
463
464 protected function buildStringFromControlledVocabInput(
465 string $label,
466 SlotIdentifier $slot,
467 ?string $data = null
468 ): Input {
469 if (!$this->vocabulary_adapter->doesSlotHaveVocabularies($slot)) {
470 $input = $this->ui_factory->input()->field()->text($label);
471 if (isset($data)) {
472 $input = $input->withValue($data);
473 }
474 return $input;
475 }
476
477 $values = [];
478 $raw_values = iterator_to_array($this->vocabulary_adapter->valuesInVocabulariesForSlot(
479 $slot,
480 !$this->vocabulary_adapter->doesSlotAllowCustomInput($slot) ? $data : null
481 ));
482 foreach ($this->presenter->data()->vocabularyValues($slot, ...$raw_values) as $labelled_value) {
483 $values[$labelled_value->value()] = $labelled_value->label();
484 }
485
486 if (!$this->vocabulary_adapter->doesSlotAllowCustomInput($slot)) {
487 $input = $this->ui_factory->input()->field()->select($label, $values);
488 if (isset($data)) {
489 $input = $input->withValue($data);
490 }
491 return $input;
492 }
493
494 $value_label = $this->presenter->utilities()->txt('md_editor_value');
495 $text_input = $this->ui_factory->input()->field()->text($value_label);
496 $select_input = $this->ui_factory->input()->field()->select($value_label, $values);
497
498 $radio_value = 'from_vocab';
499 if (isset($data)) {
500 if (in_array($data, $raw_values)) {
501 $select_input = $select_input->withValue($data);
502 $radio_value = 'from_vocab';
503 } else {
504 $text_input = $text_input->withValue($data);
505 $radio_value = 'custom';
506 }
507 }
508
509 $input = $this->ui_factory->input()->field()->switchableGroup(
510 [
511 'from_vocab' => $this->ui_factory->input()->field()->group(
512 ['value' => $select_input],
513 $this->presenter->utilities()->txt('md_editor_from_vocab_input')
514 ),
515 'custom' => $this->ui_factory->input()->field()->group(
516 ['value' => $text_input],
517 $this->presenter->utilities()->txt('md_editor_custom_input')
518 )
519 ],
520 $label
521 );
522 if (isset($radio_value)) {
523 $input = $input->withValue($radio_value);
524 }
525 return $input->withAdditionalTransformation(
526 $this->refinery->custom()->transformation(function ($vs) {
527 return $vs[1]['value'] ?? null;
528 })
529 );
530 }
531}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Builds data types.
Definition: Factory.php:36
getCopyrightSection(SetInterface $set, Signal $signal, Signal $signal_with_oer_warning)
__construct(PathFactory $path_factory, NavigatorFactoryInterface $navigator_factory, UIFactory $factory, Refinery $refinery, PresenterInterface $presenter, PathCollection $path_collection, LinkFactory $link_factory, CopyrightHandler $copyright_handler, DataHelperInterface $data_helper, VocabularyAdapter $vocabulary_adapter)
getRoot()
Returns the root element of the metadata set.
getRessourceID()
Contains the information needed to identify the ILIAS object this metadata set belongs to.
This describes a standard form.
Definition: Standard.php:29
This describes section inputs.
Definition: Section.php:29
This describes commonalities between all inputs.
Definition: Input.php:47
withValue($value)
Get an input like this with another value displayed on the client side.
$path
Definition: ltiservices.php:30
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:61
if(!file_exists('../ilias.ini.php'))
$message
Definition: xapiexit.php:31