ILIAS  trunk Revision v11.0_alpha-1744-gb0451eebef4
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
LinkManager.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 namespace ILIAS\COPage\Link;
22 
27 {
28  protected ?\ilLogger $log;
29  protected \ILIAS\COPage\Dom\DomUtil $dom_util;
30  protected \ilObjectDefinition $obj_definition;
31 
32  public function __construct()
33  {
34  global $DIC;
35 
36  $this->dom_util = $DIC->copage()->internal()->domain()->domUtil();
37  $this->obj_definition = $DIC["objDefinition"];
38  $this->log = $DIC->copage()->internal()->domain()->log();
39  }
40 
41  protected function getDefaultMediaCollector(): \Closure
42  {
43  return fn(int $id) => \ilMediaItem::_getMapAreasIntLinks($id);
44  }
45 
46  public function getInternalLinks(
47  \DOMDocument $dom,
48  ?\Closure $media_collector = null
49  ): array {
50  if (is_null($media_collector)) {
51  $media_collector = $this->getDefaultMediaCollector();
52  }
53  // get all internal links of the page
54  $path = "//IntLink";
55  $links = array();
56  $cnt_multiple = 1;
57  $nodes = $this->dom_util->path($dom, $path);
58  foreach ($nodes as $node) {
59  $target = $node->getAttribute("Target");
60  $type = $node->getAttribute("Type");
61  $targetframe = $node->getAttribute("TargetFrame");
62  $anchor = $node->getAttribute("Anchor");
63  $links[$target . ":" . $type . ":" . $targetframe . ":" . $anchor] =
64  array("Target" => $target,
65  "Type" => $type,
66  "TargetFrame" => $targetframe,
67  "Anchor" => $anchor
68  );
69 
70  // get links (image map areas) for inline media objects
71  if ($type == "MediaObject" && $targetframe == "") {
72  if (substr($target, 0, 4) == "il__") {
73  $id_arr = explode("_", $target);
74  $id = $id_arr[count($id_arr) - 1];
75 
76  $med_links = $media_collector((int) $id);
77  // \ilMediaItem::_getMapAreasIntLinks($id);
78  foreach ($med_links as $key => $med_link) {
79  $links[$key] = $med_link;
80  }
81  }
82  }
83  }
84 
85  // get all media aliases
86  $path = "//MediaAlias";
87  $nodes = $this->dom_util->path($dom, $path);
88  foreach ($nodes as $node) {
89  $oid = $node->getAttribute("OriginId");
90  if (substr($oid, 0, 4) == "il__") {
91  $id_arr = explode("_", $oid);
92  $id = $id_arr[count($id_arr) - 1];
93 
94  $med_links = $media_collector((int) $id);
95  foreach ($med_links as $key => $med_link) {
96  $links[$key] = $med_link;
97  }
98  }
99  }
100 
101  return $links;
102  }
103 
104 
105  public function containsFileLinkId(\DOMDocument $dom, string $file_link_id): bool
106  {
107  $int_links = $this->getInternalLinks(
108  $dom,
109  function (int $id): array {
110  return [];
111  }
112  );
113  foreach ($int_links as $il) {
114  if ($il["Target"] == str_replace("_file_", "_dfile_", $file_link_id)) {
115  return true;
116  }
117  }
118  return false;
119  }
120 
121  public function extractFileFromLinkId(string $file_link_id): int
122  {
123  $file = explode("_", $file_link_id);
124  return (int) $file[count($file) - 1];
125  }
126 
131  public function resolveIntLinks(
132  \DOMDocument $dom,
133  ?array $a_link_map = null
134  ): bool {
135  $changed = false;
136  // resolve normal internal links
137  $path = "//IntLink";
138  $nodes = $this->dom_util->path($dom, $path);
139  foreach ($nodes as $node) {
140  $target = $node->getAttribute("Target");
141  $type = $node->getAttribute("Type");
142 
143  if ($a_link_map === null) {
144  $new_target = \ilInternalLink::_getIdForImportId($type, $target);
145  //$this->log->debug("no map, type: " . $type . ", target: " . $target . ", new target: " . $new_target);
146  } else {
147  $nt = explode("_", $a_link_map[$target] ?? "");
148  $new_target = false;
149  if (($nt[1] ?? "") == IL_INST_ID) {
150  $new_target = "il__" . $nt[2] . "_" . $nt[3];
151  }
152  //$this->log->debug("map, type: " . $type . ", target: " . $target . ", new target: " . $new_target);
153  }
154  if ($new_target !== false && !is_null($new_target)) {
155  $node->setAttribute("Target", $new_target);
156  $changed = true;
157  } else { // check wether link target is same installation
159  IL_INST_ID > 0 && $type != "RepositoryItem") {
160  $new_target = \ilInternalLink::_removeInstFromTarget($target);
161  if (\ilInternalLink::_exists($type, $new_target)) {
162  $node->setAttribute("Target", $new_target);
163  $changed = true;
164  }
165  }
166  }
167  }
168 
169  // resolve internal links in map areas
170  $path = "//MediaAlias";
171  $nodes = $this->dom_util->path($dom, $path);
172  foreach ($nodes as $node) {
173  $orig_id = $node->getAttribute("OriginId");
174  $id_arr = explode("_", $orig_id);
175  $mob_id = $id_arr[count($id_arr) - 1];
176  \ilMediaItem::_resolveMapAreaLinks((int) $mob_id);
177  }
178  return $changed;
179  }
180 
181  protected function getDefaultLMTypeLookuper(): \Closure
182  {
183  return fn(int $id) => \ilLMObject::_lookupType($id);
184  }
185 
190  public function moveIntLinks(
191  \DOMDocument $dom,
192  array $a_from_to,
193  ?\Closure $lm_type_lookup = null
194  ): bool {
195  if (is_null($lm_type_lookup)) {
196  $lm_type_lookup = $this->getDefaultLMTypeLookuper();
197  }
198 
199  $changed = false;
200 
201  // resolve normal internal links
202  $path = "//IntLink";
203  $nodes = $this->dom_util->path($dom, $path);
204  foreach ($nodes as $node) {
205  $target = $node->getAttribute("Target");
206  $type = $node->getAttribute("Type");
207  $obj_id = \ilInternalLink::_extractObjIdOfTarget($target);
208  if (($a_from_to[$obj_id] ?? 0) > 0 && is_int(strpos($target, "__"))) {
209  if ($type == "PageObject" && $lm_type_lookup($a_from_to[$obj_id]) == "pg") {
210  $node->setAttribute("Target", "il__pg_" . $a_from_to[$obj_id]);
211  $changed = true;
212  }
213  if ($type == "StructureObject" && $lm_type_lookup($a_from_to[$obj_id]) == "st") {
214  $node->setAttribute("Target", "il__st_" . $a_from_to[$obj_id]);
215  $changed = true;
216  }
217  if ($type == "PortfolioPage") {
218  $node->setAttribute("Target", "il__ppage_" . $a_from_to[$obj_id]);
219  $changed = true;
220  }
221  if ($type == "WikiPage") {
222  $node->setAttribute("Target", "il__wpage_" . $a_from_to[$obj_id]);
223  $changed = true;
224  }
225  }
226  }
227 
228  // map areas
229  $path = "//MediaAlias";
230  $nodes = $this->dom_util->path($dom, $path);
231  foreach ($nodes as $node) {
232  $media_object_node = $node->parentNode;
233  $page_content_node = $media_object_node->parentNode;
234  $c_hier_id = $page_content_node->getAttribute("HierId");
235 
236  // first check, wheter we got instance map areas -> take these
237  $std_alias_item = new \ilMediaAliasItem(
238  $dom,
239  $c_hier_id,
240  "Standard"
241  );
242  $areas = $std_alias_item->getMapAreas();
243  $correction_needed = false;
244  if (count($areas) > 0) {
245  // check if correction needed
246  foreach ($areas as $area) {
247  if ($area["Type"] == "PageObject" ||
248  $area["Type"] == "StructureObject") {
249  $t = $area["Target"];
251  if ($a_from_to[$tid] > 0) {
252  $correction_needed = true;
253  }
254  }
255  }
256  } else {
257  $areas = array();
258 
259  // get object map areas and check whether at least one must
260  // be corrected
261  $oid = $node->getAttribute("OriginId");
262  if (substr($oid, 0, 4) == "il__") {
263  $id_arr = explode("_", $oid);
264  $id = $id_arr[count($id_arr) - 1];
265 
266  $mob = new \ilObjMediaObject((int) $id);
267  $med_item = $mob->getMediaItem("Standard");
268  $med_areas = $med_item->getMapAreas();
269 
270  foreach ($med_areas as $area) {
271  $link_type = ($area->getLinkType() == "int")
272  ? "IntLink"
273  : "ExtLink";
274 
275  $areas[] = array(
276  "Nr" => $area->getNr(),
277  "Shape" => $area->getShape(),
278  "Coords" => $area->getCoords(),
279  "Link" => array(
280  "LinkType" => $link_type,
281  "Href" => $area->getHref(),
282  "Title" => $area->getTitle(),
283  "Target" => $area->getTarget(),
284  "Type" => $area->getType(),
285  "TargetFrame" => $area->getTargetFrame()
286  )
287  );
288 
289  if ($area->getType() == "PageObject" ||
290  $area->getType() == "StructureObject") {
291  $t = $area->getTarget();
293  if ($a_from_to[$tid] > 0) {
294  $correction_needed = true;
295  }
296  //var_dump($a_from_to);
297  }
298  }
299  }
300  }
301 
302  // correct map area links
303  if ($correction_needed) {
304  $changed = true;
305  $std_alias_item->deleteAllMapAreas();
306  foreach ($areas as $area) {
307  if ($area["Link"]["LinkType"] == "IntLink") {
308  $target = $area["Link"]["Target"];
309  $type = $area["Link"]["Type"];
310  $obj_id = \ilInternalLink::_extractObjIdOfTarget($target);
311  if ($a_from_to[$obj_id] > 0) {
312  if ($type == "PageObject" && $lm_type_lookup($a_from_to[$obj_id]) == "pg") {
313  $area["Link"]["Target"] = "il__pg_" . $a_from_to[$obj_id];
314  }
315  if ($type == "StructureObject" && $lm_type_lookup($a_from_to[$obj_id]) == "st") {
316  $area["Link"]["Target"] = "il__st_" . $a_from_to[$obj_id];
317  }
318  }
319  }
320 
321  $std_alias_item->addMapArea(
322  $area["Shape"],
323  $area["Coords"],
324  $area["Link"]["Title"],
325  array("Type" => $area["Link"]["Type"],
326  "TargetFrame" => $area["Link"]["TargetFrame"],
327  "Target" => $area["Link"]["Target"],
328  "Href" => $area["Link"]["Href"],
329  "LinkType" => $area["Link"]["LinkType"],
330  )
331  );
332  }
333  }
334  }
335  return $changed;
336  }
337 
342  \DOMDocument $dom,
343  array $a_mapping,
344  int $a_source_ref_id,
345  \ilTree $tree
346  ): void {
347  $type = "";
348  $objDefinition = $this->obj_definition;
349  $ext_link_mapper = new ExtLinkMapper(
350  $this->obj_definition,
351  ILIAS_HTTP_PATH,
352  $a_mapping
353  );
354 
355 
356  // resolve normal internal links
357  $path = "//IntLink";
358  $nodes = $this->dom_util->path($dom, $path);
359  foreach ($nodes as $node) {
360  $target = $node->getAttribute("Target");
361  $type = $node->getAttribute("Type");
362  //$this->log->debug("Target: " . $target);
363  $t = explode("_", $target);
364  if ($type == "RepositoryItem" && ((int) $t[1] == 0 || (int) $t[1] == IL_INST_ID)) {
365  if (isset($a_mapping[$t[3]])) {
366  // we have a mapping -> replace the ID
367  //$this->log->debug("... replace " . $t[3] . " with " . $a_mapping[$t[3]] . ".");
368  $node->setAttribute(
369  "Target",
370  "il__obj_" . $a_mapping[$t[3]]
371  );
372  } elseif ($tree->isGrandChild($a_source_ref_id, (int) $t[3])) {
373  // we have no mapping, but the linked object is child of the original node -> remove link
374  //$this->log->debug("... remove links.");
375  if ($node->parentNode->nodeName === "MapArea") { // simply remove map areas
376  $parent = $node->parentNode;
377  $parent->parentNode->removeChild($parent);
378  } else { // replace link by content of the link for other internal links
379  $source_node = $node;
380  $new_node = $source_node->cloneNode(true);
381  //$new_node->parentNode->removeChild($new_node);
382  $childs = $new_node->child_nodes();
383  foreach ($new_node->childNodes as $child) {
384  //$this->log->debug("... move node $j " . $child->node_name() . " before " . $source_node->node_name());
385  $source_node->parentNode->insertBefore($child, $source_node);
386  }
387  $source_node->parentNode->removeChild($source_node);
388  }
389  }
390  }
391  }
392 
393  // resolve normal external links
394  $ilias_url = parse_url(ILIAS_HTTP_PATH);
395  $path = "//ExtLink";
396  $nodes = $this->dom_util->path($dom, $path);
397  foreach ($nodes as $node) {
398  $href = $node->getAttribute("Href");
399 
400  $this->log->debug("Href: " . $href);
401  $ref_id = $ext_link_mapper->getRefId($href);
402  $this->log->debug("Ref Id: " . $ref_id);
403 
404  if ($ref_id > 0) {
405  $new_href = $ext_link_mapper->getNewHref($ref_id);
406  $this->log->debug("New ref id: " . $new_href);
407  if ($new_href !== "") {
408  $node->setAttribute("Href", $new_href);
409  } elseif ($tree->isGrandChild($a_source_ref_id, $ref_id)) {
410  // we have no mapping, but the linked object is child of the original node -> remove link
411  //$this->log->debug("... remove ext links.");
412  if ($node->parentNode->nodeName == "MapArea") { // simply remove map areas
413  $parent = $node->parentNode;
414  $parent->parentNode->removeChild($parent);
415  } else { // replace link by content of the link for other internal links
416  $source_node = $node;
417  $new_node = $source_node->cloneNode(true);
418  //$new_node->unlink_node($new_node);
419  foreach ($new_node->childNodes as $child) {
420  //$this->log->debug("... move node $j " . $childs[$j]->node_name() . " before " . $source_node->node_name());
421  $source_node->parentNode->insertBefore($child, $source_node);
422  }
423  $source_node->parentNode->removeChild($source_node);
424  }
425  }
426  }
427  }
428  }
429 
433  public function deleteInternalLinks(
434  \ilPageObject $page
435  ): void {
437  $page->getParentType() . ":pg",
438  $page->getId(),
439  $page->getLanguage()
440  );
441  }
442 
443 
447  public function saveInternalLinks(
448  \ilPageObject $page,
449  \DOMDocument $a_domdoc,
450  ): void {
451  $this->deleteInternalLinks(
452  $page
453  );
454  $t_type = "";
455  // query IntLink elements
456  $xpath = new \DOMXPath($a_domdoc);
457  $nodes = $xpath->query('//IntLink');
458  foreach ($nodes as $node) {
459  $link_type = $node->getAttribute("Type");
460 
461  switch ($link_type) {
462  case "StructureObject":
463  $t_type = "st";
464  break;
465 
466  case "PageObject":
467  $t_type = "pg";
468  break;
469 
470  case "GlossaryItem":
471  $t_type = "git";
472  break;
473 
474  case "MediaObject":
475  $t_type = "mob";
476  break;
477 
478  case "RepositoryItem":
479  $t_type = "obj";
480  break;
481 
482  case "File":
483  $t_type = "file";
484  break;
485 
486  case "WikiPage":
487  $t_type = "wpage";
488  break;
489 
490  case "PortfolioPage":
491  $t_type = "ppage";
492  break;
493 
494  case "User":
495  $t_type = "user";
496  break;
497  }
498 
499  $target = $node->getAttribute("Target");
500  $target_arr = explode("_", $target);
501  $t_id = (int) $target_arr[count($target_arr) - 1];
502 
503  // link to other internal object
504  if (is_int(strpos($target, "__"))) {
505  $t_inst = 0;
506  } else { // link to unresolved object in other installation
507  $t_inst = (int) ($target_arr[1] ?? 0);
508  }
509 
510  if ($t_id > 0) {
512  $page->getParentType() . ":pg",
513  $page->getId(),
514  $t_type,
515  $t_id,
516  $t_inst,
517  $page->getLanguage()
518  );
519  }
520  }
521  }
522 }
const IL_INST_ID
Definition: constants.php:40
$path
Definition: ltiservices.php:29
isGrandChild(int $a_startnode_id, int $a_querynode_id)
checks if a node is in the path of an other node
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
$ref_id
Definition: ltiauth.php:65
Class ilPageObject Handles PageObjects of ILIAS Learning Modules (see ILIAS DTD)
global $DIC
Definition: shib_login.php:22
static _getMapAreasIntLinks(int $a_mob_id)
get all internal links of map areas of a mob
static _resolveMapAreaLinks(int $a_mob_id)
resolve internal links of all media items of a media object
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static _lookupType(int $a_obj_id, int $a_lm_id=0)
Component logger with individual log levels by component id.