ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilAdvancedMDRecordParser.php
Go to the documentation of this file.
1<?php
2
19declare(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
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()) {
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()) {
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 {
312 }
313
315 {
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()) {
339 return;
340
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()) {
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 }
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}
static getInstanceByTypeString(string $a_type)
Get instance by type string (used by import)
Class ilAdvancedMDFieldTranslation.
SAX based XML parser for record import files.
handlerCharacterData($a_xml_parser, string $a_data)
handler for character data
handlerBeginTag($a_xml_parser, $a_name, $a_attribs)
Handler for start tags @access protected.
initFieldObject(int $a_id, string $a_type)
Init field definition object.
setHandlers($a_xml_parser)
set event handlers
ilAdvancedMDFieldDefinition $current_field
startParsing()
stores xml data in array
handlerEndTag($a_xml_parser, $a_name)
Handler for end tags @access protected.
setContext(int $a_obj_id, string $a_obj_type, ?string $a_sub_type=null)
Scope restrictions for advanced md records.
static _getInstanceByRecordId(int $a_record_id)
static _lookupRecordIdByImportId(string $a_ilias_id)
static lookupId(string $a_lang_key)
Lookup obj_id of language.
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static parseImportId(string $a_import_id)
Parse an ilias import id Typically of type il_[IL_INST_ID]_[OBJ_TYPE]_[OBJ_ID] returns array( 'orig' ...
const IL_INST_ID
Definition: constants.php:40
$scope
Definition: ltiregstart.php:51
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc