ILIAS  trunk Revision v11.0_alpha-1723-g8e69f309bab
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.ilAdvancedMDRecordParser.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
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_element_handler($a_xml_parser, $this->handlerBeginTag(...), $this->handlerEndTag(...));
92  xml_set_character_data_handler($a_xml_parser, $this->handlerCharacterData(...));
93  }
94 
99  protected function handlerBeginTag($a_xml_parser, $a_name, $a_attribs): void
100  {
101  switch ($a_name) {
102  case 'AdvancedMetaDataRecords':
103  $this->is_error = false;
104  $this->error_msg = array();
105  // Nothing to do
106  break;
107 
108  case 'Scope':
109  $this->scopes = [];
110  break;
111 
112  case 'ScopeEntry':
113  $parsed_id = ilUtil::parseImportId($a_attribs['id']);
114  if (
115  $parsed_id['inst_id'] == IL_INST_ID &&
116  ilObject::_exists($parsed_id['id'], true, $parsed_id['type'])
117  ) {
119  $scope->setRefId((int) $parsed_id['id']);
120  $this->scopes[] = $scope;
121  }
122  break;
123 
124  case 'Record':
125  $this->fields = array();
126  $this->current_field = null;
127  $this->current_record = null;
128  if (!strlen($a_attribs['id']) or !isset($a_attribs['active'])) {
129  $this->appendErrorMessage('Missing XML attribute for element "Record".');
130  }
131  if (!$this->initRecordObject((string) $a_attribs['id'])) {
132  $this->appendErrorMessage('Invalid attribute Id given for element "Record".');
133  }
134  $this->getCurrentRecord()->setActive((bool) $a_attribs['active']);
135  $this->getCurrentRecord()->setImportId($a_attribs['id']);
136  $this->getCurrentRecord()->setAssignedObjectTypes(array());
137 
138  if (isset($a_attribs['defaultLanguage'])) {
139  $language = (string) $a_attribs['defaultLanguage'];
140  if (ilLanguage::lookupId($language)) {
141  $this->getCurrentRecord()->setDefaultLanguage($language);
142  }
143  } else {
144  $this->getCurrentRecord()->setDefaultLanguage($this->lng->getDefaultLanguage());
145  }
146  break;
147 
148  case 'RecordTranslations':
149  $this->translations = [];
150  $this->field_translations = [];
151  $this->getCurrentRecord()->setDefaultLanguage(
152  $a_attribs['defaultLanguage'] ?? $this->getCurrentRecord()->getDefaultLanguage()
153  );
154  break;
155 
156  case 'RecordTranslation':
157  $this->translation_language = $a_attribs['language'] ?? $this->lng->getDefaultLanguage();
158  break;
159 
160  case 'FieldTranslations':
161  $this->field_translations[$this->getCurrentField()->getImportId()] = [];
162  break;
163 
164  case 'FieldTranslation':
165  $this->field_translation_language = $a_attribs['language'] ?? $this->lng->getDefaultLanguage();
166  break;
167 
168  case 'Title':
169  break;
170 
171  case 'Field':
172  if (!strlen($a_attribs['id']) or !isset($a_attribs['searchable']) or !isset($a_attribs['fieldType'])) {
173  $this->appendErrorMessage('Missing XML attribute for element "Field".');
174  }
175  if (!$this->initFieldObject((int) $a_attribs['id'], (string) $a_attribs['fieldType'])) {
176  $this->appendErrorMessage('Invalid attribute Id given for element "Record".');
177  }
178  $this->getCurrentField()->setImportId($a_attribs['id']);
179  $this->getCurrentField()->setSearchable($a_attribs['searchable'] == 'Yes');
180  break;
181 
182  case 'FieldTitle':
183  case 'FieldDescription':
184  case 'FieldPosition':
185  case 'FieldValue':
186  $this->field_value_id = (string) ($a_attribs['id'] ?? "");
187  break;
188  }
189  }
190 
195  protected function handlerEndTag($a_xml_parser, $a_name): void
196  {
197  switch ($a_name) {
198  case 'AdvancedMetaDataRecords':
199  break;
200 
201  case 'Record':
202  $this->storeRecords();
203  break;
204 
205  case 'Scope':
206  $this->getCurrentRecord()->setScopes($this->scopes);
207  break;
208 
209  case 'Title':
210  $this->getCurrentRecord()->setTitle(trim($this->cdata));
211  break;
212 
213  case 'Description':
214  $this->getCurrentRecord()->setDescription(trim($this->cdata));
215  break;
216 
217  case 'ObjectType':
218  // #12980
219  $parts = explode(":", trim($this->cdata));
220  $this->getCurrentRecord()->appendAssignedObjectType($parts[0], $parts[1]);
221  break;
222 
223  case 'Field':
224  break;
225 
226  case 'RecordTranslationTitle':
227  $this->translations[$this->translation_language]['title'] = trim($this->cdata);
228  break;
229 
230  case 'RecordTranslationDescription':
231  $this->translations[$this->translation_language]['description'] = trim($this->cdata);
232  break;
233 
234  case 'FieldTranslationTitle':
235  $this->field_translations[$this->getCurrentField()->getImportId()][$this->field_translation_language]['title'] = trim($this->cdata);
236  break;
237 
238  case 'FieldTranslationDescription':
239  $this->field_translations[$this->getCurrentField()->getImportId()][$this->field_translation_language]['description'] = trim($this->cdata);
240  break;
241 
242  case 'FieldTitle':
243  $this->getCurrentField()->setTitle(trim($this->cdata));
244  break;
245 
246  case 'FieldDescription':
247  $this->getCurrentField()->setDescription(trim($this->cdata));
248  break;
249 
250  case 'FieldPosition':
251  $this->getCurrentField()->setPosition((int) trim($this->cdata));
252  break;
253 
254  case 'FieldValue':
255  $this->getCurrentField()->importXMLProperty($this->field_value_id, trim($this->cdata));
256  break;
257  }
258  $this->cdata = '';
259  }
260 
266  protected function handlerCharacterData($a_xml_parser, string $a_data): void
267  {
268  if ($a_data != "\n") {
269  // Replace multiple tabs with one space
270  $a_data = preg_replace("/\t+/", " ", $a_data);
271 
272  $this->cdata .= $a_data;
273  }
274  }
275 
276  private function initRecordObject(string $a_id): bool
277  {
278  switch ($this->getMode()) {
279  case self::MODE_INSERT:
280  case self::MODE_INSERT_VALIDATION:
281  $this->current_record = new ilAdvancedMDRecord(0);
282  return true;
283 
284  default:
285  $this->current_record = ilAdvancedMDRecord::_getInstanceByRecordId($this->extractRecordId($a_id));
286  return true;
287  }
288  }
289 
293  private function initFieldObject(int $a_id, string $a_type)
294  {
295  switch ($this->getMode()) {
296  case self::MODE_INSERT:
297  case self::MODE_INSERT_VALIDATION:
298  $this->current_field = ilAdvancedMDFieldDefinition::getInstanceByTypeString($a_type);
299  $this->fields[] = $this->current_field;
300  return true;
301 
302  default:
303  throw new InvalidArgumentException(
304  'Current parsing mode is not supported. Mode: ' . $this->getMode()
305  );
306  }
307  }
308 
310  {
311  return $this->current_record;
312  }
313 
315  {
316  return $this->current_field;
317  }
318 
319  private function extractRecordId(string $a_id_string): int
320  {
321  // first lookup import id
322  if ($record_id = ilAdvancedMDRecord::_lookupRecordIdByImportId($a_id_string)) {
323  return $record_id;
324  }
325  return 0;
326  }
327 
328  private function appendErrorMessage(string $a_msg): void
329  {
330  $this->is_error = true;
331  $this->error_msg[] = $a_msg;
332  }
333 
334  private function storeRecords(): void
335  {
336  switch ($this->getMode()) {
337  case self::MODE_INSERT_VALIDATION:
338  case self::MODE_UPDATE_VALIDATION:
339  return;
340 
341  case self::MODE_INSERT:
342  // set local context
343  if (isset($this->context) && is_array($this->context)) {
344  $this->getCurrentRecord()->setParentObject($this->context["obj_id"]);
345  $this->getCurrentRecord()->setAssignedObjectTypes(array(
346  array(
347  "obj_type" => $this->context["obj_type"],
348  "sub_type" => $this->context["sub_type"],
349  "optional" => false
350  )
351  ));
352  }
353 
354  $this->getCurrentRecord()->save();
355  break;
356  }
357  foreach ($this->fields as $field) {
358  $field->setRecordId($this->getCurrentRecord()->getRecordId());
359  switch ($this->getMode()) {
360  case self::MODE_INSERT:
361  $field->save(false, true);
362  foreach ($this->field_translations as $field_id => $field_info) {
363  if (strcmp($field_id, $field->getImportId()) !== 0) {
364  continue;
365  }
366  foreach ((array) $field_info as $language => $field_translation) {
367  $translation = new ilAdvancedMDFieldTranslation(
368  (int) $field->getFieldId(),
369  (string) $field_translation['title'],
370  (string) $field_translation['description'],
371  (string) $language
372  );
373  $translation->insert();
374  }
375  }
376 
377  // see getRecordMap()
378  $this->log->debug("add to record map, rec id: " . $this->getCurrentRecord()->getRecordId() .
379  ", import id: " . $field->getImportId() . ", field id:" . $field->getFieldId());
380  $this->rec_map[$this->getCurrentRecord()->getRecordId()][$field->getImportId()] = $field->getFieldId();
381  break;
382  }
383  }
384  $translations = ilAdvancedMDRecordTranslations::getInstanceByRecordId($this->getCurrentRecord()->getRecordId());
385  $translations->addTranslationEntry($this->getCurrentRecord()->getDefaultLanguage(), true);
386  $translations->updateTranslations(
387  $this->getCurrentRecord()->getDefaultLanguage(),
388  $this->getCurrentRecord()->getTitle(),
389  $this->getCurrentRecord()->getDescription()
390  );
391 
392  foreach ($this->translations as $lang_key => $translation_info) {
393  if (!$translations->isConfigured($lang_key)) {
394  $translations->addTranslationEntry($lang_key);
395  }
396  $translations->updateTranslations(
397  $lang_key,
398  (string) $translation_info['title'],
399  (string) $translation_info['description']
400  );
401  }
402  }
403 
404  public function setContext(int $a_obj_id, string $a_obj_type, ?string $a_sub_type = null): void
405  {
406  if (!$a_sub_type) {
407  $a_sub_type = "-";
408  }
409 
410  $this->context = array(
411  "obj_id" => $a_obj_id,
412  "obj_type" => $a_obj_type,
413  "sub_type" => $a_sub_type
414  );
415  }
416 
417  public function getRecordMap(): array
418  {
419  return $this->rec_map;
420  }
421 }
Scope restrictions for advanced md records.
initFieldObject(int $a_id, string $a_type)
Init field definition object.
setHandlers($a_xml_parser)
set event handlers
$scope
Definition: ltiregstart.php:47
const IL_INST_ID
Definition: constants.php:40
ilAdvancedMDFieldDefinition $current_field
static getLogger(string $a_component_id)
Get component logger.
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
setContext(int $a_obj_id, string $a_obj_type, ?string $a_sub_type=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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...
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
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)
SAX based XML parser for record import files.
static getInstanceByTypeString(string $a_type)
Get instance by type string (used by import)
Class ilAdvancedMDFieldTranslation.