ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
LinkManager.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21namespace 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 {
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];
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");
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"] ?? "";
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
380 // replace link by the content of the link
381 $source_node = $node;
382 while ($source_node->firstChild) {
383 $source_node->parentNode->insertBefore($source_node->firstChild, $source_node);
384 }
385 $source_node->parentNode->removeChild($source_node);
386
387 /*
388 $source_node = $node;
389 $new_node = $source_node->cloneNode(true);
390 //$new_node->parentNode->removeChild($new_node);
391 foreach ($new_node->childNodes as $child) {
392 //$this->log->debug("... move node $j " . $child->node_name() . " before " . $source_node->node_name());
393 $source_node->parentNode->insertBefore($child, $source_node);
394 }
395 $source_node->parentNode->removeChild($source_node);*/
396 }
397 }
398 }
399 }
400
401 // resolve normal external links
402 $ilias_url = parse_url(ILIAS_HTTP_PATH);
403 $path = "//ExtLink";
404 $nodes = $this->dom_util->path($dom, $path);
405 foreach ($nodes as $node) {
406 $href = $node->getAttribute("Href");
407
408 $this->log->debug("Href: " . $href);
409 $ref_id = $ext_link_mapper->getRefId($href);
410 $this->log->debug("Ref Id: " . $ref_id);
411
412 if ($ref_id > 0) {
413 $new_href = $ext_link_mapper->getNewHref($ref_id);
414 $this->log->debug("New ref id: " . $new_href);
415 if ($new_href !== "") {
416 $node->setAttribute("Href", $new_href);
417 } elseif ($tree->isGrandChild($a_source_ref_id, $ref_id)) {
418 // we have no mapping, but the linked object is child of the original node -> remove link
419 //$this->log->debug("... remove ext links.");
420 if ($node->parentNode->nodeName == "MapArea") { // simply remove map areas
421 $parent = $node->parentNode;
422 $parent->parentNode->removeChild($parent);
423 } else { // replace link by content of the link for other internal links
424 $source_node = $node;
425 $new_node = $source_node->cloneNode(true);
426 //$new_node->unlink_node($new_node);
427 foreach ($new_node->childNodes as $child) {
428 //$this->log->debug("... move node $j " . $childs[$j]->node_name() . " before " . $source_node->node_name());
429 $source_node->parentNode->insertBefore($child, $source_node);
430 }
431 $source_node->parentNode->removeChild($source_node);
432 }
433 }
434 }
435 }
436 }
437
441 public function deleteInternalLinks(
442 \ilPageObject $page
443 ): void {
444 \ilInternalLink::_deleteAllLinksOfSource(
445 $page->getParentType() . ":pg",
446 $page->getId(),
447 $page->getLanguage()
448 );
449 }
450
451
455 public function saveInternalLinks(
456 \ilPageObject $page,
457 \DOMDocument $a_domdoc,
458 ): void {
459 $this->deleteInternalLinks(
460 $page
461 );
462 $t_type = "";
463 // query IntLink elements
464 $xpath = new \DOMXPath($a_domdoc);
465 $nodes = $xpath->query('//IntLink');
466 foreach ($nodes as $node) {
467 $link_type = $node->getAttribute("Type");
468
469 switch ($link_type) {
470 case "StructureObject":
471 $t_type = "st";
472 break;
473
474 case "PageObject":
475 $t_type = "pg";
476 break;
477
478 case "GlossaryItem":
479 $t_type = "git";
480 break;
481
482 case "MediaObject":
483 $t_type = "mob";
484 break;
485
486 case "RepositoryItem":
487 $t_type = "obj";
488 break;
489
490 case "File":
491 $t_type = "file";
492 break;
493
494 case "WikiPage":
495 $t_type = "wpage";
496 break;
497
498 case "PortfolioPage":
499 $t_type = "ppage";
500 break;
501
502 case "User":
503 $t_type = "user";
504 break;
505 }
506
507 $target = $node->getAttribute("Target");
508 $target_arr = explode("_", $target);
509 $t_id = (int) $target_arr[count($target_arr) - 1];
510
511 // link to other internal object
512 if (is_int(strpos($target, "__"))) {
513 $t_inst = 0;
514 } else { // link to unresolved object in other installation
515 $t_inst = (int) ($target_arr[1] ?? 0);
516 }
517
518 if ($t_id > 0) {
520 $page->getParentType() . ":pg",
521 $page->getId(),
522 $t_type,
523 $t_id,
524 $t_inst,
525 $page->getLanguage()
526 );
527 }
528 }
529 }
530}
$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.
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
Class ilPageObject Handles PageObjects of ILIAS Learning Modules (see ILIAS DTD)
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
isGrandChild(int $a_startnode_id, int $a_querynode_id)
checks if a node is in the path of an other node
const IL_INST_ID
Definition: constants.php:40
$ref_id
Definition: ltiauth.php:66
$path
Definition: ltiservices.php:30
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
getLanguage()