ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilAdvancedMDRecordParser.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
28 {
29  public const MODE_UNDEFINED = 0;
30  public const MODE_UPDATE = 1;
31  public const MODE_INSERT = 2;
32  // update is not supported anymore
33  public const MODE_UPDATE_VALIDATION = 3;
34  public const MODE_INSERT_VALIDATION = 4;
35 
36  private int $mode = self::MODE_UNDEFINED;
37 
38  private array $fields = [];
39 
40  private bool $is_error = false;
41  private array $error_msg = [];
42  private string $field_value_id = '';
43 
44  protected array $context;
45  protected array $scopes = [];
46 
47  protected array $translations = [];
48  protected string $translation_language = '';
49 
50  protected array $field_translations = [];
51  protected string $field_translation_language = '';
52 
53  private array $rec_map;
56  protected string $cdata = '';
57 
58  protected ilLogger $log;
59 
60  public function __construct(string $a_file)
61  {
62  parent::__construct($a_file, true);
63  $this->log = ilLoggerFactory::getLogger('amet');
64  }
65 
66  public function setMode(int $a_mode): void
67  {
68  $this->mode = $a_mode;
69  }
70 
71  public function getMode(): int
72  {
73  return $this->mode;
74  }
75 
76  public function startParsing(): void
77  {
78  parent::startParsing();
79  if ($this->is_error) {
80  throw new ilSaxParserException(implode('<br/>', $this->error_msg));
81  }
82  }
83 
89  public function setHandlers($a_xml_parser): void
90  {
91  xml_set_object($a_xml_parser, $this);
92  xml_set_element_handler($a_xml_parser, 'handlerBeginTag', 'handlerEndTag');
93  xml_set_character_data_handler($a_xml_parser, 'handlerCharacterData');
94  }
95 
100  protected function handlerBeginTag($a_xml_parser, $a_name, $a_attribs): void
101  {
102  switch ($a_name) {
103  case 'AdvancedMetaDataRecords':
104  $this->is_error = false;
105  $this->error_msg = array();
106  // Nothing to do
107  break;
108 
109  case 'Scope':
110  $this->scopes = [];
111  break;
112 
113  case 'ScopeEntry':
114  $parsed_id = ilUtil::parseImportId($a_attribs['id']);
115  if (
116  $parsed_id['inst_id'] == IL_INST_ID &&
117  ilObject::_exists($parsed_id['id'], true, $parsed_id['type'])
118  ) {
120  $scope->setRefId((int) $parsed_id['id']);
121  $this->scopes[] = $scope;
122  }
123  break;
124 
125  case 'Record':
126  $this->fields = array();
127  $this->current_field = null;
128  $this->current_record = null;
129  if (!strlen($a_attribs['id']) or !isset($a_attribs['active'])) {
130  $this->appendErrorMessage('Missing XML attribute for element "Record".');
131  }
132  if (!$this->initRecordObject((string) $a_attribs['id'])) {
133  $this->appendErrorMessage('Invalid attribute Id given for element "Record".');
134  }
135  $this->getCurrentRecord()->setActive((bool) $a_attribs['active']);
136  $this->getCurrentRecord()->setImportId($a_attribs['id']);
137  $this->getCurrentRecord()->setAssignedObjectTypes(array());
138 
139  if (isset($a_attribs['defaultLanguage'])) {
140  $language = (string) $a_attribs['defaultLanguage'];
141  if (ilLanguage::lookupId($language)) {
142  $this->getCurrentRecord()->setDefaultLanguage($language);
143  }
144  } else {
145  $this->getCurrentRecord()->setDefaultLanguage($this->lng->getDefaultLanguage());
146  }
147  break;
148 
149  case 'RecordTranslations':
150  $this->translations = [];
151  $this->field_translations = [];
152  $this->getCurrentRecord()->setDefaultLanguage(
153  $a_attribs['defaultLanguage'] ?? $this->getCurrentRecord()->getDefaultLanguage()
154  );
155  break;
156 
157  case 'RecordTranslation':
158  $this->translation_language = $a_attribs['language'] ?? $this->lng->getDefaultLanguage();
159  break;
160 
161  case 'FieldTranslations':
162  $this->field_translations[$this->getCurrentField()->getImportId()] = [];
163  break;
164 
165  case 'FieldTranslation':
166  $this->field_translation_language = $a_attribs['language'] ?? $this->lng->getDefaultLanguage();
167  break;
168 
169  case 'Title':
170  break;
171 
172  case 'Field':
173  if (!strlen($a_attribs['id']) or !isset($a_attribs['searchable']) or !isset($a_attribs['fieldType'])) {
174  $this->appendErrorMessage('Missing XML attribute for element "Field".');
175  }
176  if (!$this->initFieldObject((int) $a_attribs['id'], (string) $a_attribs['fieldType'])) {
177  $this->appendErrorMessage('Invalid attribute Id given for element "Record".');
178  }
179  $this->getCurrentField()->setImportId($a_attribs['id']);
180  $this->getCurrentField()->setSearchable($a_attribs['searchable'] == 'Yes');
181  break;
182 
183  case 'FieldTitle':
184  case 'FieldDescription':
185  case 'FieldPosition':
186  case 'FieldValue':
187  $this->field_value_id = (string) ($a_attribs['id'] ?? "");
188  break;
189  }
190  }
191 
196  protected function handlerEndTag($a_xml_parser, $a_name): void
197  {
198  switch ($a_name) {
199  case 'AdvancedMetaDataRecords':
200  break;
201 
202  case 'Record':
203  $this->storeRecords();
204  break;
205 
206  case 'Scope':
207  $this->getCurrentRecord()->setScopes($this->scopes);
208  break;
209 
210  case 'Title':
211  $this->getCurrentRecord()->setTitle(trim($this->cdata));
212  break;
213 
214  case 'Description':
215  $this->getCurrentRecord()->setDescription(trim($this->cdata));
216  break;
217 
218  case 'ObjectType':
219  // #12980
220  $parts = explode(":", trim($this->cdata));
221  $this->getCurrentRecord()->appendAssignedObjectType($parts[0], $parts[1]);
222  break;
223 
224  case 'Field':
225  break;
226 
227  case 'RecordTranslationTitle':
228  $this->translations[$this->translation_language]['title'] = trim($this->cdata);
229  break;
230 
231  case 'RecordTranslationDescription':
232  $this->translations[$this->translation_language]['description'] = trim($this->cdata);
233  break;
234 
235  case 'FieldTranslationTitle':
236  $this->field_translations[$this->getCurrentField()->getImportId()][$this->field_translation_language]['title'] = trim($this->cdata);
237  break;
238 
239  case 'FieldTranslationDescription':
240  $this->field_translations[$this->getCurrentField()->getImportId()][$this->field_translation_language]['description'] = trim($this->cdata);
241  break;
242 
243  case 'FieldTitle':
244  $this->getCurrentField()->setTitle(trim($this->cdata));
245  break;
246 
247  case 'FieldDescription':
248  $this->getCurrentField()->setDescription(trim($this->cdata));
249  break;
250 
251  case 'FieldPosition':
252  $this->getCurrentField()->setPosition((int) trim($this->cdata));
253  break;
254 
255  case 'FieldValue':
256  $this->getCurrentField()->importXMLProperty($this->field_value_id, trim($this->cdata));
257  break;
258  }
259  $this->cdata = '';
260  }
261 
267  protected function handlerCharacterData($a_xml_parser, string $a_data): void
268  {
269  if ($a_data != "\n") {
270  // Replace multiple tabs with one space
271  $a_data = preg_replace("/\t+/", " ", $a_data);
272 
273  $this->cdata .= $a_data;
274  }
275  }
276 
277  private function initRecordObject(string $a_id): bool
278  {
279  switch ($this->getMode()) {
280  case self::MODE_INSERT:
281  case self::MODE_INSERT_VALIDATION:
282  $this->current_record = new ilAdvancedMDRecord(0);
283  return true;
284 
285  default:
286  $this->current_record = ilAdvancedMDRecord::_getInstanceByRecordId($this->extractRecordId($a_id));
287  return true;
288  }
289  }
290 
294  private function initFieldObject(int $a_id, string $a_type)
295  {
296  switch ($this->getMode()) {
297  case self::MODE_INSERT:
298  case self::MODE_INSERT_VALIDATION:
299  $this->current_field = ilAdvancedMDFieldDefinition::getInstanceByTypeString($a_type);
300  $this->fields[] = $this->current_field;
301  return true;
302 
303  default:
304  throw new InvalidArgumentException(
305  'Current parsing mode is not supported. Mode: ' . $this->getMode()
306  );
307  }
308  }
309 
311  {
312  return $this->current_record;
313  }
314 
316  {
317  return $this->current_field;
318  }
319 
320  private function extractRecordId(string $a_id_string): int
321  {
322  // first lookup import id
323  if ($record_id = ilAdvancedMDRecord::_lookupRecordIdByImportId($a_id_string)) {
324  return $record_id;
325  }
326  return 0;
327  }
328 
329  private function appendErrorMessage(string $a_msg): void
330  {
331  $this->is_error = true;
332  $this->error_msg[] = $a_msg;
333  }
334 
335  private function storeRecords(): void
336  {
337  switch ($this->getMode()) {
338  case self::MODE_INSERT_VALIDATION:
339  case self::MODE_UPDATE_VALIDATION:
340  return;
341 
342  case self::MODE_INSERT:
343  // set local context
344  if (isset($this->context) && is_array($this->context)) {
345  $this->getCurrentRecord()->setParentObject($this->context["obj_id"]);
346  $this->getCurrentRecord()->setAssignedObjectTypes(array(
347  array(
348  "obj_type" => $this->context["obj_type"],
349  "sub_type" => $this->context["sub_type"],
350  "optional" => false
351  )
352  ));
353  }
354 
355  $this->getCurrentRecord()->save();
356  break;
357  }
358  foreach ($this->fields as $field) {
359  $field->setRecordId($this->getCurrentRecord()->getRecordId());
360  switch ($this->getMode()) {
361  case self::MODE_INSERT:
362  $field->save();
363  foreach ($this->field_translations as $field_id => $field_info) {
364  if (strcmp($field_id, $field->getImportId()) !== 0) {
365  continue;
366  }
367  foreach ((array) $field_info as $language => $field_translation) {
368  $translation = new ilAdvancedMDFieldTranslation(
369  (int) $field->getFieldId(),
370  (string) $field_translation['title'],
371  (string) $field_translation['description'],
372  (string) $language
373  );
374  $translation->insert();
375  }
376  }
377 
378  // see getRecordMap()
379  $this->log->debug("add to record map, rec id: " . $this->getCurrentRecord()->getRecordId() .
380  ", import id: " . $field->getImportId() . ", field id:" . $field->getFieldId());
381  $this->rec_map[$this->getCurrentRecord()->getRecordId()][$field->getImportId()] = $field->getFieldId();
382  break;
383  }
384  }
386  $translations->addTranslationEntry($this->getCurrentRecord()->getDefaultLanguage(), true);
387  $translations->updateTranslations(
388  $this->getCurrentRecord()->getDefaultLanguage(),
389  $this->getCurrentRecord()->getTitle(),
390  $this->getCurrentRecord()->getDescription()
391  );
392 
393  foreach ($this->translations as $lang_key => $translation_info) {
394  if (!$translations->isConfigured($lang_key)) {
395  $translations->addTranslationEntry($lang_key);
396  }
397  $translations->updateTranslations(
398  $lang_key,
399  (string) $translation_info['title'],
400  (string) $translation_info['description']
401  );
402  }
403  }
404 
405  public function setContext(int $a_obj_id, string $a_obj_type, ?string $a_sub_type = null): void
406  {
407  if (!$a_sub_type) {
408  $a_sub_type = "-";
409  }
410 
411  $this->context = array(
412  "obj_id" => $a_obj_id,
413  "obj_type" => $a_obj_type,
414  "sub_type" => $a_sub_type
415  );
416  }
417 
418  public function getRecordMap(): array
419  {
420  return $this->rec_map;
421  }
422 }
Scope restrictions for advanced md records.
getRecordId()
Get the system record ID.
Definition: System.php:214
initFieldObject(int $a_id, string $a_type)
Init field definition object.
setHandlers($a_xml_parser)
set event handlers
$scope
Definition: ltiregstart.php:53
const IL_INST_ID
Definition: constants.php:40
ilAdvancedMDFieldDefinition $current_field
static getLogger(string $a_component_id)
Get component logger.
$errors fields
Definition: imgupload.php:67
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:64
setContext(int $a_obj_id, string $a_obj_type, ?string $a_sub_type=null)
SaxParserException thrown by ilSaxParser if property throwException is set.
handlerEndTag($a_xml_parser, $a_name)
Handler for end tags protected.
handlerCharacterData($a_xml_parser, string $a_data)
handler for character data
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getInstanceByRecordId(int $a_record_id)
static _lookupRecordIdByImportId(string $a_ilias_id)
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
handlerBeginTag($a_xml_parser, $a_name, $a_attribs)
Handler for start tags protected.
static lookupId(string $a_lang_key)
Lookup obj_id of language.
static parseImportId(string $a_import_id)
Parse an ilias import id Typically of type il_[IL_INST_ID]_[OBJ_TYPE]_[OBJ_ID] returns array( &#39;orig&#39; ...
__construct(Container $dic, ilPlugin $plugin)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByTypeString(string $a_type)
Get instance by type string (used by import)
Class ilAdvancedMDFieldTranslation.