ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
Cleaner.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
36 
37 class Cleaner implements CleanerInterface
38 {
43  protected \ilLogger $logger;
44 
45  public function __construct(
46  Factory $element_factory,
47  StructureSetInterface $structure_set,
48  DataValidatorInterface $data_validator,
49  DictionaryInterface $dictionary,
50  \ilLogger $logger
51  ) {
52  $this->element_factory = $element_factory;
53  $this->structure_set = $structure_set;
54  $this->data_validator = $data_validator;
55  $this->dictionary = $dictionary;
56  $this->logger = $logger;
57  }
58 
59  public function clean(SetInterface $set): SetInterface
60  {
61  return $this->element_factory->set(
62  $set->getRessourceID(),
63  $this->getCleanRoot($set)
64  );
65  }
66 
67  protected function getCleanRoot(
68  SetInterface $set
69  ): ElementInterface {
70  $root = $set->getRoot();
71  if (!$this->data_validator->isValid($root, true)) {
72  throw new \ilMDRepositoryException('Invalid data on root');
73  }
74  return $this->element_factory->root(
75  $root->getDefinition(),
76  ...$this->getCleanSubElements($root, 0)
77  );
78  }
79 
83  protected function getCleanSubElements(
84  ElementInterface $element,
85  int $depth
86  ): \Generator {
87  if ($depth > 20) {
88  throw new \ilMDStructureException('LOM Structure is nested to deep.');
89  }
90  $sub_names = [];
91  foreach ($element->getSubElements() as $sub) {
92  $name = $sub->getDefinition()->name();
93  if ($sub->isScaffold()) {
94  continue;
95  }
96  if ($sub->getDefinition()->unique() && in_array($name, $sub_names)) {
97  $this->throwErrorOrLog($sub, 'duplicate of unique element.');
98  continue;
99  }
100  if ($this->data_validator->isValid($sub, true)) {
101  $sub_names[] = $name;
102  yield $this->element_factory->element(
103  $sub->getMDID(),
104  $sub->getDefinition(),
105  $sub->getData()->value(),
106  ...$this->getCleanSubElements($sub, $depth + 1)
107  );
108  continue;
109  }
110  $message = $sub->getData()->value() . ' is not valid as ' .
111  $sub->getData()->type()->value . ' data.';
112  $this->throwErrorOrLog($sub, $message);
113  }
114  }
115 
116  public function checkMarkers(SetInterface $set): void
117  {
118  $this->checkMarkerOnElement($set->getRoot(), 0);
119  }
120 
121  protected function checkMarkerOnElement(
122  ElementInterface $element,
123  int $depth
124  ): void {
125  if ($depth > 20) {
126  throw new \ilMDStructureException('LOM Structure is nested to deep.');
127  }
128  if (!($element instanceof MarkableInterface) || !$element->isMarked()) {
129  return;
130  }
131  $marker = $element->getMarker();
132  if (
133  $marker->action() === Action::CREATE_OR_UPDATE &&
134  !$this->data_validator->isValid($element, false)
135  ) {
136  $message = $marker->dataValue() . ' is not valid as ' .
137  $element->getDefinition()->dataType()->value . ' data.';
138  $this->throwErrorOrLog($element, $message, true);
139  }
140  foreach ($this->dictionary->tagsForElement($element) as $tag) {
141  $this->checkMarkerAgainstTag($tag, $element, $marker);
142  }
143  foreach ($element->getSubElements() as $sub) {
144  $this->checkMarkerOnElement($sub, $depth + 1);
145  }
146  }
147 
148  protected function checkMarkerAgainstTag(
149  TagInterface $tag,
150  ElementInterface $element,
151  MarkerInterface $marker
152  ): void {
153  switch ($tag->restriction()) {
154  case Restriction::PRESET_VALUE:
155  if (
156  $this->willBeCreated($element, $marker) &&
157  $marker->dataValue() !== $tag->value()
158  ) {
159  $this->throwErrorOrLog(
160  $element,
161  'can only be created with preset value ' . $tag->value(),
162  true
163  );
164  }
165  break;
166 
167  case Restriction::NOT_DELETABLE:
168  if ($marker->action() === Action::DELETE) {
169  $this->throwErrorOrLog($element, 'cannot be deleted.', true);
170  }
171  break;
172 
174  if (
175  $marker->action() === Action::CREATE_OR_UPDATE &&
176  $element->getMDID() !== NoID::SCAFFOLD
177  ) {
178  $this->throwErrorOrLog($element, 'cannot be edited.', true);
179  }
180  break;
181  }
182  }
183 
184  protected function willBeCreated(
185  ElementInterface $element,
186  MarkerInterface $marker
187  ): bool {
188  return $element->getMDID() === NoID::SCAFFOLD && (
189  $marker->action() === Action::CREATE_OR_UPDATE ||
190  $marker->action() === Action::NEUTRAL
191  );
192  }
193 
194  protected function throwErrorOrLog(
195  ElementInterface $element,
196  string $message,
197  bool $throw_error = false
198  ): void {
199  $id = $element->getMDID();
200  $id = is_int($id) ? (string) $id : $id->value;
201  $message = $element->getDefinition()->name() . ' (ID ' . $id . '): ' . $message;
202  if ($super = $element->getSuperElement()) {
203  $message = $super->getDefinition()->name() . ': ' . $message;
204  }
205  if ($throw_error) {
206  throw new \ilMDRepositoryException('Invalid marker on element ' . $message);
207  }
208  $this->logger->info('Skipping element ' . $message);
209  }
210 }
throwErrorOrLog(ElementInterface $element, string $message, bool $throw_error=false)
Definition: Cleaner.php:194
checkMarkerAgainstTag(TagInterface $tag, ElementInterface $element, MarkerInterface $marker)
Definition: Cleaner.php:148
checkMarkerOnElement(ElementInterface $element, int $depth)
Definition: Cleaner.php:121
getRoot()
Returns the root element of the metadata set.
__construct(Factory $element_factory, StructureSetInterface $structure_set, DataValidatorInterface $data_validator, DictionaryInterface $dictionary, \ilLogger $logger)
Definition: Cleaner.php:45
getRessourceID()
Contains the information needed to identify the ILIAS object this metadata set belongs to...
clean(SetInterface $set)
Returns a new metadata set, identical to the one given but with all invalid elements (invalid data...
Definition: Cleaner.php:59
checkMarkers(SetInterface $set)
Checks whether the proposed manipulations on the set via markers are valid.
Definition: Cleaner.php:116
getCleanSubElements(ElementInterface $element, int $depth)
Definition: Cleaner.php:83
getDefinition()
Defining properties of the metadata element.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
DataValidatorInterface $data_validator
Definition: Cleaner.php:41
isMarked()
Elements can be marked to be created, updated or deleted.
$message
Definition: xapiexit.php:32
willBeCreated(ElementInterface $element, MarkerInterface $marker)
Definition: Cleaner.php:184