ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilPageObject.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 define("IL_INSERT_BEFORE", 0);
5 define("IL_INSERT_AFTER", 1);
6 define("IL_INSERT_CHILD", 2);
7 
8 define ("IL_CHAPTER_TITLE", "st_title");
9 define ("IL_PAGE_TITLE", "pg_title");
10 define ("IL_NO_HEADER", "none");
11 
15 /*
16  @todo 1
17 
18  - All PC types could be defined in service/module xml. (done)
19  -- type, class, directory (done)
20  -- internal links used/implemented?
21  -- styles used/implemented?
22  - application classes need
23  -- page object
24  --- page object should return php5 domdoc (getDom() vs getDomDoc()?)
25  esp. plugins should use this
26  -- remove content element hook, if content is not allowed
27  - PC types could move to components (e.g. blog, login)
28  - Problem: How to modularize xsl?
29  -- read from db?
30  -- xml entries say that xslt code is used -> read file and include in
31  main xslt file
32 
33 */
34 
46 abstract class ilPageObject
47 {
48  static $exists = array();
49 
50  var $id;
51  var $ilias;
52  var $dom;
53  var $xml;
54  var $encoding;
55  var $node;
56  var $cur_dtd = "ilias_pg_4_4.dtd";
66  var $language = "-";
67  static protected $activation_data = array();
68 
73  final public function ilPageObject($a_id = 0, $a_old_nr = 0, $a_lang = "-")
74  {
75  global $ilias;
76 
77  // @todo: move this elsewhere
78  require_once("./Services/COPage/syntax_highlight/php/Beautifier/Init.php");
79  require_once("./Services/COPage/syntax_highlight/php/Output/Output_css.php");
80 
81  $this->parent_type = $this->getParentType();
82  $this->id = $a_id;
83  $this->ilias =& $ilias;
84  $this->setLanguage($a_lang);
85 
86  $this->contains_int_link = false;
87  $this->needs_parsing = false;
88  $this->update_listeners = array();
89  $this->update_listener_cnt = 0;
90  $this->dom_builded = false;
91  $this->page_not_found = false;
92  $this->old_nr = $a_old_nr;
93  $this->encoding = "UTF-8";
94  $this->id_elements =
95  array("PageContent", "TableRow", "TableData", "ListItem", "FileItem",
96  "Section", "Tab", "ContentPopup");
97  $this->setActive(true);
98 
99  if($a_id != 0)
100  {
101  $this->read();
102  }
103 
104  $this->initPageConfig();
105 
106  $this->afterConstructor();
107  }
108 
115  function afterConstructor()
116  {
117 
118  }
119 
120 
126  abstract function getParentType();
127 
133  final function initPageConfig()
134  {
135  include_once("./Services/COPage/classes/class.ilPageObjectFactory.php");
137  $this->setPageConfig($cfg);
138  }
139 
145  function setLanguage($a_val)
146  {
147  $this->language = $a_val;
148  }
149 
155  function getLanguage()
156  {
157  return $this->language;
158  }
159 
165  function setPageConfig($a_val)
166  {
167  $this->page_config = $a_val;
168  }
169 
175  function getPageConfig()
176  {
177  return $this->page_config;
178  }
179 
185  function setRenderMd5($a_rendermd5)
186  {
187  $this->rendermd5 = $a_rendermd5;
188  }
189 
195  function getRenderMd5()
196  {
197  return $this->rendermd5;
198  }
199 
205  function setRenderedContent($a_renderedcontent)
206  {
207  $this->renderedcontent = $a_renderedcontent;
208  }
209 
216  {
217  return $this->renderedcontent;
218  }
219 
225  function setRenderedTime($a_renderedtime)
226  {
227  $this->renderedtime = $a_renderedtime;
228  }
229 
235  function getRenderedTime()
236  {
237  return $this->renderedtime;
238  }
239 
245  function setLastChange($a_lastchange)
246  {
247  $this->lastchange = $a_lastchange;
248  }
249 
255  function getLastChange()
256  {
257  return $this->lastchange;
258  }
259 
265  public function setLastChangeUser($a_val)
266  {
267  $this->last_change_user = $a_val;
268  }
269 
275  public function getLastChangeUser()
276  {
277  return $this->last_change_user;
278  }
279 
285  function setShowActivationInfo($a_val)
286  {
287  $this->show_page_act_info = $a_val;
288  }
289 
296  {
297  return $this->show_page_act_info;
298  }
299 
303  function read()
304  {
305  global $ilDB;
306 
307  $this->setActive(true);
308  if ($this->old_nr == 0)
309  {
310  $query = "SELECT * FROM page_object".
311  " WHERE page_id = ".$ilDB->quote($this->id, "integer").
312  " AND parent_type=".$ilDB->quote($this->getParentType(), "text").
313  " AND lang = ".$ilDB->quote($this->getLanguage(), "text");
314  $pg_set = $this->ilias->db->query($query);
315  $this->page_record = $ilDB->fetchAssoc($pg_set);
316  $this->setActive($this->page_record["active"]);
317  $this->setActivationStart($this->page_record["activation_start"]);
318  $this->setActivationEnd($this->page_record["activation_end"]);
319  $this->setShowActivationInfo($this->page_record["show_activation_info"]);
320  }
321  else
322  {
323  $query = "SELECT * FROM page_history".
324  " WHERE page_id = ".$ilDB->quote($this->id, "integer").
325  " AND parent_type=".$ilDB->quote($this->getParentType(), "text").
326  " AND nr = ".$ilDB->quote((int) $this->old_nr, "integer").
327  " AND lang = ".$ilDB->quote($this->getLanguage(), "text");
328  $pg_set = $ilDB->query($query);
329  $this->page_record = $ilDB->fetchAssoc($pg_set);
330  }
331  if (!$this->page_record)
332  {
333  include_once("./Services/COPage/exceptions/class.ilCOPageNotFoundException.php");
334  throw new ilCOPageNotFoundException("Error: Page ".$this->id." is not in database".
335  " (parent type ".$this->getParentType().").");
336  }
337 
338  $this->xml = $this->page_record["content"];
339  $this->setParentId($this->page_record["parent_id"]);
340  $this->last_change_user = $this->page_record["last_change_user"];
341  $this->create_user = $this->page_record["create_user"];
342  $this->setRenderedContent($this->page_record["rendered_content"]);
343  $this->setRenderMd5($this->page_record["render_md5"]);
344  $this->setRenderedTime($this->page_record["rendered_time"]);
345  $this->setLastChange($this->page_record["last_change"]);
346 
347  }
348 
356  static function _exists($a_parent_type, $a_id, $a_lang = "")
357  {
358  global $ilDB;
359  if (isset(self::$exists[$a_parent_type.":".$a_id.":".$a_lang]))
360  {
361  return self::$exists[$a_parent_type.":".$a_id.":".$a_lang];
362  }
363 
364  $and_lang = "";
365  if ($a_lang != "")
366  {
367  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
368  }
369 
370  $query = "SELECT page_id FROM page_object WHERE page_id = ".$ilDB->quote($a_id, "integer")." ".
371  "AND parent_type = ".$ilDB->quote($a_parent_type, "text").$and_lang;
372  $set = $ilDB->query($query);
373  if ($row = $ilDB->fetchAssoc($set))
374  {
375  self::$exists[$a_parent_type.":".$a_id.":".$a_lang] = true;
376  return true;
377  }
378  else
379  {
380  self::$exists[$a_parent_type.":".$a_id.":".$a_lang] = false;
381  return false;
382  }
383  }
384 
392  static function _existsAndNotEmpty($a_parent_type, $a_id, $a_lang = "-")
393  {
394  global $ilDB;
395 
396  include_once("./Services/COPage/classes/class.ilPageUtil.php");
397 
398  return ilPageUtil::_existsAndNotEmpty($a_parent_type, $a_id, $a_lang);
399  }
400 
401  function buildDom($a_force = false)
402  {
403  if ($this->dom_builded && !$a_force)
404  {
405  return;
406  }
407 
408 //echo "\n<br>buildDomWith:".$this->getId().":xml:".$this->getXMLContent(true).":<br>";
409 
410  $this->dom = @domxml_open_mem($this->getXMLContent(true), DOMXML_LOAD_VALIDATING, $error);
411 
412  $xpc = xpath_new_context($this->dom);
413  $path = "//PageObject";
414  $res =& xpath_eval($xpc, $path);
415  if (count($res->nodeset) == 1)
416  {
417  $this->node =& $res->nodeset[0];
418  }
419 
420  if (empty($error))
421  {
422  $this->dom_builded = true;
423  return true;
424  }
425  else
426  {
427  return $error;
428  }
429  }
430 
431  function freeDom()
432  {
433  //$this->dom->free();
434  unset($this->dom);
435  }
436 
440  function getDom()
441  {
442  return $this->dom;
443  }
444 
451  function getDomDoc()
452  {
453  if ($this->dom instanceof php4DOMDocument)
454  {
455  return $this->dom->myDOMDocument;
456  }
457 
458  return $this->dom;
459  }
460 
461 
465  function setId($a_id)
466  {
467  $this->id = $a_id;
468  }
469 
470  function getId()
471  {
472  return $this->id;
473  }
474 
475  function setParentId($a_id)
476  {
477  $this->parent_id = $a_id;
478  }
479 
480  function getParentId()
481  {
482  return $this->parent_id;
483  }
484 
485  function addUpdateListener(&$a_object, $a_method, $a_parameters = "")
486  {
488  $this->update_listeners[$cnt]["object"] =& $a_object;
489  $this->update_listeners[$cnt]["method"] = $a_method;
490  $this->update_listeners[$cnt]["parameters"] = $a_parameters;
491  $this->update_listener_cnt++;
492  }
493 
495  {
496  for($i=0; $i<$this->update_listener_cnt; $i++)
497  {
498  $object =& $this->update_listeners[$i]["object"];
499  $method = $this->update_listeners[$i]["method"];
500  $parameters = $this->update_listeners[$i]["parameters"];
501  $object->$method($parameters);
502  }
503  }
504 
510  function setActive($a_active)
511  {
512  $this->active = $a_active;
513  }
514 
520  function getActive($a_check_scheduled_activation = false)
521  {
522  if ($a_check_scheduled_activation && !$this->active)
523  {
524  include_once("./Services/Calendar/classes/class.ilDateTime.php");
525  $start = new ilDateTime($this->getActivationStart(), IL_CAL_DATETIME);
526  $end = new ilDateTime($this->getActivationEnd(), IL_CAL_DATETIME);
527  $now = new ilDateTime(time(), IL_CAL_UNIX);
528  if (!ilDateTime::_before($now, $start) && !ilDateTime::_after($now, $end))
529  {
530  return true;
531  }
532  }
533  return $this->active;
534  }
535 
541  static function preloadActivationDataByParentId($a_parent_id)
542  {
543  global $ilDB;
544 
545  $set = $ilDB->query("SELECT page_id, parent_type, lang, active, activation_start, activation_end, show_activation_info FROM page_object ".
546  " WHERE parent_id = ".$ilDB->quote($a_parent_id, "integer")
547  );
548  while ($rec = $ilDB->fetchAssoc($set))
549  {
550  self::$activation_data[$rec["page_id"].":".$rec["parent_type"].":".$rec["lang"]] = $rec;
551  }
552  }
553 
554 
558  static function _lookupActive($a_id, $a_parent_type, $a_check_scheduled_activation = false, $a_lang = "-")
559  {
560  global $ilDB;
561 
562  // language must be set at least to "-"
563  if ($a_lang == "")
564  {
565  $a_lang = "-";
566  }
567 
568  if (isset(self::$activation_data[$a_id.":".$a_parent_type.":".$a_lang]))
569  {
570  $rec = self::$activation_data[$a_id.":".$a_parent_type.":".$a_lang];
571  }
572  else
573  {
574  $set = $ilDB->queryF("SELECT active, activation_start, activation_end FROM page_object WHERE page_id = %s".
575  " AND parent_type = %s AND lang = %s",
576  array("integer", "text", "text"),
577  array($a_id, $a_parent_type, $a_lang));
578  $rec = $ilDB->fetchAssoc($set);
579  }
580 
581 
582  $rec["n"] = ilUtil::now();
583 
584  if (!$rec["active"] && $a_check_scheduled_activation)
585  {
586  if ($rec["n"] >= $rec["activation_start"] &&
587  $rec["n"] <= $rec["activation_end"])
588  {
589  return true;
590  }
591  }
592 
593  return $rec["active"];
594  }
595 
599  static function _isScheduledActivation($a_id, $a_parent_type, $a_lang = "-")
600  {
601  global $ilDB;
602 
603  // language must be set at least to "-"
604  if ($a_lang == "")
605  {
606  $a_lang = "-";
607  }
608 
609 //echo "<br>";
610 //var_dump(self::$activation_data); exit;
611  if (isset(self::$activation_data[$a_id.":".$a_parent_type.":".$a_lang]))
612  {
613  $rec = self::$activation_data[$a_id.":".$a_parent_type.":".$a_lang];
614  }
615  else
616  {
617  $set = $ilDB->queryF("SELECT active, activation_start, activation_end FROM page_object WHERE page_id = %s".
618  " AND parent_type = %s AND lang = %s", array("integer", "text", "text"),
619  array($a_id, $a_parent_type, $a_lang));
620  $rec = $ilDB->fetchAssoc($set);
621  }
622 
623  if (!$rec["active"] && $rec["activation_start"] != "")
624  {
625  return true;
626  }
627 
628  return false;
629  }
630 
634  function _writeActive($a_id, $a_parent_type, $a_active, $a_reset_scheduled_activation = true, $a_lang = "-")
635  {
636  global $ilDB;
637 
638  // language must be set at least to "-"
639  if ($a_lang == "")
640  {
641  $a_lang = "-";
642  }
643 
644  if ($a_reset_scheduled_activation)
645  {
646  $st = $ilDB->manipulateF("UPDATE page_object SET active = %s, activation_start = %s, ".
647  " activation_end = %s WHERE page_id = %s".
648  " AND parent_type = %s AND lang = %s", array("boolean", "timestamp", "timestamp", "integer", "text", "text"),
649  array($a_active, null, null, $a_id, $a_parent_type, $a_lang));
650  }
651  else
652  {
653  $st = $ilDB->prepareManip("UPDATE page_object SET active = %s WHERE page_id = %s".
654  " AND parent_type = %s AND lang = %s", array("boolean", "integer", "text", "text"),
655  array($a_active, $a_id, $a_parent_type, $a_lang));
656  }
657  }
658 
662  function _lookupActivationData($a_id, $a_parent_type, $a_lang = "-")
663  {
664  global $ilDB;
665 
666  // language must be set at least to "-"
667  if ($a_lang == "")
668  {
669  $a_lang = "-";
670  }
671 
672  if (isset(self::$activation_data[$a_id.":".$a_parent_type.":".$a_lang]))
673  {
674  $rec = self::$activation_data[$a_id.":".$a_parent_type.":".$a_lang];
675  }
676  else
677  {
678  $set = $ilDB->queryF("SELECT active, activation_start, activation_end, show_activation_info FROM page_object WHERE page_id = %s".
679  " AND parent_type = %s AND lang = %s",
680  array("integer", "text", "text"),
681  array($a_id, $a_parent_type, $a_lang));
682  $rec = $ilDB->fetchAssoc($set);
683  }
684 
685  return $rec;
686  }
687 
688 
692  static function lookupParentId($a_id, $a_type)
693  {
694  global $ilDB;
695 
696  $res = $ilDB->query("SELECT parent_id FROM page_object WHERE page_id = ".$ilDB->quote($a_id, "integer")." ".
697  "AND parent_type=".$ilDB->quote($a_type, "text"));
698  $rec = $ilDB->fetchAssoc($res);
699  return $rec["parent_id"];
700  }
701 
705  function _writeParentId($a_parent_type, $a_pg_id, $a_par_id)
706  {
707  global $ilDB;
708 
709  $st = $ilDB->manipulateF("UPDATE page_object SET parent_id = %s WHERE page_id = %s".
710  " AND parent_type = %s", array("integer", "integer", "text"),
711  array($a_par_id, $a_pg_id, $a_parent_type));
712  }
713 
719  function setActivationStart($a_activationstart)
720  {
721  $this->activationstart = $a_activationstart;
722  }
723 
730  {
731  return $this->activationstart;
732  }
733 
739  function setActivationEnd($a_activationend)
740  {
741  $this->activationend = $a_activationend;
742  }
743 
749  function getActivationEnd()
750  {
751  return $this->activationend;
752  }
753 
762  function getContentObject($a_hier_id, $a_pc_id = "")
763  {
764  $cont_node = $this->getContentNode($a_hier_id, $a_pc_id);
765  if (!is_object($cont_node))
766  {
767  return false;
768  }
769  include_once("./Services/COPage/classes/class.ilCOPagePCDef.php");
770  $node_name = $cont_node->node_name();
771  if ($node_name == "PageObject")
772  {
773  return null;
774  }
775  if ($node_name == "PageContent")
776  {
777  $child_node = $cont_node->first_child();
778  $node_name = $child_node->node_name();
779  }
780 
781  // table extra handling (@todo: get rid of it)
782  if ($node_name == "Table")
783  {
784  if ($child_node->get_attribute("DataTable") == "y")
785  {
786  require_once("./Services/COPage/classes/class.ilPCDataTable.php");
787  $tab = new ilPCDataTable($this);
788  $tab->setNode($cont_node);
789  $tab->setHierId($a_hier_id);
790  }
791  else
792  {
793  require_once("./Services/COPage/classes/class.ilPCTable.php");
794  $tab = new ilPCTable($this);
795  $tab->setNode($cont_node);
796  $tab->setHierId($a_hier_id);
797  }
798  $tab->setPcId($a_pc_id);
799  return $tab;
800  }
801 
802  // media extra handling (@todo: get rid of it)
803  if ($node_name == "MediaObject")
804  {
805  if ($_GET["pgEdMediaMode"] != "") {echo "ilPageObject::error media"; exit;}
806 
807  //require_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
808  require_once("./Services/COPage/classes/class.ilPCMediaObject.php");
809 
810  $mal_node =& $child_node->first_child();
811 //echo "ilPageObject::getContentObject:nodename:".$mal_node->node_name().":<br>";
812  $id_arr = explode("_", $mal_node->get_attribute("OriginId"));
813  $mob_id = $id_arr[count($id_arr) - 1];
814 
815  // allow deletion of non-existing media objects
816  if (!ilObject::_exists($mob_id) && in_array("delete", $_POST))
817  {
818  $mob_id = 0;
819  }
820 
821  //$mob =& new ilObjMediaObject($mob_id);
822  $mob = new ilPCMediaObject($this);
823  $mob->readMediaObject($mob_id);
824 
825  //$mob->setDom($this->dom);
826  $mob->setNode($cont_node);
827  $mob->setHierId($a_hier_id);
828  $mob->setPcId($a_pc_id);
829  return $mob;
830  }
831 
832  //
833  // generic procedure
834  //
835 
836  $pc_def = ilCOPagePCDef::getPCDefinitionByName($node_name);
837 
838  // check if pc definition has been found
839  if (!is_array($pc_def))
840  {
841  include_once("./Services/COPage/exceptions/class.ilCOPageUnknownPCTypeException.php");
842  throw new ilCOPageUnknownPCTypeException('Unknown PC Name "'.$node_name.'".');
843  }
844  $pc_class = "ilPC".$pc_def["name"];
845  $pc_path = "./".$pc_def["component"]."/".$pc_def["directory"]."/class.".$pc_class.".php";
846  require_once($pc_path);
847  $pc = new $pc_class($this);
848  $pc->setNode($cont_node);
849  $pc->setHierId($a_hier_id);
850  $pc->setPcId($a_pc_id);
851  return $pc;
852  }
853 
860  function &getContentNode($a_hier_id, $a_pc_id = "")
861  {
862  $xpc = xpath_new_context($this->dom);
863  if($a_hier_id == "pg")
864  {
865  return $this->node;
866  }
867  else
868  {
869  // get per pc id
870  if ($a_pc_id != "")
871  {
872  $path = "//*[@PCID = '$a_pc_id']";
873  $res =& xpath_eval($xpc, $path);
874  if (count($res->nodeset) == 1)
875  {
876  $cont_node =& $res->nodeset[0];
877  return $cont_node;
878  }
879  }
880 
881  // fall back to hier id
882  $path = "//*[@HierId = '$a_hier_id']";
883  $res =& xpath_eval($xpc, $path);
884  if (count($res->nodeset) == 1)
885  {
886  $cont_node =& $res->nodeset[0];
887  return $cont_node;
888  }
889  }
890  }
891 
898  function checkForTag($a_content_tag, $a_hier_id, $a_pc_id = "")
899  {
900  $xpc = xpath_new_context($this->dom);
901  // get per pc id
902  if ($a_pc_id != "")
903  {
904  $path = "//*[@PCID = '$a_pc_id']//".$a_content_tag;
905  $res = xpath_eval($xpc, $path);
906  if (count($res->nodeset) > 0)
907  {
908  return true;
909  }
910  }
911 
912  // fall back to hier id
913  $path = "//*[@HierId = '$a_hier_id']//".$a_content_tag;
914  $res =& xpath_eval($xpc, $path);
915  if (count($res->nodeset) > 0)
916  {
917  return true;
918  }
919  return false;
920  }
921 
922  // only for test purposes
923  function lookforhier($a_hier_id)
924  {
925  $xpc = xpath_new_context($this->dom);
926  $path = "//*[@HierId = '$a_hier_id']";
927  $res =& xpath_eval($xpc, $path);
928  if (count($res->nodeset) == 1)
929  return "YES";
930  else
931  return "NO";
932  }
933 
934 
935  function &getNode()
936  {
937  return $this->node;
938  }
939 
940 
949  function setXMLContent($a_xml, $a_encoding = "UTF-8")
950  {
951  $this->encoding = $a_encoding;
952  $this->xml = $a_xml;
953  }
954 
961  function appendXMLContent($a_xml)
962  {
963  $this->xml.= $a_xml;
964  }
965 
966 
970  function getXMLContent($a_incl_head = false)
971  {
972  // build full http path for XML DOCTYPE header.
973  // Under windows a relative path doesn't work :-(
974  if($a_incl_head)
975  {
976 //echo "+".$this->encoding."+";
977  $enc_str = (!empty($this->encoding))
978  ? "encoding=\"".$this->encoding."\""
979  : "";
980  return "<?xml version=\"1.0\" $enc_str ?>".
981  "<!DOCTYPE PageObject SYSTEM \"".ILIAS_ABSOLUTE_PATH."/xml/".$this->cur_dtd."\">".
982  $this->xml;
983  }
984  else
985  {
986  return $this->xml;
987  }
988  }
989 
994  function copyXmlContent($a_clone_mobs = false)
995  {
996  $xml = $this->getXmlContent();
997  $temp_dom = domxml_open_mem('<?xml version="1.0" encoding="UTF-8"?>'.$xml,
998  DOMXML_LOAD_PARSING, $error);
999  if(empty($error))
1000  {
1001  $this->handleCopiedContent($temp_dom, true, $a_clone_mobs);
1002  }
1003  $xml = $temp_dom->dump_mem(0, $this->encoding);
1004  $xml = eregi_replace("<\?xml[^>]*>","",$xml);
1005  $xml = eregi_replace("<!DOCTYPE[^>]*>","",$xml);
1006 
1007  return $xml;
1008  }
1009 
1010 // @todo 1: begin: generalize, remove concrete dependencies
1011 
1021  function handleCopiedContent($a_dom, $a_self_ass = true, $a_clone_mobs = false)
1022  {
1023  include_once("./Services/COPage/classes/class.ilCOPagePCDef.php");
1025 
1026  // handle question elements
1027  if ($a_self_ass)
1028  {
1029  $this->newQuestionCopies($a_dom);
1030  }
1031  else
1032  {
1033  $this->removeQuestions($a_dom);
1034  }
1035 
1036  // handle interactive images
1037  $this->newIIMCopies($a_dom);
1038 
1039  // handle media objects
1040  if ($a_clone_mobs)
1041  {
1042  $this->newMobCopies($a_dom);
1043  }
1044 
1045 // @todo 1: move all functions from above to the new domdoc
1046  if ($a_dom instanceof php4DOMDocument)
1047  {
1048  $a_dom = $a_dom->myDOMDocument;
1049  }
1050  foreach ($defs as $def)
1051  {
1053  $cl = $def["pc_class"];
1054  $cl::handleCopiedContent($a_dom, $a_self_ass, $a_clone_mobs);
1055  }
1056 
1057  }
1058 
1063  function newIIMCopies($temp_dom)
1064  {
1065  // Get question IDs
1066  $path = "//InteractiveImage/MediaAlias";
1067  $xpc = xpath_new_context($temp_dom);
1068  $res = & xpath_eval($xpc, $path);
1069 
1070  $q_ids = array();
1071  include_once("./Services/COPage/classes/class.ilInternalLink.php");
1072  for ($i = 0; $i < count ($res->nodeset); $i++)
1073  {
1074  $or_id = $res->nodeset[$i]->get_attribute("OriginId");
1075 
1076  $inst_id = ilInternalLink::_extractInstOfTarget($or_id);
1077  $mob_id = ilInternalLink::_extractObjIdOfTarget($or_id);
1078 
1079  if (!($inst_id > 0))
1080  {
1081  if ($mob_id > 0)
1082  {
1083  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1084  $media_object = new ilObjMediaObject($mob_id);
1085 
1086  // now copy this question and change reference to
1087  // new question id
1088  $new_mob = $media_object->duplicate();
1089 
1090  $res->nodeset[$i]->set_attribute("OriginId", "il__mob_".$new_mob->getId());
1091  }
1092  }
1093  }
1094  }
1095 
1099  function newMobCopies($temp_dom)
1100  {
1101  // Get question IDs
1102  $path = "//MediaObject/MediaAlias";
1103  $xpc = xpath_new_context($temp_dom);
1104  $res = & xpath_eval($xpc, $path);
1105 
1106  $q_ids = array();
1107  include_once("./Services/COPage/classes/class.ilInternalLink.php");
1108  for ($i = 0; $i < count ($res->nodeset); $i++)
1109  {
1110  $or_id = $res->nodeset[$i]->get_attribute("OriginId");
1111 
1112  $inst_id = ilInternalLink::_extractInstOfTarget($or_id);
1113  $mob_id = ilInternalLink::_extractObjIdOfTarget($or_id);
1114 
1115  if (!($inst_id > 0))
1116  {
1117  if ($mob_id > 0)
1118  {
1119  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1120  $media_object = new ilObjMediaObject($mob_id);
1121 
1122  // now copy this question and change reference to
1123  // new question id
1124  $new_mob = $media_object->duplicate();
1125 
1126  $res->nodeset[$i]->set_attribute("OriginId", "il__mob_".$new_mob->getId());
1127  }
1128  }
1129  }
1130  }
1131 
1136  function newQuestionCopies(&$temp_dom)
1137  {
1138  // Get question IDs
1139  $path = "//Question";
1140  $xpc = xpath_new_context($temp_dom);
1141  $res = & xpath_eval($xpc, $path);
1142 
1143  $q_ids = array();
1144  include_once("./Services/COPage/classes/class.ilInternalLink.php");
1145  for ($i = 0; $i < count ($res->nodeset); $i++)
1146  {
1147  $qref = $res->nodeset[$i]->get_attribute("QRef");
1148 
1149  $inst_id = ilInternalLink::_extractInstOfTarget($qref);
1151 
1152  if (!($inst_id > 0))
1153  {
1154  if ($q_id > 0)
1155  {
1156  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1157  $question = assQuestion::_instanciateQuestion($q_id);
1158 
1159  // check if page for question exists
1160  // due to a bug in early 4.2.x version this is possible
1161  if (!ilPageObject::_exists("qpl", $q_id))
1162  {
1163  $question->createPageObject();
1164  }
1165 
1166  // now copy this question and change reference to
1167  // new question id
1168  $duplicate_id = $question->duplicate(false);
1169  $res->nodeset[$i]->set_attribute("QRef", "il__qst_".$duplicate_id);
1170  }
1171  }
1172  }
1173  }
1174 
1181  function removeQuestions(&$temp_dom)
1182  {
1183  // Get question IDs
1184  $path = "//Question";
1185  $xpc = xpath_new_context($temp_dom);
1186  $res = & xpath_eval($xpc, $path);
1187  for ($i = 0; $i < count ($res->nodeset); $i++)
1188  {
1189  $parent_node = $res->nodeset[$i]->parent_node();
1190  $parent_node->unlink_node($parent_node);
1191  }
1192  }
1193 
1194 // @todo: end
1195 
1203  {
1204  // Get question IDs
1205  $this->buildDom();
1206  $path = "//PageContent";
1207  $xpc = xpath_new_context($this->dom);
1208  $res = & xpath_eval($xpc, $path);
1209  return count ($res->nodeset);
1210  }
1211 
1216  function getXMLFromDom($a_incl_head = false, $a_append_mobs = false, $a_append_bib = false,
1217  $a_append_str = "", $a_omit_pageobject_tag = false)
1218  {
1219  if ($a_incl_head)
1220  {
1221 //echo "\n<br>#".$this->encoding."#";
1222  return $this->dom->dump_mem(0, $this->encoding);
1223  }
1224  else
1225  {
1226  // append multimedia object elements
1227  if ($a_append_mobs || $a_append_bib || $a_append_link_info)
1228  {
1229  $mobs = "";
1230  $bibs = "";
1231  if ($a_append_mobs)
1232  {
1233  $mobs =& $this->getMultimediaXML();
1234  }
1235  if ($a_append_bib)
1236  {
1237 // deprecated
1238 // $bibs =& $this->getBibliographyXML();
1239  }
1240  $trans =& $this->getLanguageVariablesXML();
1241  return "<dummy>".$this->dom->dump_node($this->node).$mobs.$bibs.$trans.$a_append_str."</dummy>";
1242  }
1243  else
1244  {
1245  if (is_object($this->dom))
1246  {
1247  if ($a_omit_pageobject_tag)
1248  {
1249  $xml = "";
1250  $childs =& $this->node->child_nodes();
1251  for($i = 0; $i < count($childs); $i++)
1252  {
1253  $xml.= $this->dom->dump_node($childs[$i]);
1254  }
1255  return $xml;
1256  }
1257  else
1258  {
1259  $xml = $this->dom->dump_mem(0, $this->encoding);
1260  $xml = eregi_replace("<\?xml[^>]*>","",$xml);
1261  $xml = eregi_replace("<!DOCTYPE[^>]*>","",$xml);
1262 
1263  return $xml;
1264 
1265  // don't use dump_node. This gives always entities.
1266  //return $this->dom->dump_node($this->node);
1267  }
1268  }
1269  else
1270  {
1271  return "";
1272  }
1273  }
1274  }
1275  }
1276 
1281  {
1282  global $lng;
1283 
1284  $xml = "<LVs>";
1285  $lang_vars = array(
1286  "ed_paste_clip", "ed_edit", "ed_edit_prop", "ed_delete", "ed_moveafter",
1287  "ed_movebefore", "ed_go", "ed_class", "ed_width", "ed_align_left",
1288  "ed_align_right", "ed_align_center", "ed_align_left_float",
1289  "ed_align_right_float", "ed_delete_item", "ed_new_item_before",
1290  "ed_new_item_after", "ed_copy_clip", "please_select", "ed_split_page",
1291  "ed_item_up", "ed_item_down", "ed_split_page_next","ed_enable",
1292  "de_activate", "ed_paste", "ed_edit_multiple", "ed_cut", "ed_copy");
1293 
1294  // collect lang vars from pc elements
1295  include_once("./Services/COPage/classes/class.ilCOPagePCDef.php");
1297  foreach ($defs as $def)
1298  {
1299  $lang_vars[] = "pc_".$def["pc_type"];
1300  $lang_vars[] = "ed_insert_".$def["pc_type"];
1301 
1303  $cl = $def["pc_class"];
1304  $lvs = call_user_func($def["pc_class"].'::getLangVars');
1305  foreach ($lvs as $lv)
1306  {
1307  $lang_vars[] = $lv;
1308  }
1309  }
1310 
1311  foreach ($lang_vars as $lang_var)
1312  {
1313  $this->appendLangVarXML($xml, $lang_var);
1314  }
1315 
1316  $xml.= "</LVs>";
1317 
1318  return $xml;
1319  }
1320 
1321  function appendLangVarXML(&$xml, $var)
1322  {
1323  global $lng;
1324 
1325  $xml.= "<LV name=\"$var\" value=\"".$lng->txt("cont_".$var)."\"/>";
1326  }
1327 
1328 // @todo begin: move this to paragraph class
1329 
1331  {
1332  if($this->dom)
1333  {
1334  require_once("./Services/COPage/classes/class.ilPCParagraph.php");
1335  $xpc = xpath_new_context($this->dom);
1336  $path = "//Paragraph[1]";
1337  $res =& xpath_eval($xpc, $path);
1338  if (count($res->nodeset) > 0)
1339  {
1340  $cont_node =& $res->nodeset[0]->parent_node();
1341  $par =& new ilPCParagraph($this);
1342  $par->setNode($cont_node);
1343  return $par->getText();
1344  }
1345  }
1346  return "";
1347  }
1348 
1355  function setParagraphContent($a_hier_id, $a_content)
1356  {
1357  $node = $this->getContentNode($a_hier_id);
1358  if (is_object($node))
1359  {
1360  $node->set_content($a_content);
1361  }
1362  }
1363 
1364 // @todo end
1365 
1366 
1375  // @todo: can we do this better
1376  function setContainsIntLink($a_contains_link)
1377  {
1378  $this->contains_int_link = $a_contains_link;
1379  }
1380 
1385  // @todo: can we do this better
1386  function containsIntLink()
1387  {
1388  return $this->contains_int_link;
1389  }
1390 
1391  function needsImportParsing($a_parse = "")
1392  {
1393 
1394  if ($a_parse === true)
1395  {
1396  $this->needs_parsing = true;
1397  }
1398  if ($a_parse === false)
1399  {
1400  $this->needs_parsing = false;
1401  }
1402  return $this->needs_parsing;
1403  }
1404 
1410  // @todo: can we do this better
1411  public function setContainsQuestion($a_val)
1412  {
1413  $this->contains_question = $a_val;
1414  }
1415 
1421  public function getContainsQuestion()
1422  {
1423  return $this->contains_question;
1424  }
1425 
1426 
1431  // @todo: move to media class
1432  function collectMediaObjects($a_inline_only = true)
1433  {
1434 //echo htmlentities($this->getXMLFromDom());
1435  // determine all media aliases of the page
1436  $xpc = xpath_new_context($this->dom);
1437  $path = "//MediaObject/MediaAlias";
1438  $res =& xpath_eval($xpc, $path);
1439  $mob_ids = array();
1440  for($i = 0; $i < count($res->nodeset); $i++)
1441  {
1442  $id_arr = explode("_", $res->nodeset[$i]->get_attribute("OriginId"));
1443  $mob_id = $id_arr[count($id_arr) - 1];
1444  $mob_ids[$mob_id] = $mob_id;
1445  }
1446 
1447  // determine all media aliases of interactive images
1448  $xpc = xpath_new_context($this->dom);
1449  $path = "//InteractiveImage/MediaAlias";
1450  $res =& xpath_eval($xpc, $path);
1451  for($i = 0; $i < count($res->nodeset); $i++)
1452  {
1453  $id_arr = explode("_", $res->nodeset[$i]->get_attribute("OriginId"));
1454  $mob_id = $id_arr[count($id_arr) - 1];
1455  $mob_ids[$mob_id] = $mob_id;
1456  }
1457 
1458  // determine all inline internal media links
1459  $xpc = xpath_new_context($this->dom);
1460  $path = "//IntLink[@Type = 'MediaObject']";
1461  $res =& xpath_eval($xpc, $path);
1462 
1463  for($i = 0; $i < count($res->nodeset); $i++)
1464  {
1465  if (($res->nodeset[$i]->get_attribute("TargetFrame") == "") ||
1466  (!$a_inline_only))
1467  {
1468  $target = $res->nodeset[$i]->get_attribute("Target");
1469  $id_arr = explode("_", $target);
1470  if (($id_arr[1] == IL_INST_ID) ||
1471  (substr($target, 0, 4) == "il__"))
1472  {
1473  $mob_id = $id_arr[count($id_arr) - 1];
1474  if (ilObject::_exists($mob_id))
1475  {
1476  $mob_ids[$mob_id] = $mob_id;
1477  }
1478  }
1479  }
1480  }
1481 
1482  return $mob_ids;
1483  }
1484 
1485 
1489  // @todo: can we do this better?
1490  function getInternalLinks($a_cnt_multiple = false)
1491  {
1492  // get all internal links of the page
1493  $xpc = xpath_new_context($this->dom);
1494  $path = "//IntLink";
1495  $res = xpath_eval($xpc, $path);
1496 
1497  $links = array();
1498  $cnt_multiple = 1;
1499  for($i = 0; $i < count($res->nodeset); $i++)
1500  {
1501  $add = "";
1502  if ($a_cnt_multiple)
1503  {
1504  $add = ":".$cnt_multiple;
1505  }
1506  $target = $res->nodeset[$i]->get_attribute("Target");
1507  $type = $res->nodeset[$i]->get_attribute("Type");
1508  $targetframe = $res->nodeset[$i]->get_attribute("TargetFrame");
1509  $anchor = $res->nodeset[$i]->get_attribute("Anchor");
1510  $links[$target.":".$type.":".$targetframe.":".$anchor.$add] =
1511  array("Target" => $target, "Type" => $type,
1512  "TargetFrame" => $targetframe, "Anchor" => $anchor);
1513 
1514  // get links (image map areas) for inline media objects
1515  if ($type == "MediaObject" && $targetframe == "")
1516  {
1517  if (substr($target, 0, 4) =="il__")
1518  {
1519  $id_arr = explode("_", $target);
1520  $id = $id_arr[count($id_arr) - 1];
1521 
1522  $med_links = ilMediaItem::_getMapAreasIntLinks($id);
1523  foreach($med_links as $key => $med_link)
1524  {
1525  $links[$key] = $med_link;
1526  }
1527  }
1528 
1529  }
1530 //echo "<br>-:".$target.":".$type.":".$targetframe.":-";
1531  $cnt_multiple++;
1532  }
1533  unset($xpc);
1534 
1535  // get all media aliases
1536  $xpc = xpath_new_context($this->dom);
1537  $path = "//MediaAlias";
1538  $res =& xpath_eval($xpc, $path);
1539 
1540  require_once("Services/MediaObjects/classes/class.ilMediaItem.php");
1541  for($i = 0; $i < count($res->nodeset); $i++)
1542  {
1543  $oid = $res->nodeset[$i]->get_attribute("OriginId");
1544  if (substr($oid, 0, 4) =="il__")
1545  {
1546  $id_arr = explode("_", $oid);
1547  $id = $id_arr[count($id_arr) - 1];
1548 
1549  $med_links = ilMediaItem::_getMapAreasIntLinks($id);
1550  foreach($med_links as $key => $med_link)
1551  {
1552  $links[$key] = $med_link;
1553  }
1554  }
1555  }
1556  unset($xpc);
1557 
1558  return $links;
1559  }
1560 
1565  // @todo: move to media class
1566  function getMultimediaXML()
1567  {
1568  $mob_ids = $this->collectMediaObjects();
1569 
1570  // get xml of corresponding media objects
1571  $mobs_xml = "";
1572  require_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1573  foreach($mob_ids as $mob_id => $dummy)
1574  {
1575  if (ilObject::_lookupType($mob_id) == "mob")
1576  {
1577  $mob_obj =& new ilObjMediaObject($mob_id);
1578  $mobs_xml .= $mob_obj->getXML(IL_MODE_OUTPUT);
1579  }
1580  }
1581 //var_dump($mobs_xml);
1582  return $mobs_xml;
1583  }
1584 
1588  // @todo: move to media class
1589  function getMediaAliasElement($a_mob_id, $a_nr = 1)
1590  {
1591  $xpc = xpath_new_context($this->dom);
1592  $path = "//MediaObject/MediaAlias[@OriginId='il__mob_$a_mob_id']";
1593  $res =& xpath_eval($xpc, $path);
1594  $mal_node =& $res->nodeset[$a_nr - 1];
1595  $mob_node =& $mal_node->parent_node();
1596 
1597  return $this->dom->dump_node($mob_node);
1598  }
1599 
1605  function validateDom()
1606  {
1607  $this->stripHierIDs();
1608 
1609  // possible fix for #14820
1610  libxml_disable_entity_loader(false);
1611 
1612  @$this->dom->validate($error);
1613 
1614  return $error;
1615  }
1616 
1632  // @todo: can we do this better? remove dependencies?
1633  function addHierIDs()
1634  {
1635  $this->hier_ids = array();
1636  $this->first_row_ids = array();
1637  $this->first_col_ids = array();
1638  $this->list_item_ids = array();
1639  $this->file_item_ids = array();
1640 
1641  // set hierarchical ids for Paragraphs, Tables, TableRows and TableData elements
1642  $xpc = xpath_new_context($this->dom);
1643  //$path = "//Paragraph | //Table | //TableRow | //TableData";
1644 
1645  $sep = $path = "";
1646  foreach ($this->id_elements as $el)
1647  {
1648  $path.= $sep."//".$el;
1649  $sep = " | ";
1650  }
1651 
1652  $res =& xpath_eval($xpc, $path);
1653  for($i = 0; $i < count($res->nodeset); $i++)
1654  {
1655  $cnode = $res->nodeset[$i];
1656  $ctag = $cnode->node_name();
1657 
1658  // get hierarchical id of previous sibling
1659  $sib_hier_id = "";
1660  while($cnode =& $cnode->previous_sibling())
1661  {
1662  if (($cnode->node_type() == XML_ELEMENT_NODE)
1663  && $cnode->has_attribute("HierId"))
1664  {
1665  $sib_hier_id = $cnode->get_attribute("HierId");
1666  //$sib_hier_id = $id_attr->value();
1667  break;
1668  }
1669  }
1670 
1671  if ($sib_hier_id != "") // set id to sibling id "+ 1"
1672  {
1673  require_once("./Services/COPage/classes/class.ilPageContent.php");
1674  $node_hier_id = ilPageContent::incEdId($sib_hier_id);
1675  $res->nodeset[$i]->set_attribute("HierId", $node_hier_id);
1676  $this->hier_ids[] = $node_hier_id;
1677  if ($ctag == "TableData")
1678  {
1679  if (substr($par_hier_id,strlen($par_hier_id)-2) == "_1")
1680  {
1681  $this->first_row_ids[] = $node_hier_id;
1682  }
1683  }
1684  if ($ctag == "ListItem")
1685  {
1686  $this->list_item_ids[] = $node_hier_id;
1687  }
1688  if ($ctag == "FileItem")
1689  {
1690  $this->file_item_ids[] = $node_hier_id;
1691  }
1692  }
1693  else // no sibling -> node is first child
1694  {
1695  // get hierarchical id of next parent
1696  $cnode = $res->nodeset[$i];
1697  $par_hier_id = "";
1698  while($cnode =& $cnode->parent_node())
1699  {
1700  if (($cnode->node_type() == XML_ELEMENT_NODE)
1701  && $cnode->has_attribute("HierId"))
1702  {
1703  $par_hier_id = $cnode->get_attribute("HierId");
1704  //$par_hier_id = $id_attr->value();
1705  break;
1706  }
1707  }
1708 //echo "<br>par:".$par_hier_id." ($ctag)";
1709  if (($par_hier_id != "") && ($par_hier_id != "pg")) // set id to parent_id."_1"
1710  {
1711  $node_hier_id = $par_hier_id."_1";
1712  $res->nodeset[$i]->set_attribute("HierId", $node_hier_id);
1713  $this->hier_ids[] = $node_hier_id;
1714  if ($ctag == "TableData")
1715  {
1716  $this->first_col_ids[] = $node_hier_id;
1717  if (substr($par_hier_id,strlen($par_hier_id)-2) == "_1")
1718  {
1719  $this->first_row_ids[] = $node_hier_id;
1720  }
1721  }
1722  if ($ctag == "ListItem")
1723  {
1724  $this->list_item_ids[] = $node_hier_id;
1725  }
1726  if ($ctag == "FileItem")
1727  {
1728  $this->file_item_ids[] = $node_hier_id;
1729  }
1730 
1731  }
1732  else // no sibling, no parent -> first node
1733  {
1734  $node_hier_id = "1";
1735  $res->nodeset[$i]->set_attribute("HierId", $node_hier_id);
1736  $this->hier_ids[] = $node_hier_id;
1737  }
1738  }
1739  }
1740 
1741  // set special hierarchical id "pg" for pageobject
1742  $xpc = xpath_new_context($this->dom);
1743  $path = "//PageObject";
1744  $res =& xpath_eval($xpc, $path);
1745  for($i = 0; $i < count($res->nodeset); $i++) // should only be 1
1746  {
1747  $res->nodeset[$i]->set_attribute("HierId", "pg");
1748  $this->hier_ids[] = "pg";
1749  }
1750  unset($xpc);
1751  }
1752 
1756  function getHierIds()
1757  {
1758  return $this->hier_ids;
1759  }
1760 
1764  // @todo: move to table classes
1765  function getFirstRowIds()
1766  {
1767  return $this->first_row_ids;
1768  }
1769 
1773  // @todo: move to table classes
1775  {
1776  return $this->first_col_ids;
1777  }
1778 
1782  // @todo: move to list class
1783  function getListItemIds()
1784  {
1785  return $this->list_item_ids;
1786  }
1787 
1791  // @todo: move to file item class
1792  function getFileItemIds()
1793  {
1794  return $this->file_item_ids;
1795  }
1796 
1800  function stripHierIDs()
1801  {
1802  if(is_object($this->dom))
1803  {
1804  $xpc = xpath_new_context($this->dom);
1805  $path = "//*[@HierId]";
1806  $res =& xpath_eval($xpc, $path);
1807  for($i = 0; $i < count($res->nodeset); $i++) // should only be 1
1808  {
1809  if ($res->nodeset[$i]->has_attribute("HierId"))
1810  {
1811  $res->nodeset[$i]->remove_attribute("HierId");
1812  }
1813  }
1814  unset($xpc);
1815  }
1816  }
1817 
1821  function getHierIdsForPCIds($a_pc_ids)
1822  {
1823  if (!is_array($a_pc_ids) || count($a_pc_ids) == 0)
1824  {
1825  return array();
1826  }
1827  $ret = array();
1828 
1829  if(is_object($this->dom))
1830  {
1831  $xpc = xpath_new_context($this->dom);
1832  $path = "//*[@PCID]";
1833  $res =& xpath_eval($xpc, $path);
1834  for($i = 0; $i < count($res->nodeset); $i++) // should only be 1
1835  {
1836  $pc_id = $res->nodeset[$i]->get_attribute("PCID");
1837  if (in_array($pc_id, $a_pc_ids))
1838  {
1839  $ret[$pc_id] = $res->nodeset[$i]->get_attribute("HierId");
1840  }
1841  }
1842  unset($xpc);
1843  }
1844 //var_dump($ret);
1845  return $ret;
1846  }
1847 
1851  // @todo: move to file item class
1852  function addFileSizes()
1853  {
1854  $xpc = xpath_new_context($this->dom);
1855  $path = "//FileItem";
1856  $res =& xpath_eval($xpc, $path);
1857  for($i = 0; $i < count($res->nodeset); $i++)
1858  {
1859  $cnode =& $res->nodeset[$i];
1860  $size_node =& $this->dom->create_element("Size");
1861  $size_node =& $cnode->append_child($size_node);
1862 
1863  $childs =& $cnode->child_nodes();
1864  $size = "";
1865  for($j = 0; $j < count($childs); $j++)
1866  {
1867  if ($childs[$j]->node_name() == "Identifier")
1868  {
1869  if ($childs[$j]->has_attribute("Entry"))
1870  {
1871  $entry = $childs[$j]->get_attribute("Entry");
1872  $entry_arr = explode("_", $entry);
1873  $id = $entry_arr[count($entry_arr) - 1];
1874  require_once("./Modules/File/classes/class.ilObjFile.php");
1876  }
1877  }
1878  }
1879  $size_node->set_content($size);
1880  }
1881 
1882  unset($xpc);
1883  }
1884 
1889  // @todo: possible to improve this?
1890  function resolveIntLinks()
1891  {
1892  // resolve normal internal links
1893  $xpc = xpath_new_context($this->dom);
1894  $path = "//IntLink";
1895  $res =& xpath_eval($xpc, $path);
1896  for($i = 0; $i < count($res->nodeset); $i++)
1897  {
1898  $target = $res->nodeset[$i]->get_attribute("Target");
1899  $type = $res->nodeset[$i]->get_attribute("Type");
1900 
1901  $new_target = ilInternalLink::_getIdForImportId($type, $target);
1902  if ($new_target !== false)
1903  {
1904  $res->nodeset[$i]->set_attribute("Target", $new_target);
1905  }
1906  else // check wether link target is same installation
1907  {
1908  if (ilInternalLink::_extractInstOfTarget($target) == IL_INST_ID &&
1909  IL_INST_ID > 0 && $type != "RepositoryItem")
1910  {
1911  $new_target = ilInternalLink::_removeInstFromTarget($target);
1912  if (ilInternalLink::_exists($type, $new_target))
1913  {
1914  $res->nodeset[$i]->set_attribute("Target", $new_target);
1915  }
1916  }
1917  }
1918 
1919  }
1920  unset($xpc);
1921 
1922  // resolve internal links in map areas
1923  $xpc = xpath_new_context($this->dom);
1924  $path = "//MediaAlias";
1925  $res =& xpath_eval($xpc, $path);
1926 //echo "<br><b>page::resolve</b><br>";
1927 //echo "Content:".htmlentities($this->getXMLFromDOM()).":<br>";
1928  for($i = 0; $i < count($res->nodeset); $i++)
1929  {
1930  $orig_id = $res->nodeset[$i]->get_attribute("OriginId");
1931  $id_arr = explode("_", $orig_id);
1932  $mob_id = $id_arr[count($id_arr) - 1];
1934  }
1935  }
1936 
1943  // @todo: move to media classes?
1944  function resolveMediaAliases($a_mapping)
1945  {
1946  // resolve normal internal links
1947  $xpc = xpath_new_context($this->dom);
1948  $path = "//MediaAlias";
1949  $res =& xpath_eval($xpc, $path);
1950  $changed = false;
1951  for($i = 0; $i < count($res->nodeset); $i++)
1952  {
1953  $old_id = $res->nodeset[$i]->get_attribute("OriginId");
1954  $old_id = explode("_", $old_id);
1955  $old_id = $old_id[count($old_id) - 1];
1956  if ($a_mapping[$old_id] > 0)
1957  {
1958  $res->nodeset[$i]->set_attribute("OriginId", "il__mob_".$a_mapping[$old_id]);
1959  $changed = true;
1960  }
1961  }
1962  unset($xpc);
1963 
1964  return $changed;
1965  }
1966 
1973  // @todo: move to iim classes?
1974  function resolveIIMMediaAliases($a_mapping)
1975  {
1976  // resolve normal internal links
1977  $xpc = xpath_new_context($this->dom);
1978  $path = "//InteractiveImage/MediaAlias";
1979  $res =& xpath_eval($xpc, $path);
1980  $changed = false;
1981  for($i = 0; $i < count($res->nodeset); $i++)
1982  {
1983  $old_id = $res->nodeset[$i]->get_attribute("OriginId");
1984  if ($a_mapping[$old_id] > 0)
1985  {
1986  $res->nodeset[$i]->set_attribute("OriginId", "il__mob_".$a_mapping[$old_id]);
1987  $changed = true;
1988  }
1989  }
1990  unset($xpc);
1991 
1992  return $changed;
1993  }
1994 
2001  // @todo: move to file classes?
2002  function resolveFileItems($a_mapping)
2003  {
2004  // resolve normal internal links
2005  $xpc = xpath_new_context($this->dom);
2006  $path = "//FileItem/Identifier";
2007  $res =& xpath_eval($xpc, $path);
2008  $changed = false;
2009  for($i = 0; $i < count($res->nodeset); $i++)
2010  {
2011  $old_id = $res->nodeset[$i]->get_attribute("Entry");
2012  $old_id = explode("_", $old_id);
2013  $old_id = $old_id[count($old_id) - 1];
2014  if ($a_mapping[$old_id] > 0)
2015  {
2016  $res->nodeset[$i]->set_attribute("Entry", "il__file_".$a_mapping[$old_id]);
2017  $changed = true;
2018  }
2019  }
2020  unset($xpc);
2021 
2022  return $changed;
2023  }
2024 
2029  // @todo: move to question classes
2030  function resolveQuestionReferences($a_mapping)
2031  {
2032  // resolve normal internal links
2033  $xpc = xpath_new_context($this->dom);
2034  $path = "//Question";
2035  $res =& xpath_eval($xpc, $path);
2036  for($i = 0; $i < count($res->nodeset); $i++)
2037  {
2038  $qref = $res->nodeset[$i]->get_attribute("QRef");
2039 
2040  if (isset($a_mapping[$qref]))
2041  {
2042  $res->nodeset[$i]->set_attribute("QRef", "il__qst_".$a_mapping[$qref]["pool"]);
2043  }
2044  }
2045  unset($xpc);
2046  }
2047 
2048 
2055  // @todo: generalize, internal links usage info
2056  function moveIntLinks($a_from_to)
2057  {
2058  $this->buildDom();
2059 
2060  $changed = false;
2061 
2062  // resolve normal internal links
2063  $xpc = xpath_new_context($this->dom);
2064  $path = "//IntLink";
2065  $res =& xpath_eval($xpc, $path);
2066  for($i = 0; $i < count($res->nodeset); $i++)
2067  {
2068  $target = $res->nodeset[$i]->get_attribute("Target");
2069  $type = $res->nodeset[$i]->get_attribute("Type");
2070  $obj_id = ilInternalLink::_extractObjIdOfTarget($target);
2071  if ($a_from_to[$obj_id] > 0 && is_int(strpos($target, "__")))
2072  {
2073  if ($type == "PageObject" && ilLMObject::_lookupType($a_from_to[$obj_id]) == "pg")
2074  {
2075  $res->nodeset[$i]->set_attribute("Target", "il__pg_".$a_from_to[$obj_id]);
2076  $changed = true;
2077  }
2078  if ($type == "StructureObject" && ilLMObject::_lookupType($a_from_to[$obj_id]) == "st")
2079  {
2080  $res->nodeset[$i]->set_attribute("Target", "il__st_".$a_from_to[$obj_id]);
2081  $changed = true;
2082  }
2083  }
2084  }
2085  unset($xpc);
2086 
2087  // map areas
2088  $this->addHierIDs();
2089  $xpc = xpath_new_context($this->dom);
2090  $path = "//MediaAlias";
2091  $res =& xpath_eval($xpc, $path);
2092 
2093  require_once("Services/MediaObjects/classes/class.ilMediaItem.php");
2094  require_once("Services/COPage/classes/class.ilMediaAliasItem.php");
2095 
2096  for($i = 0; $i < count($res->nodeset); $i++)
2097  {
2098  $media_object_node = $res->nodeset[$i]->parent_node();
2099  $page_content_node = $media_object_node->parent_node();
2100  $c_hier_id = $page_content_node->get_attribute("HierId");
2101 
2102  // first check, wheter we got instance map areas -> take these
2103  $std_alias_item = new ilMediaAliasItem($this->dom,
2104  $c_hier_id, "Standard");
2105  $areas = $std_alias_item->getMapAreas();
2106  $correction_needed = false;
2107  if (count($areas) > 0)
2108  {
2109  // check if correction needed
2110  foreach($areas as $area)
2111  {
2112  if ($area["Type"] == "PageObject" ||
2113  $area["Type"] == "StructureObject")
2114  {
2115  $t = $area["Target"];
2116  $tid = _extractObjIdOfTarget($t);
2117  if ($a_from_to[$tid] > 0)
2118  {
2119  $correction_needed = true;
2120  }
2121  }
2122  }
2123  }
2124  else
2125  {
2126  $areas = array();
2127 
2128  // get object map areas and check whether at least one must
2129  // be corrected
2130  $oid = $res->nodeset[$i]->get_attribute("OriginId");
2131  if (substr($oid, 0, 4) =="il__")
2132  {
2133  $id_arr = explode("_", $oid);
2134  $id = $id_arr[count($id_arr) - 1];
2135 
2136  $mob = new ilObjMediaObject($id);
2137  $med_item = $mob->getMediaItem("Standard");
2138  $med_areas = $med_item->getMapAreas();
2139 
2140  foreach($med_areas as $area)
2141  {
2142  $link_type = ($area->getLinkType() == "int")
2143  ? "IntLink"
2144  : "ExtLink";
2145 
2146  $areas[] = array(
2147  "Nr" => $area->getNr(),
2148  "Shape" => $area->getShape(),
2149  "Coords" => $area->getCoords(),
2150  "Link" => array(
2151  "LinkType" => $link_type,
2152  "Href" => $area->getHref(),
2153  "Title" => $area->getTitle(),
2154  "Target" => $area->getTarget(),
2155  "Type" => $area->getType(),
2156  "TargetFrame" => $area->getTargetFrame()
2157  )
2158  );
2159 
2160  if ($area->getType() == "PageObject" ||
2161  $area->getType() == "StructureObject")
2162  {
2163  $t = $area->getTarget();
2165  if ($a_from_to[$tid] > 0)
2166  {
2167  $correction_needed = true;
2168  }
2169 //var_dump($a_from_to);
2170  }
2171  }
2172  }
2173  }
2174 
2175  // correct map area links
2176  if ($correction_needed)
2177  {
2178  $changed = true;
2179  $std_alias_item->deleteAllMapAreas();
2180  foreach($areas as $area)
2181  {
2182  if ($area["Link"]["LinkType"] == "IntLink")
2183  {
2184  $target = $area["Link"]["Target"];
2185  $type = $area["Link"]["Type"];
2186  $obj_id = ilInternalLink::_extractObjIdOfTarget($target);
2187  if ($a_from_to[$obj_id] > 0)
2188  {
2189  if ($type == "PageObject" && ilLMObject::_lookupType($a_from_to[$obj_id]) == "pg")
2190  {
2191  $area["Link"]["Target"] = "il__pg_".$a_from_to[$obj_id];
2192  }
2193  if ($type == "StructureObject" && ilLMObject::_lookupType($a_from_to[$obj_id]) == "st")
2194  {
2195  $area["Link"]["Target"] = "il__st_".$a_from_to[$obj_id];
2196  }
2197  }
2198  }
2199 
2200  $std_alias_item->addMapArea($area["Shape"], $area["Coords"],
2201  $area["Link"]["Title"],
2202  array( "Type" => $area["Link"]["Type"],
2203  "TargetFrame" => $area["Link"]["TargetFrame"],
2204  "Target" => $area["Link"]["Target"],
2205  "Href" => $area["Link"]["Href"],
2206  "LinkType" => $area["Link"]["LinkType"],
2207  ));
2208  }
2209  }
2210  }
2211  unset($xpc);
2212 
2213  return $changed;
2214  }
2215 
2221  // @todo: generalize, internal links usage info
2222  static function _handleImportRepositoryLinks($a_rep_import_id, $a_rep_type, $a_rep_ref_id)
2223  {
2224  include_once("./Services/COPage/classes/class.ilInternalLink.php");
2225 
2226 //echo "-".$a_rep_import_id."-".$a_rep_ref_id."-";
2227  $sources = ilInternalLink::_getSourcesOfTarget("obj",
2228  ilInternalLink::_extractObjIdOfTarget($a_rep_import_id),
2229  ilInternalLink::_extractInstOfTarget($a_rep_import_id));
2230 //var_dump($sources);
2231  foreach($sources as $source)
2232  {
2233 //echo "A";
2234  if ($source["type"] == "lm:pg")
2235  {
2236 //echo "B";
2237  include_once("./Modules/LearningModule/classes/class.ilLMPage.php");
2238  if (self::_exists("lm", $source["id"], $source["lang"]))
2239  {
2240  $page_obj = new ilLMPage($source["id"], 0, $source["lang"]);
2241  if (!$page_obj->page_not_found)
2242  {
2243  //echo "C";
2244  $page_obj->handleImportRepositoryLink($a_rep_import_id,
2245  $a_rep_type, $a_rep_ref_id);
2246  }
2247  $page_obj->update();
2248  }
2249  }
2250  }
2251  }
2252 
2253  // @todo: generalize, internal links usage info
2254  function handleImportRepositoryLink($a_rep_import_id, $a_rep_type, $a_rep_ref_id)
2255  {
2256  $this->buildDom();
2257 
2258  // resolve normal internal links
2259  $xpc = xpath_new_context($this->dom);
2260  $path = "//IntLink";
2261  $res =& xpath_eval($xpc, $path);
2262 //echo "1";
2263  for($i = 0; $i < count($res->nodeset); $i++)
2264  {
2265 //echo "2";
2266  $target = $res->nodeset[$i]->get_attribute("Target");
2267  $type = $res->nodeset[$i]->get_attribute("Type");
2268  if ($target == $a_rep_import_id && $type == "RepositoryItem")
2269  {
2270 //echo "setting:"."il__".$a_rep_type."_".$a_rep_ref_id;
2271  $res->nodeset[$i]->set_attribute("Target",
2272  "il__".$a_rep_type."_".$a_rep_ref_id);
2273  }
2274  }
2275  unset($xpc);
2276  }
2277 
2281  function createFromXML()
2282  {
2283  global $lng, $ilDB, $ilUser;
2284 
2285 //echo "<br>PageObject::createFromXML[".$this->getId()."]";
2286 
2287  $empty = false;
2288  if($this->getXMLContent() == "")
2289  {
2290  $this->setXMLContent("<PageObject></PageObject>");
2291  $empty = true;
2292  }
2293 
2294  $content = $this->getXMLContent();
2295  $this->buildDom(true);
2296  $dom_doc = $this->getDomDoc();
2297 
2298  $iel = $this->containsDeactivatedElements($content);
2299  $inl = $this->containsIntLinks($content);
2300 
2301  // create object
2302  $ilDB->insert("page_object", array(
2303  "page_id" => array("integer", $this->getId()),
2304  "parent_id" => array("integer", $this->getParentId()),
2305  "lang" => array("text", $this->getLanguage()),
2306  "content" => array("clob", $content),
2307  "parent_type" => array("text", $this->getParentType()),
2308  "create_user" => array("integer", $ilUser->getId()),
2309  "last_change_user" => array("integer", $ilUser->getId()),
2310  "active" => array("integer", $this->getActive()),
2311  "inactive_elements" => array("integer", $iel),
2312  "int_links" => array("integer", $inl),
2313  "created" => array("timestamp", ilUtil::now()),
2314  "last_change" => array("timestamp", ilUtil::now())
2315  ));
2316 
2317  // after update event
2318  $this->__afterUpdate($dom_doc, $content, true, $empty);
2319 
2320  }
2321 
2322 
2331  function updateFromXML()
2332  {
2333  global $lng, $ilDB, $ilUser;
2334 
2335 //echo "<br>PageObject::updateFromXML[".$this->getId()."]";
2336 //echo "update:".ilUtil::prepareDBString(($this->getXMLContent())).":<br>";
2337 //echo "update:".htmlentities($this->getXMLContent()).":<br>";
2338 
2339  $content = $this->getXMLContent();
2340  $this->buildDom(true);
2341  $dom_doc = $this->getDomDoc();
2342 
2343  $iel = $this->containsDeactivatedElements($content);
2344  $inl = $this->containsIntLinks($content);
2345 
2346  $ilDB->update("page_object", array(
2347  "content" => array("clob", $content),
2348  "parent_id" => array("integer", $this->getParentId()),
2349  "last_change_user" => array("integer", $ilUser->getId()),
2350  "last_change" => array("timestamp", ilUtil::now()),
2351  "active" => array("integer", $this->getActive()),
2352  "activation_start" => array("timestamp", $this->getActivationStart()),
2353  "activation_end" => array("timestamp", $this->getActivationEnd()),
2354  "inactive_elements" => array("integer", $iel),
2355  "int_links" => array("integer", $inl),
2356  ), array(
2357  "page_id" => array("integer", $this->getId()),
2358  "parent_type" => array("text", $this->getParentType()),
2359  "lang" => array("text", $this->getLanguage())
2360  ));
2361 
2362  // after update event
2363  $this->__afterUpdate($dom_doc, $content);
2364 
2365  return true;
2366  }
2367 
2374  protected final function __afterUpdate($a_domdoc, $a_xml, $a_creation = false, $a_empty = false)
2375  {
2376  // we do not need this if we are creating an empty page
2377  if (!$a_creation || !$a_empty)
2378  {
2379  // save internal link information
2380  // the page object is responsible to do this, since it "offers" the
2381  // internal link feature pc and page classes
2382  $this->saveInternalLinks($a_domdoc);
2383 
2384  // save style usage
2385  $this->saveStyleUsage($a_domdoc);
2386 
2387  // pc classes hook
2388  include_once("./Services/COPage/classes/class.ilCOPagePCDef.php");
2390  foreach ($defs as $def)
2391  {
2393  $cl = $def["pc_class"];
2394  call_user_func($def["pc_class"].'::afterPageUpdate', $this, $a_domdoc, $a_xml, $a_creation);
2395  }
2396  }
2397 
2398  // call page hook
2399  $this->afterUpdate();
2400 
2401  // call update listeners
2402  $this->callUpdateListeners();
2403  }
2404 
2411  function afterUpdate()
2412  {
2413  }
2414 
2415 
2420  function update($a_validate = true, $a_no_history = false)
2421  {
2422  global $lng, $ilDB, $ilUser, $ilLog, $ilCtrl;
2423 
2424  $lm_set = new ilSetting("lm");
2425 
2426 //echo "<br>**".$this->getId()."**";
2427 //echo "<br>PageObject::update[".$this->getId()."],validate($a_validate)";
2428 //echo "\n<br>dump_all2:".$this->dom->dump_mem(0, "UTF-8").":";
2429 //echo "\n<br>PageObject::update:".$this->getXMLFromDom().":";
2430 //debug_print_backtrace();
2431 //echo "<br>PageObject::update:".htmlentities($this->getXMLFromDom()); exit;
2432 
2433  // add missing pc ids
2434  if (!$this->checkPCIds())
2435  {
2436  $this->insertPCIds();
2437  }
2438 
2439  // test validating
2440  if($a_validate)
2441  {
2442  $errors = $this->validateDom();
2443  }
2444 //var_dump($errors); exit;
2445  if (empty($errors) && !$this->getEditLock())
2446  {
2447  include_once("./Services/User/classes/class.ilUserUtil.php");
2448  $lock = $this->getEditLockInfo();
2449  $errors = $lng->txt("cont_not_saved_edit_lock_expired");
2450  $errors.= "</br>".$lng->txt("obj_usr").": ".
2451  ilUserUtil::getNamePresentation($lock["edit_lock_user"]);
2452  $errors.= "</br>".$lng->txt("content_until").": ".
2453  ilDatePresentation::formatDate(new ilDateTime($lock["edit_lock_until"],IL_CAL_UNIX));
2454  }
2455 
2456 //echo "-".htmlentities($this->getXMLFromDom())."-"; exit;
2457  if(empty($errors))
2458  {
2459  // @todo 1: is this page type or pc content type
2460  // related -> plugins should be able to hook in!?
2462 
2463  // get xml content
2464  $content = $this->getXMLFromDom();
2465  $dom_doc = $this->getDomDoc();
2466 
2467  // this needs to be locked
2468 
2469  // write history entry
2470  $old_set = $ilDB->query("SELECT * FROM page_object WHERE ".
2471  "page_id = ".$ilDB->quote($this->getId(), "integer")." AND ".
2472  "parent_type = ".$ilDB->quote($this->getParentType(), "text")." AND ".
2473  "lang = ".$ilDB->quote($this->getLanguage(), "text"));
2474  $last_nr_set = $ilDB->query("SELECT max(nr) as mnr FROM page_history WHERE ".
2475  "page_id = ".$ilDB->quote($this->getId(), "integer")." AND ".
2476  "parent_type = ".$ilDB->quote($this->getParentType(), "text")." AND ".
2477  "lang = ".$ilDB->quote($this->getLanguage(), "text"));
2478  $last_nr = $ilDB->fetchAssoc($last_nr_set);
2479  if ($old_rec = $ilDB->fetchAssoc($old_set))
2480  {
2481  // only save, if something has changed
2482  if (($content != $old_rec["content"]) && !$a_no_history &&
2483  !$this->history_saved &&
2484  $lm_set->get("page_history", 1))
2485  {
2486  if ($old_rec["content"] != "<PageObject></PageObject>")
2487  {
2488  $ilDB->manipulateF("DELETE FROM page_history WHERE ".
2489  "page_id = %s AND parent_type = %s AND hdate = %s AND lang = %s",
2490  array("integer", "text", "timestamp", "text"),
2491  array($old_rec["page_id"], $old_rec["parent_type"], $old_rec["last_change"], $old_rec["lang"]));
2492 
2493  // the following lines are a workaround for
2494  // bug 6741
2495  $last_c = $old_rec["last_change"];
2496  if ($last_c == "")
2497  {
2498  $last_c = ilUtil::now();
2499  }
2500 
2501  $ilDB->insert("page_history", array(
2502  "page_id" => array("integer", $old_rec["page_id"]),
2503  "parent_type" => array("text", $old_rec["parent_type"]),
2504  "lang" => array("text", $old_rec["lang"]),
2505  "hdate" => array("timestamp", $last_c),
2506  "parent_id" => array("integer", $old_rec["parent_id"]),
2507  "content" => array("clob", $old_rec["content"]),
2508  "user_id" => array("integer", $old_rec["last_change_user"]),
2509  "ilias_version" => array("text", ILIAS_VERSION_NUMERIC),
2510  "nr" => array("integer", (int) $last_nr["mnr"] + 1)
2511  ));
2512 
2513  $old_content = $old_rec["content"];
2514  $old_domdoc = new DOMDocument();
2515  $old_nr = $last_nr["mnr"] + 1;
2516  $old_domdoc->loadXML('<?xml version="1.0" encoding="UTF-8"?>'.$old_content);
2517 
2518  // after history entry creation event
2519  $this->__afterHistoryEntry($old_domdoc, $old_content, $old_nr);
2520 
2521  $this->history_saved = true; // only save one time
2522  }
2523  else
2524  {
2525  $this->history_saved = true; // do not save on first change
2526  }
2527  }
2528  }
2529 //echo htmlentities($content);
2530  $em = (trim($content) == "<PageObject/>")
2531  ? 1
2532  : 0;
2533 
2534  // @todo: pass dom instead?
2535  $iel = $this->containsDeactivatedElements($content);
2536  $inl = $this->containsIntLinks($content);
2537 
2538  $ilDB->update("page_object", array(
2539  "content" => array("clob", $content),
2540  "parent_id" => array("integer", $this->getParentId()),
2541  "last_change_user" => array("integer", $ilUser->getId()),
2542  "last_change" => array("timestamp", ilUtil::now()),
2543  "is_empty" => array("integer", $em),
2544  "active" => array("integer", $this->getActive()),
2545  "activation_start" => array("timestamp", $this->getActivationStart()),
2546  "activation_end" => array("timestamp", $this->getActivationEnd()),
2547  "show_activation_info" => array("integer", $this->getShowActivationInfo()),
2548  "inactive_elements" => array("integer", $iel),
2549  "int_links" => array("integer", $inl),
2550  ), array(
2551  "page_id" => array("integer", $this->getId()),
2552  "parent_type" => array("text", $this->getParentType()),
2553  "lang" => array("text", $this->getLanguage())
2554  ));
2555 
2556  // after update event
2557  $this->__afterUpdate($dom_doc, $content);
2558 
2559 //echo "<br>PageObject::update:".htmlentities($this->getXMLContent()).":";
2560  return true;
2561  }
2562  else
2563  {
2564  return $errors;
2565  }
2566  }
2567 
2568 
2569 
2573  function delete()
2574  {
2575  global $ilDB;
2576 
2577  $mobs = array();
2578  $files = array();
2579 
2580  if (!$this->page_not_found)
2581  {
2582  $this->buildDom();
2583  $mobs = $this->collectMediaObjects(false);
2584  }
2585 
2586  $this->__beforeDelete();
2587 
2588  // delete style usages
2589  $this->deleteStyleUsages(false);
2590 
2591  // delete internal links
2592  $this->deleteInternalLinks();
2593 
2594  // delete all mob usages
2595  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2596  ilObjMediaObject::_deleteAllUsages($this->getParentType().":pg", $this->getId());
2597 
2598  // delete news
2599  include_once("./Services/News/classes/class.ilNewsItem.php");
2601  $this->getParentType(), $this->getId(), "pg");
2602 
2603  // delete page_object entry
2604  $ilDB->manipulate("DELETE FROM page_object ".
2605  "WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
2606  " AND parent_type= ".$ilDB->quote($this->getParentType(), "text"));
2607  //$this->ilias->db->query($query);
2608 
2609  // delete media objects
2610  foreach ($mobs as $mob_id)
2611  {
2612  if(ilObject::_lookupType($mob_id) != 'mob')
2613  {
2614  $GLOBALS['ilLog']->write(__METHOD__.': Type mismatch. Ignoring mob with id: '.$mob_id);
2615  continue;
2616  }
2617 
2618  if (ilObject::_exists($mob_id))
2619  {
2620  $mob_obj =& new ilObjMediaObject($mob_id);
2621  $mob_obj->delete();
2622  }
2623  }
2624 
2625 
2626  /* delete public and private notes (see PageObjectGUI->getNotesHTML())
2627  as they can be seen as personal data we are keeping them for now
2628  include_once("Services/Notes/classes/class.ilNote.php");
2629  foreach(array(IL_NOTE_PRIVATE, IL_NOTE_PUBLIC) as $note_type)
2630  {
2631  foreach(ilNote::_getNotesOfObject($this->getParentId(), $this->getId(),
2632  $this->getParentType(), $note_type) as $note)
2633  {
2634  $note->delete();
2635  }
2636  }
2637  */
2638  }
2639 
2645  protected final function __beforeDelete()
2646  {
2647  // pc classes hook
2648  include_once("./Services/COPage/classes/class.ilCOPagePCDef.php");
2650  foreach ($defs as $def)
2651  {
2653  $cl = $def["pc_class"];
2654  call_user_func($def["pc_class"].'::beforePageDelete', $this);
2655  }
2656  }
2657 
2663  protected final function __afterHistoryEntry($a_old_domdoc, $a_old_content, $a_old_nr)
2664  {
2665  // save style usage
2666  $this->saveStyleUsage($a_old_domdoc, $a_old_nr);
2667 
2668  // pc classes hook
2669  include_once("./Services/COPage/classes/class.ilCOPagePCDef.php");
2671  foreach ($defs as $def)
2672  {
2674  $cl = $def["pc_class"];
2675  call_user_func($def["pc_class"].'::afterPageHistoryEntry', $this, $a_old_domdoc, $a_old_content, $a_old_nr);
2676  }
2677  }
2678 
2684  function saveStyleUsage($a_domdoc, $a_old_nr = 0)
2685  {
2686  global $ilDB;
2687 
2688  // media aliases
2689  $xpath = new DOMXPath($a_domdoc);
2690  $path = "//Paragraph | //Section | //MediaAlias | //FileItem".
2691  " | //Table | //TableData | //Tabs | //List";
2692  $nodes = $xpath->query($path);
2693  $usages = array();
2694  foreach($nodes as $node)
2695  {
2696  switch ($node->localName)
2697  {
2698  case "Paragraph":
2699  $sname = $node->getAttribute("Characteristic");
2700  $stype = "text_block";
2701  $template = 0;
2702  break;
2703 
2704  case "Section":
2705  $sname = $node->getAttribute("Characteristic");
2706  $stype = "section";
2707  $template = 0;
2708  break;
2709 
2710  case "MediaAlias":
2711  $sname = $node->getAttribute("Class");
2712  $stype = "media_cont";
2713  $template = 0;
2714  break;
2715 
2716  case "FileItem":
2717  $sname = $node->getAttribute("Class");
2718  $stype = "flist_li";
2719  $template = 0;
2720  break;
2721 
2722  case "Table":
2723  $sname = $node->getAttribute("Template");
2724  if ($sname == "")
2725  {
2726  $sname = $node->getAttribute("Class");
2727  $stype = "table";
2728  $template = 0;
2729  }
2730  else
2731  {
2732  $stype = "table";
2733  $template = 1;
2734  }
2735  break;
2736 
2737  case "TableData":
2738  $sname = $node->getAttribute("Class");
2739  $stype = "table_cell";
2740  $template = 0;
2741  break;
2742 
2743  case "Tabs":
2744  $sname = $node->getAttribute("Template");
2745  if ($sname != "")
2746  {
2747  if ($node->getAttribute("Type") == "HorizontalAccordion")
2748  {
2749  $stype = "haccordion";
2750  }
2751  if ($node->getAttribute("Type") == "VerticalAccordion")
2752  {
2753  $stype = "vaccordion";
2754  }
2755  }
2756  $template = 1;
2757  break;
2758 
2759  case "List":
2760  $sname = $node->getAttribute("Class");
2761  if ($node->getAttribute("Type") == "Ordered")
2762  {
2763  $stype = "list_o";
2764  }
2765  else
2766  {
2767  $stype = "list_u";
2768  }
2769  $template = 0;
2770  break;
2771  }
2772  if ($sname != "" && $stype != "")
2773  {
2774  $usages[$sname.":".$stype.":".$template] = array("sname" => $sname,
2775  "stype" => $stype, "template" => $template);
2776  }
2777  }
2778 
2779 
2780  $this->deleteStyleUsages($a_old_nr);
2781 
2782  foreach ($usages as $u)
2783  {
2784  $ilDB->manipulate("INSERT INTO page_style_usage ".
2785  "(page_id, page_type, page_lang, page_nr, template, stype, sname) VALUES (".
2786  $ilDB->quote($this->getId(), "integer").",".
2787  $ilDB->quote($this->getParentType(), "text").",".
2788  $ilDB->quote($this->getLanguage(), "text").",".
2789  $ilDB->quote($a_old_nr, "integer").",".
2790  $ilDB->quote($u["template"], "integer").",".
2791  $ilDB->quote($u["stype"], "text").",".
2792  $ilDB->quote($u["sname"], "text").
2793  ")");
2794  }
2795  }
2796 
2803  function deleteStyleUsages($a_old_nr = 0)
2804  {
2805  global $ilDB;
2806 
2807  if ($a_old_nr !== false)
2808  {
2809  $and_old_nr = " AND page_nr = ".$ilDB->quote($a_old_nr, "integer");
2810  }
2811 
2812  $ilDB->manipulate("DELETE FROM page_style_usage WHERE ".
2813  " page_id = ".$ilDB->quote($this->getId(), "integer").
2814  " AND page_type = ".$ilDB->quote($this->getParentType(), "text").
2815  " AND page_lang = ".$ilDB->quote($this->getLanguage(), "text").
2816  $and_old_nr
2817  );
2818  }
2819 
2820 
2825  // @todo: move to content include class
2827  {
2828  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
2829  include_once("./Modules/File/classes/class.ilObjFile.php");
2831  $this->getId());
2832  $files = ilObjFile::_getFilesOfObject($this->getParentType().":pg",
2833  $this->getId());
2834  $objs = array_merge($mobs, $files);
2835  return ilObject::_getLastUpdateOfObjects($objs);
2836  }
2837 
2845  {
2846  include_once("./Services/COPage/classes/class.ilInternalLink.php");
2848  $this->getLanguage());
2849  }
2850 
2851 
2857  // @todo: move to specific classes, internal link use info
2858  function saveInternalLinks($a_domdoc)
2859  {
2860  global $ilDB;
2861 
2862  $this->deleteInternalLinks();
2863 
2864  // query IntLink elements
2865  $xpath = new DOMXPath($a_domdoc);
2866  $nodes = $xpath->query('//IntLink');
2867  foreach($nodes as $node)
2868  {
2869  $link_type = $node->getAttribute("Type");
2870 
2871  switch ($link_type)
2872  {
2873  case "StructureObject":
2874  $t_type = "st";
2875  break;
2876 
2877  case "PageObject":
2878  $t_type = "pg";
2879  break;
2880 
2881  case "GlossaryItem":
2882  $t_type = "git";
2883  break;
2884 
2885  case "MediaObject":
2886  $t_type = "mob";
2887  break;
2888 
2889  case "RepositoryItem":
2890  $t_type = "obj";
2891  break;
2892 
2893  case "File":
2894  $t_type = "file";
2895  break;
2896 
2897  case "WikiPage":
2898  $t_type = "wpage";
2899  break;
2900  }
2901 
2902  $target = $node->getAttribute("Target");
2903  $target_arr = explode("_", $target);
2904  $t_id = $target_arr[count($target_arr) - 1];
2905 
2906  // link to other internal object
2907  if (is_int(strpos($target, "__")))
2908  {
2909  $t_inst = 0;
2910  }
2911  else // link to unresolved object in other installation
2912  {
2913  $t_inst = $target_arr[1];
2914  }
2915 
2916  if ($t_id > 0)
2917  {
2918  ilInternalLink::_saveLink($this->getParentType().":pg", $this->getId(), $t_type,
2919  $t_id, $t_inst, $this->getLanguage());
2920  }
2921  }
2922  }
2923 
2927  function create()
2928  {
2929  $this->createFromXML();
2930  }
2931 
2939  function deleteContent($a_hid, $a_update = true, $a_pcid = "")
2940  {
2941  $curr_node =& $this->getContentNode($a_hid, $a_pcid);
2942  $curr_node->unlink_node($curr_node);
2943  if ($a_update)
2944  {
2945  return $this->update();
2946  }
2947  }
2948 
2949 
2957  function deleteContents($a_hids, $a_update = true, $a_self_ass = false)
2958  {
2959  if (!is_array($a_hids))
2960  {
2961  return;
2962  }
2963  foreach($a_hids as $a_hid)
2964  {
2965  $a_hid = explode(":", $a_hid);
2966 //echo "-".$a_hid[0]."-".$a_hid[1]."-";
2967 
2968 // @todo 1: hook
2969  // do not delete question nodes in assessment pages
2970  if (!$this->checkForTag("Question", $a_hid[0], $a_hid[1]) || $a_self_ass)
2971  {
2972  $curr_node =& $this->getContentNode($a_hid[0], $a_hid[1]);
2973  if (is_object($curr_node))
2974  {
2975  $parent_node = $curr_node->parent_node();
2976  if ($parent_node->node_name() != "TableRow")
2977  {
2978  $curr_node->unlink_node($curr_node);
2979  }
2980  }
2981  }
2982  }
2983  if ($a_update)
2984  {
2985  return $this->update();
2986  }
2987  }
2988 
2994  function cutContents($a_hids)
2995  {
2996  $this->copyContents($a_hids);
2997  return $this->deleteContents($a_hids);
2998  }
2999 
3005  function copyContents($a_hids)
3006  {
3007  global $ilUser;
3008 //var_dump($a_hids);
3009  if (!is_array($a_hids))
3010  {
3011  return;
3012  }
3013 
3014  $time = date("Y-m-d H:i:s", time());
3015 
3016  $hier_ids = array();
3017  $skip = array();
3018  foreach($a_hids as $a_hid)
3019  {
3020  if ($a_hid == "")
3021  {
3022  continue;
3023  }
3024  $a_hid = explode(":", $a_hid);
3025 
3026  // check, whether new hid is child of existing one or vice versa
3027  reset($hier_ids);
3028  foreach($hier_ids as $h)
3029  {
3030  if($h."_" == substr($a_hid[0], 0, strlen($h) + 1))
3031  {
3032  $skip[] = $a_hid[0];
3033  }
3034  if($a_hid[0]."_" == substr($h, 0, strlen($a_hid[0]) + 1))
3035  {
3036  $skip[] = $h;
3037  }
3038  }
3039  $pc_id[$a_hid[0]] = $a_hid[1];
3040  if ($a_hid[0] != "")
3041  {
3042  $hier_ids[$a_hid[0]] = $a_hid[0];
3043  }
3044  }
3045  foreach ($skip as $s)
3046  {
3047  unset($hier_ids[$s]);
3048  }
3049  include_once("./Services/COPage/classes/class.ilPageContent.php");
3050  $hier_ids = ilPageContent::sortHierIds($hier_ids);
3051  $nr = 1;
3052  foreach($hier_ids as $hid)
3053  {
3054  $curr_node = $this->getContentNode($hid, $pc_id[$hid]);
3055  if (is_object($curr_node))
3056  {
3057  if ($curr_node->node_name() == "PageContent")
3058  {
3059  $content = $this->dom->dump_node($curr_node);
3060  // remove pc and hier ids
3061  $content = eregi_replace("PCID=\"[a-z0-9]*\"","",$content);
3062  $content = eregi_replace("HierId=\"[a-z0-9_]*\"","",$content);
3063 
3064  $ilUser->addToPCClipboard($content, $time, $nr);
3065  $nr++;
3066  }
3067  }
3068  }
3069  include_once("./Modules/LearningModule/classes/class.ilEditClipboard.php");
3071  }
3072 
3076  function pasteContents($a_hier_id, $a_self_ass = false)
3077  {
3078  global $ilUser;
3079 
3080  $a_hid = explode(":", $a_hier_id);
3081  $content = $ilUser->getPCClipboardContent();
3082 
3083  // we insert from last to first, because we insert all at the
3084  // same hier_id
3085  for ($i = count($content) - 1; $i >= 0; $i--)
3086  {
3087 
3088  $c = $content[$i];
3089  $temp_dom = domxml_open_mem('<?xml version="1.0" encoding="UTF-8"?>'.$c,
3090  DOMXML_LOAD_PARSING, $error);
3091  if(empty($error))
3092  {
3093  $this->handleCopiedContent($temp_dom, $a_self_ass);
3094  $xpc = xpath_new_context($temp_dom);
3095  $path = "//PageContent";
3096  $res = xpath_eval($xpc, $path);
3097  if (count($res->nodeset) > 0)
3098  {
3099  $new_pc_node = $res->nodeset[0];
3100  $cloned_pc_node = $new_pc_node->clone_node (true);
3101  $cloned_pc_node->unlink_node ($cloned_pc_node);
3102  $this->insertContentNode ($cloned_pc_node, $a_hid[0],
3103  IL_INSERT_AFTER, $a_hid[1]);
3104  }
3105  }
3106  else
3107  {
3108 //var_dump($error);
3109  }
3110  }
3111  $e = $this->update();
3112 //var_dump($e);
3113  }
3114 
3118  function switchEnableMultiple($a_hids, $a_update = true, $a_self_ass = false)
3119  {
3120  if (!is_array($a_hids))
3121  {
3122  return;
3123  }
3124  $obj = & $this->content_obj;
3125 
3126  foreach($a_hids as $a_hid)
3127  {
3128  $a_hid = explode(":", $a_hid);
3129  $curr_node =& $this->getContentNode($a_hid[0], $a_hid[1]);
3130  if (is_object($curr_node))
3131  {
3132  if ($curr_node->node_name() == "PageContent")
3133  {
3134  $cont_obj =& $this->getContentObject($a_hid[0], $a_hid[1]);
3135  if ($cont_obj->isEnabled ())
3136  {
3137  // do not deactivate question nodes in assessment pages
3138  if (!$this->checkForTag("Question", $a_hid[0], $a_hid[1]) || $a_self_ass)
3139  {
3140  $cont_obj->disable();
3141  }
3142  }
3143  else
3144  {
3145  $cont_obj->enable();
3146  }
3147  }
3148  }
3149  }
3150 
3151  if ($a_update)
3152  {
3153  return $this->update();
3154  }
3155  }
3156 
3157 
3165  function deleteContentFromHierId($a_hid, $a_update = true)
3166  {
3167  $hier_ids = $this->getHierIds();
3168 
3169  // iterate all hierarchical ids
3170  foreach ($hier_ids as $hier_id)
3171  {
3172  // delete top level nodes only
3173  if (!is_int(strpos($hier_id, "_")))
3174  {
3175  if ($hier_id != "pg" && $hier_id >= $a_hid)
3176  {
3177  $curr_node =& $this->getContentNode($hier_id);
3178  $curr_node->unlink_node($curr_node);
3179  }
3180  }
3181  }
3182  if ($a_update)
3183  {
3184  return $this->update();
3185  }
3186  }
3187 
3195  function deleteContentBeforeHierId($a_hid, $a_update = true)
3196  {
3197  $hier_ids = $this->getHierIds();
3198 
3199  // iterate all hierarchical ids
3200  foreach ($hier_ids as $hier_id)
3201  {
3202  // delete top level nodes only
3203  if (!is_int(strpos($hier_id, "_")))
3204  {
3205  if ($hier_id != "pg" && $hier_id < $a_hid)
3206  {
3207  $curr_node =& $this->getContentNode($hier_id);
3208  $curr_node->unlink_node($curr_node);
3209  }
3210  }
3211  }
3212  if ($a_update)
3213  {
3214  return $this->update();
3215  }
3216  }
3217 
3218 
3226  function _moveContentAfterHierId(&$a_source_page, &$a_target_page, $a_hid)
3227  {
3228  $hier_ids = $a_source_page->getHierIds();
3229 
3230  $copy_ids = array();
3231 
3232  // iterate all hierarchical ids
3233  foreach ($hier_ids as $hier_id)
3234  {
3235  // move top level nodes only
3236  if (!is_int(strpos($hier_id, "_")))
3237  {
3238  if ($hier_id != "pg" && $hier_id >= $a_hid)
3239  {
3240  $copy_ids[] = $hier_id;
3241  }
3242  }
3243  }
3244  asort($copy_ids);
3245 
3246  $parent_node =& $a_target_page->getContentNode("pg");
3247  $target_dom =& $a_target_page->getDom();
3248  $parent_childs =& $parent_node->child_nodes();
3249  $cnt_parent_childs = count($parent_childs);
3250 //echo "-$cnt_parent_childs-";
3251  $first_child =& $parent_childs[0];
3252  foreach($copy_ids as $copy_id)
3253  {
3254  $source_node =& $a_source_page->getContentNode($copy_id);
3255 
3256  $new_node =& $source_node->clone_node(true);
3257  $new_node->unlink_node($new_node);
3258 
3259  $source_node->unlink_node($source_node);
3260 
3261  if($cnt_parent_childs == 0)
3262  {
3263  $new_node =& $parent_node->append_child($new_node);
3264  }
3265  else
3266  {
3267  //$target_dom->import_node($new_node);
3268  $new_node =& $first_child->insert_before($new_node, $first_child);
3269  }
3270  $parent_childs =& $parent_node->child_nodes();
3271 
3272  //$cnt_parent_childs++;
3273  }
3274 
3275  $a_target_page->update();
3276  $a_source_page->update();
3277 
3278  }
3279 
3283  function insertContent(&$a_cont_obj, $a_pos, $a_mode = IL_INSERT_AFTER, $a_pcid = "")
3284  {
3285 //echo "-".$a_pos."-".$a_pcid."-";
3286  // move mode into container elements is always INSERT_CHILD
3287  $curr_node = $this->getContentNode($a_pos, $a_pcid);
3288  $curr_name = $curr_node->node_name();
3289 
3290  // @todo: try to generalize this
3291  if (($curr_name == "TableData") || ($curr_name == "PageObject") ||
3292  ($curr_name == "ListItem") || ($curr_name == "Section")
3293  || ($curr_name == "Tab") || ($curr_name == "ContentPopup"))
3294  {
3295  $a_mode = IL_INSERT_CHILD;
3296  }
3297 
3298  $hid = $curr_node->get_attribute("HierId");
3299  if ($hid != "")
3300  {
3301 //echo "-".$a_pos."-".$hid."-";
3302  $a_pos = $hid;
3303  }
3304 
3305  if($a_mode != IL_INSERT_CHILD) // determine parent hierarchical id
3306  { // of sibling at $a_pos
3307  $pos = explode("_", $a_pos);
3308  $target_pos = array_pop($pos);
3309  $parent_pos = implode($pos, "_");
3310  }
3311  else // if we should insert a child, $a_pos is alreade the hierarchical id
3312  { // of the parent node
3313  $parent_pos = $a_pos;
3314  }
3315 
3316  // get the parent node
3317  if($parent_pos != "")
3318  {
3319  $parent_node =& $this->getContentNode($parent_pos);
3320  }
3321  else
3322  {
3323  $parent_node =& $this->getNode();
3324  }
3325 
3326  // count the parent children
3327  $parent_childs =& $parent_node->child_nodes();
3328  $cnt_parent_childs = count($parent_childs);
3329 //echo "ZZ$a_mode";
3330  switch ($a_mode)
3331  {
3332  // insert new node after sibling at $a_pos
3333  case IL_INSERT_AFTER:
3334  $new_node =& $a_cont_obj->getNode();
3335  //$a_pos = ilPageContent::incEdId($a_pos);
3336  //$curr_node =& $this->getContentNode($a_pos);
3337 //echo "behind $a_pos:";
3338  if($succ_node =& $curr_node->next_sibling())
3339  {
3340  $new_node =& $succ_node->insert_before($new_node, $succ_node);
3341  }
3342  else
3343  {
3344 //echo "movin doin append_child";
3345  $new_node =& $parent_node->append_child($new_node);
3346  }
3347  $a_cont_obj->setNode($new_node);
3348  break;
3349 
3350  case IL_INSERT_BEFORE:
3351 //echo "INSERT_BEF";
3352  $new_node =& $a_cont_obj->getNode();
3353  $succ_node =& $this->getContentNode($a_pos);
3354  $new_node =& $succ_node->insert_before($new_node, $succ_node);
3355  $a_cont_obj->setNode($new_node);
3356  break;
3357 
3358  // insert new node as first child of parent $a_pos (= $a_parent)
3359  case IL_INSERT_CHILD:
3360 //echo "insert as child:parent_childs:$cnt_parent_childs:<br>";
3361  $new_node =& $a_cont_obj->getNode();
3362  if($cnt_parent_childs == 0)
3363  {
3364  $new_node =& $parent_node->append_child($new_node);
3365  }
3366  else
3367  {
3368  $new_node =& $parent_childs[0]->insert_before($new_node, $parent_childs[0]);
3369  }
3370  $a_cont_obj->setNode($new_node);
3371 //echo "PP";
3372  break;
3373  }
3374 
3375  //check for PlaceHolder to remove in EditMode-keep in Layout Mode
3376  if (!$this->getPageConfig()->getEnablePCType("PlaceHolder")) {
3377  $sub_nodes = $curr_node->child_nodes() ;
3378  foreach ( $sub_nodes as $sub_node ) {
3379  if ($sub_node->node_name() == "PlaceHolder") {
3380  $curr_node->unlink_node();
3381  }
3382  }
3383  }
3384  }
3385 
3389  function insertContentNode(&$a_cont_node, $a_pos, $a_mode = IL_INSERT_AFTER, $a_pcid = "")
3390  {
3391  // move mode into container elements is always INSERT_CHILD
3392  $curr_node = $this->getContentNode($a_pos, $a_pcid);
3393  $curr_name = $curr_node->node_name();
3394 
3395  // @todo: try to generalize
3396  if (($curr_name == "TableData") || ($curr_name == "PageObject") ||
3397  ($curr_name == "ListItem") || ($curr_name == "Section")
3398  || ($curr_name == "Tab") || ($curr_name == "ContentPopup"))
3399  {
3400  $a_mode = IL_INSERT_CHILD;
3401  }
3402 
3403  $hid = $curr_node->get_attribute("HierId");
3404  if ($hid != "")
3405  {
3406  $a_pos = $hid;
3407  }
3408 
3409  if($a_mode != IL_INSERT_CHILD) // determine parent hierarchical id
3410  { // of sibling at $a_pos
3411  $pos = explode("_", $a_pos);
3412  $target_pos = array_pop($pos);
3413  $parent_pos = implode($pos, "_");
3414  }
3415  else // if we should insert a child, $a_pos is alreade the hierarchical id
3416  { // of the parent node
3417  $parent_pos = $a_pos;
3418  }
3419 
3420  // get the parent node
3421  if($parent_pos != "")
3422  {
3423  $parent_node =& $this->getContentNode($parent_pos);
3424  }
3425  else
3426  {
3427  $parent_node =& $this->getNode();
3428  }
3429 
3430  // count the parent children
3431  $parent_childs =& $parent_node->child_nodes();
3432  $cnt_parent_childs = count($parent_childs);
3433 
3434  switch ($a_mode)
3435  {
3436  // insert new node after sibling at $a_pos
3437  case IL_INSERT_AFTER:
3438  //$new_node =& $a_cont_obj->getNode();
3439  if($succ_node = $curr_node->next_sibling())
3440  {
3441  $a_cont_node = $succ_node->insert_before($a_cont_node, $succ_node);
3442  }
3443  else
3444  {
3445  $a_cont_node = $parent_node->append_child($a_cont_node);
3446  }
3447  //$a_cont_obj->setNode($new_node);
3448  break;
3449 
3450  case IL_INSERT_BEFORE:
3451  //$new_node =& $a_cont_obj->getNode();
3452  $succ_node = $this->getContentNode($a_pos);
3453  $a_cont_node = $succ_node->insert_before($a_cont_node, $succ_node);
3454  //$a_cont_obj->setNode($new_node);
3455  break;
3456 
3457  // insert new node as first child of parent $a_pos (= $a_parent)
3458  case IL_INSERT_CHILD:
3459  //$new_node =& $a_cont_obj->getNode();
3460  if($cnt_parent_childs == 0)
3461  {
3462  $a_cont_node = $parent_node->append_child($a_cont_node);
3463  }
3464  else
3465  {
3466  $a_cont_node = $parent_childs[0]->insert_before($a_cont_node, $parent_childs[0]);
3467  }
3468  //$a_cont_obj->setNode($new_node);
3469  break;
3470  }
3471  }
3472 
3477  function moveContentBefore($a_source, $a_target, $a_spcid = "", $a_tpcid = "")
3478  {
3479  if($a_source == $a_target)
3480  {
3481  return;
3482  }
3483 
3484  // clone the node
3485  $content =& $this->getContentObject($a_source, $a_spcid);
3486  $source_node =& $content->getNode();
3487  $clone_node =& $source_node->clone_node(true);
3488 
3489  // delete source node
3490  $this->deleteContent($a_source, false, $a_spcid);
3491 
3492  // insert cloned node at target
3493  $content->setNode($clone_node);
3494  $this->insertContent($content, $a_target, IL_INSERT_BEFORE, $a_tpcid);
3495  return $this->update();
3496 
3497  }
3498 
3503  function moveContentAfter($a_source, $a_target, $a_spcid = "", $a_tpcid = "")
3504  {
3505  if($a_source == $a_target)
3506  {
3507  return;
3508  }
3509 
3510  // clone the node
3511  $content =& $this->getContentObject($a_source, $a_spcid);
3512  $source_node =& $content->getNode();
3513  $clone_node =& $source_node->clone_node(true);
3514 
3515  // delete source node
3516  $this->deleteContent($a_source, false, $a_spcid);
3517 
3518  // insert cloned node at target
3519  $content->setNode($clone_node);
3520  $this->insertContent($content, $a_target, IL_INSERT_AFTER, $a_tpcid);
3521  return $this->update();
3522  }
3523 
3527  // @todo: move to paragraph
3528  function bbCode2XML(&$a_content)
3529  {
3530  $a_content = eregi_replace("\[com\]","<Comment>",$a_content);
3531  $a_content = eregi_replace("\[\/com\]","</Comment>",$a_content);
3532  $a_content = eregi_replace("\[emp]","<Emph>",$a_content);
3533  $a_content = eregi_replace("\[\/emp\]","</Emph>",$a_content);
3534  $a_content = eregi_replace("\[str]","<Strong>",$a_content);
3535  $a_content = eregi_replace("\[\/str\]","</Strong>",$a_content);
3536  }
3537 
3542  function insertInstIntoIDs($a_inst, $a_res_ref_to_obj_id = true)
3543  {
3544  // insert inst id into internal links
3545  $xpc = xpath_new_context($this->dom);
3546  $path = "//IntLink";
3547  $res =& xpath_eval($xpc, $path);
3548  for($i = 0; $i < count($res->nodeset); $i++)
3549  {
3550  $target = $res->nodeset[$i]->get_attribute("Target");
3551  $type = $res->nodeset[$i]->get_attribute("Type");
3552 
3553  if (substr($target, 0, 4) == "il__")
3554  {
3555  $id = substr($target, 4, strlen($target) - 4);
3556 
3557  // convert repository links obj_<ref_id> to <type>_<obj_id>
3558  // this leads to bug 6685.
3559  if ($a_res_ref_to_obj_id && $type == "RepositoryItem")
3560  {
3561  $id_arr = explode("_", $id);
3562 
3563  // changed due to bug 6685
3564  $ref_id = $id_arr[1];
3565  $obj_id = ilObject::_lookupObjId($id_arr[1]);
3566 
3567  $otype = ilObject::_lookupType($obj_id);
3568  if ($obj_id > 0)
3569  {
3570  // changed due to bug 6685
3571  // the ref_id should be used, if the content is
3572  // imported on the same installation
3573  // the obj_id should be used, if a different
3574  // installation imports, but has an import_id for
3575  // the object id.
3576  $id = $otype."_".$obj_id."_".$ref_id;
3577  //$id = $otype."_".$ref_id;
3578  }
3579  }
3580  $new_target = "il_".$a_inst."_".$id;
3581  $res->nodeset[$i]->set_attribute("Target", $new_target);
3582  }
3583  }
3584  unset($xpc);
3585 
3586  // @todo: move to media/fileitems/questions, ...
3587 
3588  // insert inst id into media aliases
3589  $xpc = xpath_new_context($this->dom);
3590  $path = "//MediaAlias";
3591  $res =& xpath_eval($xpc, $path);
3592  for($i = 0; $i < count($res->nodeset); $i++)
3593  {
3594  $origin_id = $res->nodeset[$i]->get_attribute("OriginId");
3595  if (substr($origin_id, 0, 4) == "il__")
3596  {
3597  $new_id = "il_".$a_inst."_".substr($origin_id, 4, strlen($origin_id) - 4);
3598  $res->nodeset[$i]->set_attribute("OriginId", $new_id);
3599  }
3600  }
3601  unset($xpc);
3602 
3603  // insert inst id file item identifier entries
3604  $xpc = xpath_new_context($this->dom);
3605  $path = "//FileItem/Identifier";
3606  $res =& xpath_eval($xpc, $path);
3607  for($i = 0; $i < count($res->nodeset); $i++)
3608  {
3609  $origin_id = $res->nodeset[$i]->get_attribute("Entry");
3610  if (substr($origin_id, 0, 4) == "il__")
3611  {
3612  $new_id = "il_".$a_inst."_".substr($origin_id, 4, strlen($origin_id) - 4);
3613  $res->nodeset[$i]->set_attribute("Entry", $new_id);
3614  }
3615  }
3616  unset($xpc);
3617 
3618  // insert inst id into question references
3619  $xpc = xpath_new_context($this->dom);
3620  $path = "//Question";
3621  $res =& xpath_eval($xpc, $path);
3622  for($i = 0; $i < count($res->nodeset); $i++)
3623  {
3624  $qref = $res->nodeset[$i]->get_attribute("QRef");
3625 //echo "<br>setted:".$qref;
3626  if (substr($qref, 0, 4) == "il__")
3627  {
3628  $new_id = "il_".$a_inst."_".substr($qref, 4, strlen($qref) - 4);
3629 //echo "<br>setting:".$new_id;
3630  $res->nodeset[$i]->set_attribute("QRef", $new_id);
3631  }
3632  }
3633  unset($xpc);
3634 
3635  }
3636 
3640 // @todo begin: move to code/paraghraph
3641  function highlightText($a_text, $proglang, $autoindent)
3642  {
3643 
3644  if (!$this->hasHighlighter($proglang)) {
3645  $proglang="plain";
3646  }
3647 
3648  require_once("./Services/COPage/syntax_highlight/php/HFile/HFile_".$proglang.".php");
3649  $classname = "HFile_$proglang";
3650  $h_instance = new $classname();
3651  if ($autoindent == "n") {
3652  $h_instance ->notrim = 1;
3653  $h_instance ->indent = array ("");
3654  $h_instance ->unindent = array ("");
3655  }
3656 
3657  $highlighter = new Core($h_instance, new Output_css());
3658  $a_text = $highlighter->highlight_text(html_entity_decode($a_text));
3659 
3660  return $a_text;
3661  }
3662 
3663  function hasHighlighter ($hfile_ext) {
3664  return file_exists ("Services/COPage/syntax_highlight/php/HFile/HFile_".$hfile_ext.".php");
3665  }
3666 
3672  function insertSourceCodeParagraphs($a_output, $outputmode = "presentation")
3673  {
3674  $xpc = xpath_new_context($this->dom);
3675  $path = "//Paragraph"; //"[@Characteristic = 'Code']";
3676  $res = & xpath_eval($xpc, $path);
3677  for($i = 0; $i < count($res->nodeset); $i++)
3678  {
3679  $context_node = $res->nodeset[$i];
3680  $char = $context_node->get_attribute('Characteristic');
3681 
3682  if ($char != "Code")
3683  continue;
3684 
3685  $n = $context_node->parent_node();
3686  $char = $context_node->get_attribute('Characteristic');
3687  $subchar = $context_node->get_attribute('SubCharacteristic');
3688  $showlinenumbers = $context_node->get_attribute('ShowLineNumbers');
3689  $downloadtitle = $context_node->get_attribute('DownloadTitle');
3690  $autoindent = $context_node->get_attribute('AutoIndent');
3691 
3692  $content = "";
3693 
3694  // get XML Content
3695  $childs = $context_node->child_nodes();
3696 
3697  for($j=0; $j<count($childs); $j++)
3698  {
3699  $content .= $this->dom->dump_node($childs[$j]);
3700  }
3701 
3702  while ($context_node->has_child_nodes ())
3703  {
3704  $node_del = $context_node->first_child ();
3705  $context_node->remove_child ($node_del);
3706  }
3707 
3708  $content = str_replace("<br />", "<br/>", utf8_decode($content) );
3709  $content = str_replace("<br/>", "\n", $content);
3710  $rownums = count(split ("\n",$content));
3711 
3712  $plain_content = html_entity_decode($content);
3713  $plain_content = preg_replace ("/\&#x([1-9a-f]{2});?/ise","chr (base_convert (\\1, 16, 10))",$plain_content);
3714  $plain_content = preg_replace ("/\&#(\d+);?/ise","chr (\\1)",$plain_content);
3715  $content = utf8_encode($this->highlightText($plain_content, $subchar, $autoindent));
3716 
3717  $content = str_replace("&amp;lt;", "&lt;", $content);
3718  $content = str_replace("&amp;gt;", "&gt;", $content);
3719 // $content = str_replace("&", "&amp;", $content);
3720 //var_dump($content);
3721  $rows = "<tr valign=\"top\">";
3722  $rownumbers = "";
3723  $linenumbers= "";
3724 
3725  //if we have to show line numbers
3726  if (strcmp($showlinenumbers,"y")==0)
3727  {
3728  $linenumbers = "<td nowrap=\"nowrap\" class=\"ilc_LineNumbers\" >";
3729  $linenumbers .= "<pre class=\"ilc_Code\">";
3730 
3731  for ($j=0; $j < $rownums; $j++)
3732  {
3733  $indentno = strlen($rownums) - strlen($j+1) + 2;
3734  $rownumeration = ($j+1);
3735  $linenumbers .= "<span class=\"ilc_LineNumber\">$rownumeration</span>";
3736  if ($j < $rownums-1)
3737  {
3738  $linenumbers .= "\n";
3739  }
3740  }
3741  $linenumbers .= "</pre>";
3742  $linenumbers .= "</td>";
3743  }
3744 
3745  $rows .= $linenumbers."<td class=\"ilc_Sourcecode\"><pre class=\"ilc_Code\">".$content."</pre></td>";
3746  $rows .= "</tr>";
3747 
3748  // fix for ie explorer which is not able to produce empty line feeds with <br /><br />;
3749  // workaround: add a space after each br.
3750  $newcontent = str_replace("\n", "<br/>",$rows);
3751  // fix for IE
3752  $newcontent = str_replace("<br/><br/>", "<br/> <br/>",$newcontent);
3753  // falls drei hintereinander...
3754  $newcontent = str_replace("<br/><br/>", "<br/> <br/>",$newcontent);
3755 
3756  // workaround for preventing template engine
3757  // from hiding paragraph text that is enclosed
3758  // in curly brackets (e.g. "{a}", see ilLMEditorGUI::executeCommand())
3759  $newcontent = str_replace("{", "&#123;", $newcontent);
3760  $newcontent = str_replace("}", "&#125;", $newcontent);
3761 
3762 //echo htmlentities($newcontent);
3763  $a_output = str_replace("[[[[[Code;".($i + 1)."]]]]]", $newcontent, $a_output);
3764 
3765  if ($outputmode != "presentation" && is_object($this->offline_handler)
3766  && trim($downloadtitle) != "")
3767  {
3768  // call code handler for offline versions
3769  $this->offline_handler->handleCodeParagraph ($this->id, $i + 1, $downloadtitle, $plain_content);
3770  }
3771  }
3772 
3773  return $a_output;
3774  }
3775 // @todo end
3776 
3780  function checkPCIds()
3781  {
3782  $this->builddom();
3783  $mydom = $this->dom;
3784 
3785  $sep = $path = "";
3786  foreach ($this->id_elements as $el)
3787  {
3788  $path.= $sep."//".$el."[not(@PCID)]";
3789  $sep = " | ";
3790  }
3791 
3792  $xpc = xpath_new_context($mydom);
3793  $res = & xpath_eval($xpc, $path);
3794 
3795  if (count ($res->nodeset) > 0)
3796  {
3797  return false;
3798  }
3799  return true;
3800  }
3801 
3808  function getAllPCIds()
3809  {
3810  $this->builddom();
3811  $mydom = $this->dom;
3812 
3813  $pcids = array();
3814 
3815  $sep = $path = "";
3816  foreach ($this->id_elements as $el)
3817  {
3818  $path.= $sep."//".$el."[@PCID]";
3819  $sep = " | ";
3820  }
3821 
3822  // get existing ids
3823  $xpc = xpath_new_context($mydom);
3824  $res = & xpath_eval($xpc, $path);
3825 
3826  for ($i = 0; $i < count ($res->nodeset); $i++)
3827  {
3828  $node = $res->nodeset[$i];
3829  $pcids[] = $node->get_attribute("PCID");
3830  }
3831  return $pcids;
3832  }
3833 
3840  function existsPCId($a_pc_id)
3841  {
3842  $this->builddom();
3843  $mydom = $this->dom;
3844 
3845  $pcids = array();
3846 
3847  $sep = $path = "";
3848  foreach ($this->id_elements as $el)
3849  {
3850  $path.= $sep."//".$el."[@PCID='".$a_pc_id."']";
3851  $sep = " | ";
3852  }
3853 
3854  // get existing ids
3855  $xpc = xpath_new_context($mydom);
3856  $res = & xpath_eval($xpc, $path);
3857  return (count($res->nodeset) > 0);
3858  }
3859 
3866  function generatePcId($a_pc_ids = false)
3867  {
3868  if ($a_pc_ids === false)
3869  {
3870  $a_pc_ids = $this->getAllPCIds();
3871  }
3872  $id = ilUtil::randomHash(10, $a_pc_ids);
3873  return $id;
3874  }
3875 
3876 
3880  function insertPCIds()
3881  {
3882  $this->builddom();
3883  $mydom = $this->dom;
3884 
3885  $pcids = $this->getAllPCIds();
3886 
3887  // add missing ones
3888  $sep = $path = "";
3889  foreach ($this->id_elements as $el)
3890  {
3891  $path.= $sep."//".$el."[not(@PCID)]";
3892  $sep = " | ";
3893  }
3894  $xpc = xpath_new_context($mydom);
3895  $res = & xpath_eval($xpc, $path);
3896 
3897  for ($i = 0; $i < count ($res->nodeset); $i++)
3898  {
3899  $node = $res->nodeset[$i];
3900  $id = ilUtil::randomHash(10, $pcids);
3901  $pcids[] = $id;
3902 //echo "setting-".$id."-";
3903  $res->nodeset[$i]->set_attribute("PCID", $id);
3904  }
3905  }
3906 
3911  {
3912  $this->builddom();
3913  $this->addHierIds();
3914  $mydom = $this->dom;
3915 
3916  // get existing ids
3917  $path = "//PageContent";
3918  $xpc = xpath_new_context($mydom);
3919  $res = & xpath_eval($xpc, $path);
3920 
3921  $hashes = array();
3922  require_once("./Services/COPage/classes/class.ilPCParagraph.php");
3923  for ($i = 0; $i < count ($res->nodeset); $i++)
3924  {
3925  $hier_id = $res->nodeset[$i]->get_attribute("HierId");
3926  $pc_id = $res->nodeset[$i]->get_attribute("PCID");
3927  $dump = $mydom->dump_node($res->nodeset[$i]);
3928  if (($hpos = strpos($dump, ' HierId="'.$hier_id.'"')) > 0)
3929  {
3930  $dump = substr($dump, 0, $hpos).
3931  substr($dump, $hpos + strlen(' HierId="'.$hier_id.'"'));
3932  }
3933 
3934  $childs = $res->nodeset[$i]->child_nodes();
3935  $content = "";
3936  if ($childs[0] && $childs[0]->node_name() == "Paragraph")
3937  {
3938  $content = $mydom->dump_node($childs[0]);
3939  $content = substr($content, strpos($content, ">") + 1,
3940  strrpos($content, "<") - (strpos($content, ">") + 1));
3941 //var_dump($content);
3942  $content = ilPCParagraph::xml2output($content);
3943 //var_dump($content);
3944  }
3945  //$hashes[$hier_id] =
3946  // array("PCID" => $pc_id, "hash" => md5($dump));
3947  $hashes[$pc_id] =
3948  array("hier_id" => $hier_id, "hash" => md5($dump), "content" => $content);
3949  }
3950 
3951  return $hashes;
3952  }
3953 
3957 // @todo: move to questions
3958  function getQuestionIds()
3959  {
3960  $this->builddom();
3961  $mydom = $this->dom;
3962 
3963  // Get question IDs
3964  $path = "//Question";
3965  $xpc = xpath_new_context($mydom);
3966  $res = & xpath_eval($xpc, $path);
3967 
3968  $q_ids = array();
3969  include_once("./Services/COPage/classes/class.ilInternalLink.php");
3970  for ($i = 0; $i < count ($res->nodeset); $i++)
3971  {
3972  $qref = $res->nodeset[$i]->get_attribute("QRef");
3973 
3974  $inst_id = ilInternalLink::_extractInstOfTarget($qref);
3975  $obj_id = ilInternalLink::_extractObjIdOfTarget($qref);
3976 
3977  if (!($inst_id > 0))
3978  {
3979  if ($obj_id > 0)
3980  {
3981  $q_ids[] = $obj_id;
3982  }
3983  }
3984  }
3985  return $q_ids;
3986  }
3987 
3988 // @todo: move to paragraph
3989  function send_paragraph ($par_id, $filename)
3990  {
3991  $this->builddom();
3992 
3993  $mydom = $this->dom;
3994 
3995  $xpc = xpath_new_context($mydom);
3996 
3997  //$path = "//PageContent[position () = $par_id]/Paragraph";
3998  //$path = "//Paragraph[$par_id]";
3999  $path = "/descendant::Paragraph[position() = $par_id]";
4000 
4001  $res = & xpath_eval($xpc, $path);
4002 
4003  if (count ($res->nodeset) != 1)
4004  die ("Should not happen");
4005 
4006  $context_node = $res->nodeset[0];
4007 
4008  // get plain text
4009 
4010  $childs = $context_node->child_nodes();
4011 
4012  for($j=0; $j<count($childs); $j++)
4013  {
4014  $content .= $mydom->dump_node($childs[$j]);
4015  }
4016 
4017  $content = str_replace("<br />", "\n", $content);
4018  $content = str_replace("<br/>", "\n", $content);
4019 
4020  $plain_content = html_entity_decode($content);
4021 
4022  ilUtil::deliverData($plain_content, $filename);
4023  /*
4024  $file_type = "application/octet-stream";
4025  header("Content-type: ".$file_type);
4026  header("Content-disposition: attachment; filename=\"$filename\"");
4027  echo $plain_content;*/
4028  exit();
4029  }
4030 
4034 // @todo: deprecated?
4035  function getFO()
4036  {
4037  $xml = $this->getXMLFromDom(false, true, true);
4038  $xsl = file_get_contents("./Services/COPage/xsl/page_fo.xsl");
4039  $args = array( '/_xml' => $xml, '/_xsl' => $xsl );
4040  $xh = xslt_create();
4041 
4042  $params = array ();
4043 
4044 
4045  $fo = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args, $params);
4046  var_dump($fo);
4047  // do some replacements
4048  $fo = str_replace("\n", "", $fo);
4049  $fo = str_replace("<br/>", "<br>", $fo);
4050  $fo = str_replace("<br>", "\n", $fo);
4051 
4052  xslt_free($xh);
4053 
4054  //
4055  $fo = substr($fo, strpos($fo,">") + 1);
4056 //echo "<br><b>fo:</b><br>".htmlentities($fo); flush();
4057  return $fo;
4058  }
4059 
4060  function registerOfflineHandler ($handler) {
4061  $this->offline_handler = $handler;
4062  }
4063 
4067  static function _lookupContainsDeactivatedElements($a_id, $a_parent_type, $a_lang = "-")
4068  {
4069  global $ilDB;
4070 
4071  if ($a_lang == "")
4072  {
4073  $a_lang = "-";
4074  }
4075 
4076  $query = "SELECT * FROM page_object WHERE page_id = ".
4077  $ilDB->quote($a_id, "integer")." AND ".
4078  " parent_type = ".$ilDB->quote($a_parent_type, "text")." AND ".
4079  " lang = ".$ilDB->quote($a_lang, "text")." AND ".
4080  " inactive_elements = ".$ilDB->quote(1, "integer");
4081  $obj_set = $ilDB->query($query);
4082 
4083  if ($obj_rec = $obj_set->fetchRow(DB_FETCHMODE_ASSOC))
4084  {
4085  return true;
4086  }
4087 
4088  return false;
4089  }
4090 
4097  function containsDeactivatedElements($a_content)
4098  {
4099  if (strpos($a_content, " Enabled=\"False\""))
4100  {
4101  return true;
4102  }
4103  return false;
4104  }
4105 
4110  {
4111  global $ilDB;
4112 
4113  $h_query = "SELECT * FROM page_history ".
4114  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4115  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4116  " AND lang = ".$ilDB->quote($this->getLanguage(), "text").
4117  " ORDER BY hdate DESC";
4118 
4119  $hset = $ilDB->query($h_query);
4120  $hentries = array();
4121 
4122  while ($hrec = $ilDB->fetchAssoc($hset))
4123  {
4124  $hrec["sortkey"] = (int) $hrec["nr"];
4125  $hrec["user"] = (int) $hrec["user_id"];
4126  $hentries[] = $hrec;
4127  }
4128 //var_dump($hentries);
4129  return $hentries;
4130  }
4131 
4135  function getHistoryEntry($a_old_nr)
4136  {
4137  global $ilDB;
4138 
4139  $res = $ilDB->queryF("SELECT * FROM page_history ".
4140  " WHERE page_id = %s ".
4141  " AND parent_type = %s ".
4142  " AND nr = %s".
4143  " AND lang = %s",
4144  array("integer", "text", "integer", "text"),
4145  array($this->getId(), $this->getParentType(), $a_old_nr, $this->getLanguage()));
4146  if ($hrec = $ilDB->fetchAssoc($res))
4147  {
4148  return $hrec;
4149  }
4150 
4151  return false;
4152  }
4153 
4154 
4161  function getHistoryInfo($a_nr)
4162  {
4163  global $ilDB;
4164 
4165  // determine previous entry
4166  $res = $ilDB->query("SELECT MAX(nr) mnr FROM page_history ".
4167  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4168  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4169  " AND lang = ".$ilDB->quote($this->getLanguage(), "text").
4170  " AND nr < ".$ilDB->quote((int) $a_nr, "integer"));
4171  $row = $ilDB->fetchAssoc($res);
4172  if ($row["mnr"] > 0)
4173  {
4174  $res = $ilDB->query("SELECT * FROM page_history ".
4175  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4176  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4177  " AND lang = ".$ilDB->quote($this->getLanguage(), "text").
4178  " AND nr = ".$ilDB->quote((int) $row["mnr"], "integer"));
4179  $row = $ilDB->fetchAssoc($res);
4180  $ret["previous"] = $row;
4181  }
4182 
4183  // determine next entry
4184  $res = $ilDB->query("SELECT MIN(nr) mnr FROM page_history ".
4185  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4186  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4187  " AND lang = ".$ilDB->quote($this->getLanguage(), "text").
4188  " AND nr > ".$ilDB->quote((int) $a_nr, "integer"));
4189  $row = $ilDB->fetchAssoc($res);
4190  if ($row["mnr"] > 0)
4191  {
4192  $res = $ilDB->query("SELECT * FROM page_history ".
4193  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4194  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4195  " AND lang = ".$ilDB->quote($this->getLanguage(), "text").
4196  " AND nr = ".$ilDB->quote((int) $row["mnr"], "integer"));
4197  $row = $ilDB->fetchAssoc($res);
4198  $ret["next"] = $row;
4199  }
4200 
4201  // current
4202  $res = $ilDB->query("SELECT * FROM page_history ".
4203  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4204  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4205  " AND lang = ".$ilDB->quote($this->getLanguage(), "text").
4206  " AND nr = ".$ilDB->quote((int) $a_nr, "integer"));
4207  $row = $ilDB->fetchAssoc($res);
4208  $ret["current"] = $row;
4209 
4210  return $ret;
4211  }
4212 
4213  function addChangeDivClasses($a_hashes)
4214  {
4215  $xpc = xpath_new_context($this->dom);
4216  $path = "/*[1]";
4217  $res =& xpath_eval($xpc, $path);
4218  $rnode = $res->nodeset[0];
4219 
4220 //echo "A";
4221  foreach($a_hashes as $pc_id => $h)
4222  {
4223 //echo "B";
4224  if ($h["change"] != "")
4225  {
4226 //echo "<br>C-".$h["hier_id"]."-".$h["change"]."-";
4227  $dc_node = $this->dom->create_element("DivClass");
4228  $dc_node->set_attribute("HierId", $h["hier_id"]);
4229  $dc_node->set_attribute("Class", "ilEdit".$h["change"]);
4230  $dc_node = $rnode->append_child($dc_node);
4231  }
4232  }
4233  }
4234 
4241  // @todo: hook?
4242  function compareVersion($a_left, $a_right)
4243  {
4244  global $ilDB;
4245 
4246  // get page objects
4247  include_once("./Services/COPage/classes/class.ilPageObjectFactory.php");
4248  $l_page = ilPageObjectFactory::getInstance($this->getParentType(), $this->getId(), $a_left);
4249  $r_page = ilPageObjectFactory::getInstance($this->getParentType(), $this->getId(), $a_right);
4250 
4251  $l_hashes = $l_page->getPageContentsHashes();
4252  $r_hashes = $r_page->getPageContentsHashes();
4253 
4254  // determine all deleted and changed page elements
4255  foreach ($l_hashes as $pc_id => $h)
4256  {
4257  if (!isset($r_hashes[$pc_id]))
4258  {
4259  $l_hashes[$pc_id]["change"] = "Deleted";
4260  }
4261  else
4262  {
4263  if ($l_hashes[$pc_id]["hash"] != $r_hashes[$pc_id]["hash"])
4264  {
4265  $l_hashes[$pc_id]["change"] = "Modified";
4266  $r_hashes[$pc_id]["change"] = "Modified";
4267 
4268  include_once("./Services/COPage/mediawikidiff/class.WordLevelDiff.php");
4269  // if modified element is a paragraph, highlight changes
4270  if ($l_hashes[$pc_id]["content"] != "" &&
4271  $r_hashes[$pc_id]["content"] != "")
4272  {
4273  $new_left = str_replace("\n", "<br />", $l_hashes[$pc_id]["content"]);
4274  $new_right = str_replace("\n", "<br />", $r_hashes[$pc_id]["content"]);
4275  $wldiff = new WordLevelDiff(array($new_left),
4276  array($new_right));
4277  $new_left = $wldiff->orig();
4278  $new_right = $wldiff->closing();
4279  $l_page->setParagraphContent($l_hashes[$pc_id]["hier_id"], $new_left[0]);
4280  $r_page->setParagraphContent($l_hashes[$pc_id]["hier_id"], $new_right[0]);
4281  }
4282  }
4283  }
4284  }
4285 
4286  // determine all new paragraphs
4287  foreach ($r_hashes as $pc_id => $h)
4288  {
4289  if (!isset($l_hashes[$pc_id]))
4290  {
4291  $r_hashes[$pc_id]["change"] = "New";
4292  }
4293  }
4294 
4295  $l_page->addChangeDivClasses($l_hashes);
4296  $r_page->addChangeDivClasses($r_hashes);
4297 
4298  return array("l_page" => $l_page, "r_page" => $r_page,
4299  "l_changes" => $l_hashes, "r_changes" => $r_hashes);
4300  }
4301 
4305  function increaseViewCnt()
4306  {
4307  global $ilDB;
4308 
4309  $ilDB->manipulate("UPDATE page_object ".
4310  " SET view_cnt = view_cnt + 1 ".
4311  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4312  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text").
4313  " AND lang = ".$ilDB->quote($this->getLanguage(), "text"));
4314  }
4315 
4323  static function getRecentChanges($a_parent_type, $a_parent_id, $a_period = 30, $a_lang = "")
4324  {
4325  global $ilDB;
4326 
4327  $and_lang = "";
4328  if ($a_lang != "")
4329  {
4330  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
4331  }
4332 
4333  $page_changes = array();
4334  $limit_ts = date('Y-m-d H:i:s', time() - ($a_period * 24 * 60 * 60));
4335  $q = "SELECT * FROM page_object ".
4336  " WHERE parent_id = ".$ilDB->quote($a_parent_id, "integer").
4337  " AND parent_type = ".$ilDB->quote($a_parent_type, "text").
4338  " AND last_change >= ".$ilDB->quote($limit_ts, "timestamp").$and_lang;
4339  // " AND (TO_DAYS(now()) - TO_DAYS(last_change)) <= ".((int)$a_period);
4340  $set = $ilDB->query($q);
4341  while($page = $ilDB->fetchAssoc($set))
4342  {
4343  $page_changes[] = array(
4344  "date" => $page["last_change"],
4345  "id" => $page["page_id"],
4346  "lang" => $page["lang"],
4347  "type" => "page",
4348  "user" => $page["last_change_user"]);
4349  }
4350 
4351  $and_str = "";
4352  if ($a_period > 0)
4353  {
4354  $limit_ts = date('Y-m-d H:i:s', time() - ($a_period * 24 * 60 * 60));
4355  $and_str = " AND hdate >= ".$ilDB->quote($limit_ts, "timestamp")." ";
4356  }
4357 
4358  $q = "SELECT * FROM page_history ".
4359  " WHERE parent_id = ".$ilDB->quote($a_parent_id, "integer").
4360  " AND parent_type = ".$ilDB->quote($a_parent_type, "text").
4361  $and_str.$and_lang;
4362  $set = $ilDB->query($q);
4363  while ($page = $ilDB->fetchAssoc($set))
4364  {
4365  $page_changes[] = array(
4366  "date" => $page["hdate"],
4367  "id" => $page["page_id"],
4368  "lang" => $page["lang"],
4369  "type" => "hist",
4370  "nr" => $page["nr"],
4371  "user" => $page["user_id"]);
4372  }
4373 
4374  $page_changes = ilUtil::sortArray($page_changes, "date", "desc");
4375 
4376  return $page_changes;
4377  }
4378 
4386  static function getAllPages($a_parent_type, $a_parent_id, $a_lang = "-")
4387  {
4388  global $ilDB;
4389 
4390  $and_lang = "";
4391  if ($a_lang != "")
4392  {
4393  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
4394  }
4395 
4396  $page_changes = array();
4397 
4398  $q = "SELECT * FROM page_object ".
4399  " WHERE parent_id = ".$ilDB->quote($a_parent_id, "integer").
4400  " AND parent_type = ".$ilDB->quote($a_parent_type, "text").$and_lang;
4401  $set = $ilDB->query($q);
4402  $pages = array();
4403  while ($page = $ilDB->fetchAssoc($set))
4404  {
4405  $key_add = ($a_lang == "")
4406  ? ":".$page["lang"]
4407  : "";
4408  $pages[$page["page_id"].$key_add] = array(
4409  "date" => $page["last_change"],
4410  "id" => $page["page_id"],
4411  "lang" => $page["lang"],
4412  "user" => $page["last_change_user"]);
4413  }
4414 
4415  return $pages;
4416  }
4417 
4424  static function getNewPages($a_parent_type, $a_parent_id, $a_lang = "-")
4425  {
4426  global $ilDB;
4427 
4428  $and_lang = "";
4429  if ($a_lang != "")
4430  {
4431  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
4432  }
4433 
4434  $pages = array();
4435 
4436  $q = "SELECT * FROM page_object ".
4437  " WHERE parent_id = ".$ilDB->quote($a_parent_id, "integer").
4438  " AND parent_type = ".$ilDB->quote($a_parent_type, "text").$and_lang.
4439  " ORDER BY created DESC";
4440  $set = $ilDB->query($q);
4441  while($page = $ilDB->fetchAssoc($set))
4442  {
4443  if ($page["created"] != "")
4444  {
4445  $pages[] = array(
4446  "created" => $page["created"],
4447  "id" => $page["page_id"],
4448  "lang" => $page["lang"],
4449  "user" => $page["create_user"],
4450  );
4451  }
4452  }
4453 
4454  return $pages;
4455  }
4456 
4463  static function getParentObjectContributors($a_parent_type, $a_parent_id, $a_lang = "-")
4464  {
4465  global $ilDB;
4466 
4467  $and_lang = "";
4468  if ($a_lang != "")
4469  {
4470  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
4471  }
4472 
4473  $contributors = array();
4474  $set = $ilDB->queryF("SELECT last_change_user, lang, page_id FROM page_object ".
4475  " WHERE parent_id = %s AND parent_type = %s ".
4476  " AND last_change_user != %s".$and_lang,
4477  array("integer", "text", "integer"),
4478  array($a_parent_id, $a_parent_type, 0));
4479 
4480  while ($page = $ilDB->fetchAssoc($set))
4481  {
4482  if ($a_lang == "")
4483  {
4484  $contributors[$page["last_change_user"]][$page["page_id"]][$page["lang"]] = 1;
4485  }
4486  else
4487  {
4488  $contributors[$page["last_change_user"]][$page["page_id"]] = 1;
4489  }
4490  }
4491 
4492  $set = $ilDB->queryF("SELECT count(DISTINCT page_id, parent_type, hdate, lang) as cnt, lang, page_id, user_id FROM page_history ".
4493  " WHERE parent_id = %s AND parent_type = %s AND user_id != %s ".$and_lang.
4494  " GROUP BY page_id, user_id, lang ",
4495  array("integer", "text", "integer"),
4496  array($a_parent_id, $a_parent_type, 0));
4497  while ($hpage = $ilDB->fetchAssoc($set))
4498  {
4499  if ($a_lang == "")
4500  {
4501  $contributors[$hpage["user_id"]][$hpage["page_id"]][$hpage["lang"]] =
4502  $contributors[$hpage["user_id"]][$hpage["page_id"]][$hpage["lang"]] + $hpage["cnt"];
4503  }
4504  else
4505  {
4506  $contributors[$hpage["user_id"]][$hpage["page_id"]] =
4507  $contributors[$hpage["user_id"]][$hpage["page_id"]] + $hpage["cnt"];
4508  }
4509  }
4510 
4511  $c = array();
4512  foreach ($contributors as $k => $co)
4513  {
4514  if (ilObject::_lookupType($k) == "usr")
4515  {
4516  $name = ilObjUser::_lookupName($k);
4517  $c[] = array("user_id" => $k, "pages" => $co,
4518  "lastname" => $name["lastname"], "firstname" => $name["firstname"]);
4519  }
4520  }
4521 
4522  return $c;
4523  }
4524 
4531  static function getPageContributors($a_parent_type, $a_page_id, $a_lang = "-")
4532  {
4533  global $ilDB;
4534 
4535  $and_lang = "";
4536  if ($a_lang != "")
4537  {
4538  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
4539  }
4540 
4541  $contributors = array();
4542  $set = $ilDB->queryF("SELECT last_change_user, lang FROM page_object ".
4543  " WHERE page_id = %s AND parent_type = %s ".
4544  " AND last_change_user != %s".$and_lang,
4545  array("integer", "text", "integer"),
4546  array($a_page_id, $a_parent_type, 0));
4547 
4548  while ($page = $ilDB->fetchAssoc($set))
4549  {
4550  if ($a_lang == "")
4551  {
4552  $contributors[$page["last_change_user"]][$page["lang"]] = 1;
4553  }
4554  else
4555  {
4556  $contributors[$page["last_change_user"]] = 1;
4557  }
4558  }
4559 
4560  $set = $ilDB->queryF("SELECT count(DISTINCT page_id, parent_type, hdate, lang) as cnt, lang, page_id, user_id FROM page_history ".
4561  " WHERE page_id = %s AND parent_type = %s AND user_id != %s ".$and_lang.
4562  " GROUP BY user_id, page_id, lang ",
4563  array("integer", "text", "integer"),
4564  array($a_page_id, $a_parent_type, 0));
4565  while ($hpage = $ilDB->fetchAssoc($set))
4566  {
4567  if ($a_lang == "")
4568  {
4569  $contributors[$hpage["user_id"]][$page["lang"]] =
4570  $contributors[$hpage["user_id"]][$page["lang"]] + $hpage["cnt"];
4571  }
4572  else
4573  {
4574  $contributors[$hpage["user_id"]] =
4575  $contributors[$hpage["user_id"]] + $hpage["cnt"];
4576  }
4577  }
4578 
4579  $c = array();
4580  foreach ($contributors as $k => $co)
4581  {
4582  $name = ilObjUser::_lookupName($k);
4583  $c[] = array("user_id" => $k, "pages" => $co,
4584  "lastname" => $name["lastname"], "firstname" => $name["firstname"]);
4585  }
4586 
4587  return $c;
4588  }
4589 
4593  function writeRenderedContent($a_content, $a_md5)
4594  {
4595  global $ilDB;
4596 
4597  $ilDB->update("page_object", array(
4598  "rendered_content" => array("clob", $a_content),
4599  "render_md5" => array("text", $a_md5),
4600  "rendered_time" => array("timestamp", ilUtil::now())
4601  ), array(
4602  "page_id" => array("integer", $this->getId()),
4603  "lang" => array("text", $this->getLanguage()),
4604  "parent_type" => array("text", $this->getParentType())
4605  ));
4606  }
4607 
4615  static function getPagesWithLinks($a_parent_type, $a_parent_id, $a_lang = "-")
4616  {
4617  global $ilDB;
4618 
4619  $page_changes = array();
4620 
4621  $and_lang = "";
4622  if ($a_lang != "")
4623  {
4624  $and_lang = " AND lang = ".$ilDB->quote($a_lang, "text");
4625  }
4626 
4627  $q = "SELECT * FROM page_object ".
4628  " WHERE parent_id = ".$ilDB->quote($a_parent_id, "integer").
4629  " AND parent_type = ".$ilDB->quote($a_parent_type, "text").
4630  " AND int_links = ".$ilDB->quote(1, "integer").$and_lang;
4631  $set = $ilDB->query($q);
4632  $pages = array();
4633  while ($page = $ilDB->fetchAssoc($set))
4634  {
4635  $key_add = ($a_lang == "")
4636  ? ":".$page["lang"]
4637  : "";
4638  $pages[$page["page_id"].$key_add] = array(
4639  "date" => $page["last_change"],
4640  "id" => $page["page_id"],
4641  "lang" => $page["lang"],
4642  "user" => $page["last_change_user"]);
4643  }
4644 
4645  return $pages;
4646  }
4647 
4654  function containsIntLinks($a_content)
4655  {
4656  if (strpos($a_content, "IntLink"))
4657  {
4658  return true;
4659  }
4660  return false;
4661  }
4662 
4667  {
4668  }
4669 
4675 // @todo begin: generalize
4676  function saveInitialOpenedContent($a_type, $a_id, $a_target)
4677  {
4678  $this->buildDom();
4679 
4680  switch($a_type)
4681  {
4682  case "media":
4683  $link_type = "MediaObject";
4684  $a_id = "il__mob_".$a_id;
4685  break;
4686 
4687  case "page":
4688  $link_type = "PageObject";
4689  $a_id = "il__pg_".$a_id;
4690  break;
4691 
4692  case "term":
4693  $link_type = "GlossaryItem";
4694  $a_id = "il__git_".$a_id;
4695  $a_target = "Glossary";
4696  break;
4697  }
4698 
4699  // if type or id missing -> delete InitOpenedContent, if existing
4700  if ($link_type == "" || $a_id == "")
4701  {
4702  $xpc = xpath_new_context($this->dom);
4703  $path = "//PageObject/InitOpenedContent";
4704  $res = xpath_eval($xpc, $path);
4705  if (count($res->nodeset) > 0)
4706  {
4707  $res->nodeset[0]->unlink_node($res->nodeset[0]);
4708  }
4709  }
4710  else
4711  {
4712  $xpc = xpath_new_context($this->dom);
4713  $path = "//PageObject/InitOpenedContent";
4714  $res = xpath_eval($xpc, $path);
4715  if (count($res->nodeset) > 0)
4716  {
4717  $init_node = $res->nodeset[0];
4718  $childs = $init_node->child_nodes();
4719  for($i = 0; $i < count($childs); $i++)
4720  {
4721  if ($childs[$i]->node_name() == "IntLink")
4722  {
4723  $il_node = $childs[$i];
4724  }
4725  }
4726  }
4727  else
4728  {
4729  $path = "//PageObject";
4730  $res = xpath_eval($xpc, $path);
4731  $page_node = $res->nodeset[0];
4732  $init_node = $this->dom->create_element("InitOpenedContent");
4733  $init_node = $page_node->append_child($init_node);
4734  $il_node = $this->dom->create_element("IntLink");
4735  $il_node = $init_node->append_child($il_node);
4736  }
4737  $il_node->set_attribute("Target", $a_id);
4738  $il_node->set_attribute("Type", $link_type);
4739  $il_node->set_attribute("TargetFrame", $a_target);
4740  }
4741 
4742  $ret = $this->update();
4743  }
4744 
4745 
4752  {
4753  $this->buildDom();
4754 
4755  $xpc = xpath_new_context($this->dom);
4756  $path = "//PageObject/InitOpenedContent";
4757  $res = xpath_eval($xpc, $path);
4758  $il_node = null;
4759  if (count($res->nodeset) > 0)
4760  {
4761  $init_node = $res->nodeset[0];
4762  $childs = $init_node->child_nodes();
4763  for($i = 0; $i < count($childs); $i++)
4764  {
4765  if ($childs[$i]->node_name() == "IntLink")
4766  {
4767  $il_node = $childs[$i];
4768  }
4769  }
4770  }
4771  if (!is_null($il_node))
4772  {
4773  $id = $il_node->get_attribute("Target");
4774  $link_type = $il_node->get_attribute("Type");
4775  $target = $il_node->get_attribute("TargetFrame");
4776 
4777  switch($link_type)
4778  {
4779  case "MediaObject":
4780  $type = "media";
4781  break;
4782 
4783  case "PageObject":
4784  $type = "page";
4785  break;
4786 
4787  case "GlossaryItem":
4788  $type = "term";
4789  break;
4790  }
4791  include_once("./Services/COPage/classes/class.ilInternalLink.php");
4793  return array("id" => $id, "type" => $type, "target" => $target);
4794  }
4795 
4796  return array();
4797  }
4798 // @todo end
4799 
4810  function beforePageContentUpdate($a_page_content)
4811  {
4812 
4813  }
4814 
4822  function copy($a_id, $a_parent_type = "", $a_parent_id = 0, $a_clone_mobs = false)
4823  {
4824  if ($a_parent_type == "")
4825  {
4826  $a_parent_type = $this->getParentType();
4827  if ($a_parent_id == 0)
4828  {
4829  $a_parent_id = $this->getParentId();
4830  }
4831  }
4832 
4833  include_once("./Services/COPage/classes/class.ilPageObjectFactory.php");
4834  foreach (self::lookupTranslations($this->getParentType(), $this->getId()) as $l)
4835  {
4836  $existed = false;
4837  $orig_page = ilPageObjectFactory::getInstance($this->getParentType(), $this->getId(), 0, $l);
4838  if (ilPageObject::_exists($a_parent_type, $a_id, $l))
4839  {
4840  $new_page_object = ilPageObjectFactory::getInstance($a_parent_type, $a_id, 0, $l);
4841  $existed = true;
4842  }
4843  else
4844  {
4845  $new_page_object = ilPageObjectFactory::getInstance($a_parent_type, 0, 0, $l);
4846  $new_page_object->setParentId($a_parent_id);
4847  $new_page_object->setId($a_id);
4848  }
4849  $new_page_object->setXMLContent($orig_page->copyXMLContent($a_clone_mobs));
4850  $new_page_object->setActive($orig_page->getActive());
4851  $new_page_object->setActivationStart($orig_page->getActivationStart());
4852  $new_page_object->setActivationEnd($orig_page->getActivationEnd());
4853  if ($existed)
4854  {
4855  $new_page_object->buildDom();
4856  $new_page_object->update();
4857  }
4858  else
4859  {
4860  $new_page_object->create();
4861  }
4862  }
4863 
4864  }
4865 
4873  static function lookupTranslations($a_parent_type, $a_id)
4874  {
4875  global $ilDB;
4876 
4877  $set = $ilDB->query("SELECT lang FROM page_object ".
4878  " WHERE page_id = ".$ilDB->quote($a_id, "integer").
4879  " AND parent_type = ".$ilDB->quote($a_parent_type, "text")
4880  );
4881  $langs = array();
4882  while ($rec = $ilDB->fetchAssoc($set))
4883  {
4884  $langs[] = $rec["lang"];
4885  }
4886  return $langs;
4887  }
4888 
4889 
4895  function copyPageToTranslation($a_target_lang)
4896  {
4897  $transl_page = ilPageObjectFactory::getInstance($this->getParentType(),
4898  0, 0, $a_target_lang);
4899  $transl_page->setId($this->getId());
4900  $transl_page->setParentId($this->getParentId());
4901  $transl_page->setXMLContent($this->copyXMLContent());
4902  $transl_page->setActive($this->getActive());
4903  $transl_page->setActivationStart($this->getActivationStart());
4904  $transl_page->setActivationEnd($this->getActivationEnd());
4905  $transl_page->create();
4906  }
4907 
4911 
4915  function getEditLock()
4916  {
4917  global $ilUser, $ilDB;
4918 
4919  $aset = new ilSetting("adve");
4920 
4921  $min = (int) $aset->get("block_mode_minutes") ;
4922  if ($min > 0)
4923  {
4924  // try to set the lock for the user
4925  $ts = time();
4926  $ilDB->manipulate("UPDATE page_object SET ".
4927  " edit_lock_user = ".$ilDB->quote($ilUser->getId(), "integer").",".
4928  " edit_lock_ts = ".$ilDB->quote($ts, "integer").
4929  " WHERE (edit_lock_user = ".$ilDB->quote($ilUser->getId(), "integer")." OR ".
4930  " edit_lock_ts < ".$ilDB->quote(time() - ($min * 60), "integer").") ".
4931  " AND page_id = ".$ilDB->quote($this->getId(), "integer").
4932  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text")
4933  );
4934 
4935  $set = $ilDB->query("SELECT edit_lock_user FROM page_object ".
4936  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4937  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text")
4938  );
4939  $rec = $ilDB->fetchAssoc($set);
4940  if ($rec["edit_lock_user"] != $ilUser->getId())
4941  {
4942  return false;
4943  }
4944  }
4945 
4946  return true;
4947  }
4948 
4952  function releasePageLock()
4953  {
4954  global $ilUser, $ilDB;
4955 
4956  $aset = new ilSetting("adve");
4957 
4958  $min = (int) $aset->get("block_mode_minutes") ;
4959  if ($min > 0)
4960  {
4961  // try to set the lock for the user
4962  $ts = time();
4963  $ilDB->manipulate("UPDATE page_object SET ".
4964  " edit_lock_user = ".$ilDB->quote($ilUser->getId(), "integer").",".
4965  " edit_lock_ts = 0".
4966  " WHERE edit_lock_user = ".$ilDB->quote($ilUser->getId(), "integer").
4967  " AND page_id = ".$ilDB->quote($this->getId(), "integer").
4968  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text")
4969  );
4970 
4971  $set = $ilDB->query("SELECT edit_lock_user FROM page_object ".
4972  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4973  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text")
4974  );
4975  $rec = $ilDB->fetchAssoc($set);
4976  if ($rec["edit_lock_user"] != $ilUser->getId())
4977  {
4978  return false;
4979  }
4980  }
4981 
4982  return true;
4983  }
4984 
4990  function getEditLockInfo()
4991  {
4992  global $ilDB;
4993 
4994  $aset = new ilSetting("adve");
4995  $min = (int) $aset->get("block_mode_minutes");
4996 
4997  $set = $ilDB->query("SELECT edit_lock_user, edit_lock_ts FROM page_object ".
4998  " WHERE page_id = ".$ilDB->quote($this->getId(), "integer").
4999  " AND parent_type = ".$ilDB->quote($this->getParentType(), "text")
5000  );
5001  $rec = $ilDB->fetchAssoc($set);
5002  $rec["edit_lock_until"] = $rec["edit_lock_ts"] + $min * 60;
5003 
5004  return $rec;
5005  }
5006 
5007 
5008 }
5009 ?>