ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilDataSet.php
Go to the documentation of this file.
1 <?php
2 
24 
42 abstract class ilDataSet
43 {
44  public const DATASET_NS = 'http://www.ilias.de/Services/DataSet/ds/4_3';
45  public const DATASET_NS_PREFIX = 'ds';
46 
47  public const EXPORT_NO_INST_ID = 1;
48  public const EXPORT_ID_ILIAS_LOCAL = 2;
50  public const EXPORT_ID_ILIAS_REMOTE = 4;
52  public const EXPORT_ID = 6;
53  public const EXPORT_ID_INVALID = 7;
54  protected \ILIAS\ResourceStorage\Services $irss;
55 
56  public int $dircnt = 0;
57  protected string $current_installation_id = "";
58  protected array $data = [];
59  protected ilDBInterface $db;
60  protected ilLogger $ds_log;
61  protected string $import_directory = "";
62  protected string $entity = "";
63  protected string $schema_version = "";
64  protected string $component_export_dir = "";
65  protected string $ds_prefix = "ds";
66  protected string $version = "";
68  protected ilExport $export;
69 
70  public function __construct()
71  {
72  global $DIC;
73 
74  $this->db = $DIC->database();
75  $this->ds_log = ilLoggerFactory::getLogger('ds');
76  $this->irss = $DIC->resourceStorage();
77  }
78 
91  final public function init(string $a_entity, string $a_schema_version): void
92  {
93  $this->entity = $a_entity;
94  $this->schema_version = $a_schema_version;
95  $this->data = array();
96  }
97 
98  abstract public function getSupportedVersions(): array;
99 
107  abstract protected function getTypes(string $a_entity, string $a_version): array;
108 
109  abstract protected function getXmlNamespace(string $a_entity, string $a_schema_version): string;
110 
115  abstract public function readData(
116  string $a_entity,
117  string $a_version,
118  array $a_ids
119  ): void;
120 
121  public function initByExporter(ilXmlExporter $xml_exporter): void
122  {
123  $this->export = $xml_exporter->getExport();
124  }
125 
126  public function setImportDirectory(string $a_val): void
127  {
128  $this->import_directory = $a_val;
129  }
130 
131  public function getImportDirectory(): string
132  {
134  }
135 
136  public function setDSPrefix(string $a_val): void
137  {
138  $this->ds_prefix = $a_val;
139  }
140 
141  public function getDSPrefix(): string
142  {
143  return $this->ds_prefix;
144  }
145 
146  public function getDSPrefixString(): string
147  {
148  if ($this->getDSPrefix() !== "") {
149  return $this->getDSPrefix() . ":";
150  }
151  return "";
152  }
153 
158  public function getDirectDataFromQuery(
159  string $a_query,
160  bool $a_convert_to_leading_upper = true,
161  bool $a_set = true
162  ): array {
163  $ilDB = $this->db;
164 
165  $set = $ilDB->query($a_query);
166  $this->data = array();
167  $ret = [];
168  while ($rec = $ilDB->fetchAssoc($set)) {
169  if ($a_convert_to_leading_upper) {
170  $tmp = array();
171  foreach ($rec as $k => $v) {
172  $tmp[$this->convertToLeadingUpper($k)]
173  = $v;
174  }
175  $rec = $tmp;
176  }
177 
178  if ($a_set) {
179  $this->data[] = $rec;
180  }
181  $ret[] = $rec;
182  }
183  return $ret;
184  }
185 
189  public function convertToLeadingUpper(string $a_str): string
190  {
191  $a_str = strtoupper(substr($a_str, 0, 1)) . substr($a_str, 1);
192  while (($pos = strpos($a_str, "_")) !== false) {
193  $a_str = substr($a_str, 0, $pos) .
194  strtoupper(substr($a_str, $pos + 1, 1)) .
195  substr($a_str, $pos + 2);
196  }
197  return $a_str;
198  }
199 
200 
222  final public function getXmlRepresentation(
223  string $a_entity,
224  string $a_schema_version,
225  ?array $a_ids,
226  string $a_field = "",
227  bool $a_omit_header = false,
228  bool $a_omit_types = false
229  ): string {
230  $this->dircnt = 1;
231 
232  // init writer
233  $writer = new ilXmlWriter();
234  if (!$a_omit_header) {
235  $writer->xmlHeader();
236  }
237 
238  // collect namespaces
239  $namespaces = $prefixes = array();
240  $this->getNamespaces($namespaces, $a_entity, $a_schema_version);
241  $atts = array("InstallationId" => IL_INST_ID,
242  "InstallationUrl" => ILIAS_HTTP_PATH, "TopEntity" => $a_entity);
243  $cnt = 1;
244  foreach ($namespaces as $entity => $ns) {
245  $prefix = "ns" . $cnt;
246  $prefixes[$entity] = $prefix;
247  // $atts["xmlns:".$prefix] = $ns;
248  $cnt++;
249  }
250  $this->ds_log->debug("Start writing Dataset, entity: " . $a_entity . ", schema version: " . $a_schema_version .
251  ", ids: " . print_r($a_ids, true));
252 
253  if ($this->getDSPrefix() !== '') {
254  $atts['xmlns:' . $this->getDSPrefix()] = self::DATASET_NS;
255  } else {
256  $atts['xmlns'] = self::DATASET_NS;
257  }
258  $writer->xmlStartTag($this->getDSPrefixString() . 'DataSet', $atts);
259  // add types
260  if (!$a_omit_types) {
261  $this->ds_log->debug("...write types");
262  $this->addTypesXml($writer, $a_entity, $a_schema_version);
263  }
264  // add records
265  $this->ds_log->debug("...write records");
266  $this->addRecordsXml($writer, $prefixes, $a_entity, $a_schema_version, $a_ids, $a_field);
267 
268  $writer->xmlEndTag($this->getDSPrefixString() . "DataSet");
269 
270  return $writer->xmlDumpMem(false);
271  }
272 
273  protected function getExportDirInContainer(string $exp_dir): string
274  {
275  // note, the export returns in ILIAS 10 (Jan 2024) something like
276  // 1737382047__0__cat_436/components/ILIAS/Style/set_0/dsDir_1
277  // whereas ILIAS 9 returned
278  // Services/Style/set_1/expDir_1/dsDir_1
279  // thus we skip the 1737382047__0__cat_436/ part since it would be redundant
280  // an make import fail
281  if (str_contains($exp_dir, "components/")) {
282  $exp_dir = substr($exp_dir, strpos($exp_dir, "components/"));
283  }
284  return $exp_dir;
285  }
286 
287  public function addRecordsXml(
288  ilXmlWriter $a_writer,
289  array $a_prefixes,
290  string $a_entity,
291  string $a_schema_version,
292  array $a_ids,
293  ?string $a_field = ""
294  ): void {
295  $types = $this->getXmlTypes($a_entity, $a_schema_version);
296  $this->ds_log->debug("...read data");
297  $this->readData($a_entity, $a_schema_version, $a_ids);
298  $this->ds_log->debug("...data: " . print_r($this->data, true));
299  foreach ($this->data as $d) {
300  $a_writer->xmlStartTag(
301  $this->getDSPrefixString() . "Rec",
302  array("Entity" => $this->getXMLEntityName($a_entity, $a_schema_version))
303  );
304  $a_writer->xmlStartTag($this->getXMLEntityTag($a_entity, ''));
305  $rec = $this->getXmlRecord($a_entity, $a_schema_version, $d);
306  foreach ($rec as $f => $c) {
307  if (isset($this->export) and ($types[$f] ?? "") === "directory") {
308  $sdir = realpath($c);
309  $path_in_container = $this->export->getPathToComponentExpDirInContainer() . "/dsDir_" . $this->dircnt;
310  $this->export->getExportWriter()->writeDirectory(
311  $sdir,
312  $path_in_container
313  );
314  $c = $this->getExportDirInContainer($path_in_container); // note: this corrects the path, see above
315  $this->dircnt++;
316  }
317  if (isset($this->export) and ($types[$f] ?? "") === "rscollection") {
318  $path_in_container = $this->export->getPathToComponentExpDirInContainer() . "/dsDir_" . $this->dircnt;
319  $collection = $this->getCollection($rec, $a_entity, $a_schema_version, $f, $c);
320  if (!is_null($collection)) {
321  $this->export->getExportWriter()->writeFilesByResourceCollection(
322  $collection,
323  $path_in_container
324  );
325  }
326 
327  $c = $this->getExportDirInContainer($path_in_container); // note: this corrects the path, see above
328  $this->dircnt++;
329  }
330  if (isset($this->export) and ($types[$f] ?? "") === "rscontainer") {
331  $path_in_container = "/dsDir_" . $this->dircnt;
332  if ($this->export->isContainerExport()) { // note: this checks if the export is in a container context and adds the set number to the path accordingly
333  $path_in_container = $this->export->getPathToComponentExpDirInContainerWithLeadingSetNumber() . $path_in_container;
334  } else {
335  $path_in_container = $this->export->getPathToComponentExpDirInContainer() . $path_in_container;
336  }
337  if ($config = $this->getContainerExportConfig($rec, $a_entity, $a_schema_version, $f, $c)) {
338  $this->export->getExportWriter()->writeFilesByResourceContainer(
340  $config->getSourceContainer(),
341  $config->getSourcePath(),
342  $path_in_container
343  )
344  );
345  }
346  $c = $this->getExportDirInContainer($path_in_container); // note: this corrects the path, see above
347  $this->dircnt++;
348  }
349  // this changes schema/dtd
350  //$a_writer->xmlElement($a_prefixes[$a_entity].":".$f,
351  // array(), $c);
352  $a_writer->xmlElement($f, array(), $c);
353  }
354 
355  $a_writer->xmlEndTag($this->getXMLEntityTag($a_entity, ''));
356 
357  $a_writer->xmlEndTag($this->getDSPrefixString() . "Rec");
358 
359  $this->afterXmlRecordWriting($a_entity, $a_schema_version, $d);
360 
361  // foreach record records of dependent entities
362  $this->ds_log->debug("...get dependencies");
363  $deps = $this->getDependencies($a_entity, $a_schema_version, $rec, $a_ids);
364  $this->ds_log->debug("...dependencies: " . print_r($deps, true));
365  foreach ($deps as $dp => $par) {
366  $ids = !is_array($par["ids"])
367  ? [$par["ids"]]
368  : $par["ids"];
369  $this->addRecordsXml($a_writer, $a_prefixes, $dp, $a_schema_version, $ids, $par["field"] ?? null);
370  }
371  }
372  }
373 
374  protected function getIRSSContainerExportConfig(
375  StorableResource $source_container,
376  string $source_path,
377  string $target_path = ""
379  return new IRSSContainerExportConfig(
380  $source_container,
381  $source_path,
382  $target_path
383  );
384  }
385 
386  protected function getDependencies(
387  string $a_entity,
388  string $a_version,
389  ?array $a_rec = null,
390  ?array $a_ids = null
391  ): array {
392  return [];
393  }
394 
395  // After xml record writing hook record
396  public function afterXmlRecordWriting(string $a_entity, string $a_version, array $a_set): void
397  {
398  }
399 
400  // Add types to xml writer
401  private function addTypesXml(ilXmlWriter $a_writer, string $a_entity, string $a_schema_version): void
402  {
403  $types = $this->getXmlTypes($a_entity, $a_schema_version);
404 
405  // add types of current entity
406  if (count($types) > 0) {
407  $a_writer->xmlStartTag(
408  $this->getDSPrefixString() . "Types",
409  array("Entity" => $this->getXMLEntityName($a_entity, $a_schema_version),
410  "SchemaVersion" => $a_schema_version)
411  );
412  foreach ($this->getXmlTypes($a_entity, $a_schema_version) as $f => $t) {
413  $a_writer->xmlElement(
414  $this->getDSPrefixString() . 'FieldType',
415  array("Name" => $f, "Type" => $t)
416  );
417  }
418  $a_writer->xmlEndTag($this->getDSPrefixString() . "Types");
419  }
420 
421  // add types of dependent entities
422  $deps = $this->getDependencies($a_entity, $a_schema_version, null, null);
423  foreach ($deps as $dp => $w) {
424  $this->addTypesXml($a_writer, $dp, $a_schema_version);
425  }
426  }
427 
428  // Get xml namespaces
429  public function getNamespaces(array &$namespaces, string $a_entity, string $a_schema_version): void
430  {
431  $ns = $this->getXmlNamespace($a_entity, $a_schema_version);
432  if ($ns !== "") {
433  $namespaces[$a_entity] = $ns;
434  }
435  // add types of dependent entities
436  $deps = $this->getDependencies($a_entity, $a_schema_version, null, null);
437  foreach ($deps as $dp => $w) {
438  $this->getNamespaces($namespaces, $dp, $a_schema_version);
439  }
440  }
441 
446  public function getXmlRecord(string $a_entity, string $a_version, array $a_set): array
447  {
448  return $a_set;
449  }
450 
455  public function getXmlTypes(string $a_entity, string $a_version): array
456  {
457  return $this->getTypes($a_entity, $a_version);
458  }
459 
464  public function getXMLEntityName(string $a_entity, string $a_version): string
465  {
466  return $a_entity;
467  }
468 
472  public function getXMLEntityTag(string $a_entity, string $a_schema_version): string
473  {
474  return $this->convertToLeadingUpper($a_entity);
475  }
476 
477  public function setImport(ilSurveyImporter $a_val): void
478  {
479  $this->import = $a_val;
480  }
481 
482  public function getImport(): ilSurveyImporter
483  {
484  return $this->import;
485  }
486 
487  public function setCurrentInstallationId(string $a_val): void
488  {
489  $this->current_installation_id = $a_val;
490  }
491 
492  public function getCurrentInstallationId(): string
493  {
495  }
496 
500  protected function createObjectExportId(string $a_type, string $a_id): string
501  {
502  return "il_" . IL_INST_ID . "_" . $a_type . "_" . $a_id;
503  }
504 
509  protected function parseObjectExportId(string $a_id, ?string $a_fallback_id = null): array
510  {
511  // ilias export id?
512  if (strpos($a_id, "il_") === 0) {
513  $parts = explode("_", $a_id);
514  if (count($parts) !== 4) {
515  throw new ilException("Invalid import ID '" . $a_id . "'.");
516  }
517  $inst_id = $parts[1];
518  $type = $parts[2];
519  $id = $parts[3];
520 
521  // missing installation ids?
522  if (($inst_id == 0 || IL_INST_ID === "0") && !DEVMODE) {
523  return array("type" => self::EXPORT_NO_INST_ID, "id" => $a_fallback_id);
524  }
525 
526  // same installation?
527  if ($inst_id == IL_INST_ID) {
528  // still existing?
529  if (ilObject::_lookupType($id) === $type) {
530  return array("type" => self::EXPORT_ID_ILIAS_LOCAL, "id" => $id);
531  }
532  // not found
533  else {
534  return array("type" => self::EXPORT_ID_ILIAS_LOCAL_INVALID, "id" => $a_fallback_id);
535  }
536  }
537  // different installation
538  else {
540  // matching type?
541  if ($id && ilObject::_lookupType($id) === $type) {
542  return array("type" => self::EXPORT_ID_ILIAS_REMOTE, "id" => $id);
543  }
544  // not found
545  else {
546  return array("type" => self::EXPORT_ID_ILIAS_REMOTE_INVALID, "id" => $a_fallback_id);
547  }
548  }
549  } else {
550  // external id
552  if ($id) {
553  return array("type" => self::EXPORT_ID, "id" => $id);
554  } else {
555  return array("type" => self::EXPORT_ID_INVALID, "id" => $a_fallback_id);
556  }
557  }
558  }
559 
563  public function importRecord(
564  string $a_entity,
565  array $a_types,
566  array $a_rec,
567  ilImportMapping $a_mapping,
568  string $a_schema_version
569  ): void {
570  }
571 
572  public function getCollection(
573  array $record,
574  string $entity,
575  string $schema_version,
576  string $field,
577  string $value
578  ): ?ResourceCollection {
579  return null;
580  }
581 
582  public function getContainerExportConfig(
583  array $record,
584  string $entity,
585  string $schema_version,
586  string $field,
587  string $value
589  return null;
590  }
591 
592  protected function stripTags(array $rec, array $omit_keys = []): array
593  {
594  $ret_rec = [];
595  foreach ($rec as $k => $v) {
596  if (in_array($k, $omit_keys, true)) {
597  $ret_rec[$k] = $v;
598  } else {
599  $ret_rec[$k] = ilUtil::stripSlashes($v);
600  }
601  }
602  return $ret_rec;
603  }
604 }
ilLogger $ds_log
getXMLEntityName(string $a_entity, string $a_version)
Get entity name for xml (may be overwritten)
readData(string $a_entity, string $a_version, array $a_ids)
Read data from DB.
const EXPORT_ID_ILIAS_REMOTE
init(string $a_entity, string $a_schema_version)
Init.
const DATASET_NS_PREFIX
string $import_directory
getCollection(array $record, string $entity, string $schema_version, string $field, string $value)
convertToLeadingUpper(string $a_str)
Make xyz_abc a XyzAbc string.
const IL_INST_ID
Definition: constants.php:40
getXmlRecord(string $a_entity, string $a_version, array $a_set)
Get xml record for version.
setCurrentInstallationId(string $a_val)
static getLogger(string $a_component_id)
Get component logger.
getContainerExportConfig(array $record, string $entity, string $schema_version, string $field, string $value)
initByExporter(ilXmlExporter $xml_exporter)
setImportDirectory(string $a_val)
getNamespaces(array &$namespaces, string $a_entity, string $a_schema_version)
string $schema_version
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
getXmlNamespace(string $a_entity, string $a_schema_version)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
getXmlTypes(string $a_entity, string $a_version)
Get xml types.
const EXPORT_ID_ILIAS_LOCAL_INVALID
parseObjectExportId(string $a_id, ?string $a_fallback_id=null)
Parse export id.
string $ds_prefix
const EXPORT_NO_INST_ID
getExportDirInContainer(string $exp_dir)
$c
Definition: deliver.php:25
addRecordsXml(ilXmlWriter $a_writer, array $a_prefixes, string $a_entity, string $a_schema_version, array $a_ids, ?string $a_field="")
static _getIdForImportId(string $import_id)
getIRSSContainerExportConfig(StorableResource $source_container, string $source_path, string $target_path="")
xmlEndTag(string $tag)
Writes an endtag.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
const EXPORT_ID_INVALID
const EXPORT_ID_ILIAS_REMOTE_INVALID
createObjectExportId(string $a_type, string $a_id)
Build ilias export id.
ilDBInterface $db
const EXPORT_ID_ILIAS_LOCAL
getSupportedVersions()
getXmlRepresentation(string $a_entity, string $a_schema_version, ?array $a_ids, string $a_field="", bool $a_omit_header=false, bool $a_omit_types=false)
Get xml representation <dataset install_id="123" install_url="..."> <types entity="table_name" versio...
ILIAS ResourceStorage Services $irss
importRecord(string $a_entity, array $a_types, array $a_rec, ilImportMapping $a_mapping, string $a_schema_version)
Needs to be overwritten for import use case.
global $DIC
Definition: shib_login.php:26
ilExport $export
afterXmlRecordWriting(string $a_entity, string $a_version, array $a_set)
const DATASET_NS
getCurrentInstallationId()
getDependencies(string $a_entity, string $a_version, ?array $a_rec=null, ?array $a_ids=null)
addTypesXml(ilXmlWriter $a_writer, string $a_entity, string $a_schema_version)
getXMLEntityTag(string $a_entity, string $a_schema_version)
Get entity tag.
getDirectDataFromQuery(string $a_query, bool $a_convert_to_leading_upper=true, bool $a_set=true)
Get data from query.This is a standard procedure, all db field names are directly mapped to abstract ...
ilSurveyImporter $import
string $version
getTypes(string $a_entity, string $a_version)
Get (abstract) types for (abstract) field names.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
setImport(ilSurveyImporter $a_val)
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
string $entity
string $current_installation_id
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
stripTags(array $rec, array $omit_keys=[])
static _lookupType(int $id, bool $reference=false)
setDSPrefix(string $a_val)
string $component_export_dir