ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilVirtualSkillTree.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
31 {
32  protected ilLanguage $lng;
33  protected ilSkillTree $tree;
34 
38  protected static ?array $order_node_data = null;
39  protected bool $include_drafts = false;
40 
44  protected array $drafts = [];
45  protected bool $include_outdated = false;
46 
50  protected array $outdated = [];
51 
52  public function __construct(int $tree_id)
53  {
54  global $DIC;
55 
56  $this->lng = $DIC->language();
57  $this->tree = $DIC->skills()->internal()->factory()->tree()->getTreeById($tree_id);
58  }
59 
63  public function getRootNode(): array
64  {
65  $root_id = $this->tree->readRootId();
66  $root_node = $this->tree->getNodeData($root_id);
67  unset($root_node["child"]);
68  $root_node["id"] = $root_id . ":0";
69  $root_node["cskill_id"] = $root_id . ":0";
70 
71  return $root_node;
72  }
73 
74  public function setIncludeDrafts(bool $a_val): void
75  {
76  $this->include_drafts = $a_val;
77  }
78 
79  public function getIncludeDrafts(): bool
80  {
81  return $this->include_drafts;
82  }
83 
84  public function setIncludeOutdated(bool $a_val): void
85  {
86  $this->include_outdated = $a_val;
87  }
88 
89  public function getIncludeOutdated(): bool
90  {
92  }
93 
94  public function getNode(string $a_vtree_id): array
95  {
96  $id_parts = explode(":", $a_vtree_id);
97  $skl_tree_id = (int) $id_parts[0];
98  $skl_template_tree_id = isset($id_parts[1]) ? (int) $id_parts[1] : 0;
99 
100  if ($skl_template_tree_id == 0
101  || (ilSkillTemplateReference::_lookupTemplateId($skl_tree_id) == $skl_template_tree_id)) {
102  $node_data = $this->tree->getNodeData($skl_tree_id);
103  if (isset($node_data["parent"])) {
104  $node_data["parent"] = $node_data["parent"] . ":0";
105  }
106  } else {
107  $node_data = $this->tree->getNodeData($skl_template_tree_id);
108  $node_data["parent"] = $skl_tree_id . ":" . $node_data["parent"];
109  }
110 
111  unset($node_data["child"]);
112  unset($node_data["skl_tree_id"]);
113  unset($node_data["lft"]);
114  unset($node_data["rgt"]);
115  unset($node_data["depth"]);
116 
117  $node_data["id"] = $a_vtree_id;
118  $cid = $this->getCSkillIdForVTreeId($a_vtree_id);
119  $cid_parts = explode(":", $cid);
120  $node_data["skill_id"] = $cid_parts[0];
121  $node_data["tref_id"] = $cid_parts[1];
122  $node_data["cskill_id"] = $cid;
123 
124  return $node_data;
125  }
126 
130  public function getChildsOfNode(string $a_parent_id): array
131  {
132  $a_parent_id_parts = explode(":", $a_parent_id);
133  $a_parent_skl_tree_id = (int) $a_parent_id_parts[0];
134  $a_parent_skl_template_tree_id = isset($a_parent_id_parts[1]) ? (int) $a_parent_id_parts[1] : 0;
135 
136  if ($a_parent_skl_template_tree_id == 0) {
137  $childs = $this->tree->getChildsByTypeFilter($a_parent_skl_tree_id, array("scat", "skll", "sktr"), "order_nr");
138  } else {
139  $childs = $this->tree->getChildsByTypeFilter($a_parent_skl_template_tree_id, array("sktp", "sctp"), "order_nr");
140  }
141 
142  $drafts = [];
143  $outdated = [];
144  foreach ($childs as $k => $c) {
145  if ($a_parent_skl_template_tree_id > 0) {
146  // we are in template tree only
147  $child_id = $a_parent_skl_tree_id . ":" . $c["child"];
148  } elseif (!in_array($c["type"], array("sktr", "sctr"))) {
149  // we are in main tree only
150  $child_id = $c["child"] . ":0";
151  } else {
152  // get template id for references
153  $child_id = $c["child"] . ":" . ilSkillTemplateReference::_lookupTemplateId((int) $c["child"]);
154  }
155  unset($childs[$k]["child"]);
156  unset($childs[$k]["skl_tree_id"]);
157  unset($childs[$k]["lft"]);
158  unset($childs[$k]["rgt"]);
159  unset($childs[$k]["depth"]);
160  $childs[$k]["id"] = $child_id;
161  $cid = $this->getCSkillIdForVTreeId($child_id);
162  $cid_parts = explode(":", $cid);
163  $childs[$k]["skill_id"] = $cid_parts[0];
164  $childs[$k]["tref_id"] = $cid_parts[1];
165  $childs[$k]["cskill_id"] = $cid;
166  $childs[$k]["parent"] = $a_parent_id;
167 
168  // @todo: prepare this for tref id?
170  in_array($a_parent_id, $this->drafts)) {
171  $this->drafts[] = $child_id;
172  $drafts[] = $k;
173  }
175  in_array($a_parent_id, $this->outdated)) {
176  $this->outdated[] = $child_id;
177  $outdated[] = $k;
178  }
179  }
180  if (!$this->getIncludeDrafts()) {
181  foreach ($drafts as $d) {
182  unset($childs[$d]);
183  }
184  }
185  if (!$this->getIncludeOutdated()) {
186  foreach ($outdated as $d) {
187  unset($childs[$d]);
188  }
189  }
190 
191  return $childs;
192  }
193 
194  public function getChildsOfNodeForCSkillId(string $a_cskill_id): array
195  {
196  $id_parts = explode(":", $a_cskill_id);
197  if (!isset($id_parts[1]) || $id_parts[1] == 0) {
198  $id = $id_parts[0] . ":0";
199  } else {
200  $id = $id_parts[1] . ":" . $id_parts[0];
201  }
202  return $this->getChildsOfNode($id);
203  }
204 
205  public function getCSkillIdForVTreeId(string $a_vtree_id): string
206  {
207  $id_parts = explode(":", $a_vtree_id);
208  if (!isset($id_parts[1]) || $id_parts[1] == 0) {
209  // skill in main tree
210  $skill_id = $id_parts[0];
211  $tref_id = 0;
212  } else {
213  // skill in template
214  $tref_id = $id_parts[0];
215  $skill_id = $id_parts[1];
216  }
217  return $skill_id . ":" . $tref_id;
218  }
219 
220  public function getVTreeIdForCSkillId(string $a_cskill_id): string
221  {
222  $id_parts = explode(":", $a_cskill_id);
223  if (!isset($id_parts[1]) || $id_parts[1] == 0) {
224  $id = $id_parts[0] . ":0";
225  } else {
226  $id = $id_parts[1] . ":" . $id_parts[0];
227  }
228  return $id;
229  }
230 
231  public function getNodeTitle(array $a_node): string
232  {
233  $lng = $this->lng;
234 
235  $a_parent_id_parts = explode(":", $a_node["id"]);
236  $a_parent_skl_tree_id = (int) $a_parent_id_parts[0];
237  $a_parent_skl_template_tree_id = isset($a_parent_id_parts[1]) ? (int) $a_parent_id_parts[1] : 0;
238 
239  // title
240  $title = $a_node["title"];
241 
242  // root?
243  if ($a_node["type"] == "skrt") {
244  $lng->txt("skmg_skills");
245  } elseif ($a_node["type"] == "sktr") {
246  // $title.= " (".ilSkillTreeNode::_lookupTitle($a_parent_skl_template_tree_id).")";
247  }
248 
249  return $title;
250  }
251 
255  public function getSubTreeForCSkillId(string $a_cskill_id, bool $a_only_basic = false): array
256  {
257  $id_parts = explode(":", $a_cskill_id);
258  if (!isset($id_parts[1]) || $id_parts[1] == 0) {
259  $id = $id_parts[0] . ":0";
260  } else {
261  $id = $id_parts[1] . ":" . $id_parts[0];
262  }
263 
264  $result = [];
265 
266  $node = $this->getNode($id);
267  if (!$a_only_basic || isset($node["type"]) && in_array($node["type"], array("skll", "sktp")) ||
268  (isset($node["type"]) && $node["type"] == "sktr" && ilSkillTreeNode::_lookupType((int) $node["skill_id"]) == "sktp")) {
269  $result[] = $node;
270  }
271  return array_merge($result, $this->__getSubTreeRec($id, $a_only_basic));
272  }
273 
277  protected function __getSubTreeRec(string $id, bool $a_only_basic): array
278  {
279  $result = [];
280  $childs = $this->getChildsOfNode($id);
281  foreach ($childs as $c) {
282  if (!$a_only_basic || in_array($c["type"], array("skll", "sktp")) ||
283  ($c["type"] == "sktr" && ilSkillTreeNode::_lookupType((int) $c["skill_id"]) == "sktp")) {
284  $result[] = $c;
285  }
286  $result = array_merge($result, $this->__getSubTreeRec($c["id"], $a_only_basic));
287  }
288 
289  return $result;
290  }
291 
292  public function isDraft(string $a_node_id): bool
293  {
294  return in_array($a_node_id, $this->drafts);
295  }
296 
297  public function isOutdated(string $a_node_id): bool
298  {
299  return in_array($a_node_id, $this->outdated);
300  }
301 
310  public function getOrderedNodeset(array $c_skill_ids, string $a_skill_id_key = "", string $a_tref_id_key = ""): array
311  {
312  global $DIC;
313 
314  $db = $DIC->database();
315 
316  if (self::$order_node_data == null) {
317  $node_data = [];
318  $set = $db->query("SELECT t.child, t.parent, t.lft, n.order_nr FROM skl_tree t JOIN skl_tree_node n ON (t.child = n.obj_id)");
319  while ($rec = $db->fetchAssoc($set)) {
320  $node_data[(int) $rec["child"]] = array(
321  "parent" => null === $rec["parent"] ? null : (int) $rec["parent"],
322  "lft" => (int) $rec["lft"],
323  "order_nr" => (int) $rec["order_nr"],
324  );
325  }
326  self::$order_node_data = $node_data;
327  } else {
328  $node_data = self::$order_node_data;
329  }
330 
331  uasort($c_skill_ids, function ($a, $b) use ($node_data, $a_skill_id_key, $a_tref_id_key): int {
332  // normalize to cskill strings
333  if (is_array($a)) {
334  $cskilla = $a[$a_skill_id_key] . ":" . $a[$a_tref_id_key];
335  $cskillb = $b[$a_skill_id_key] . ":" . $b[$a_tref_id_key];
336  } else {
337  $cskilla = $a;
338  $cskillb = $b;
339  }
340 
341  // get vtree ids
342  $vida = explode(":", $this->getVTreeIdForCSkillId($cskilla));
343  $vidb = explode(":", $this->getVTreeIdForCSkillId($cskillb));
344 
345  $ua = $this->getFirstUncommonAncestors($vida[0], $vidb[0], $node_data);
346  if (is_array($ua) && isset($node_data[$ua[0]]) && isset($node_data[$ua[1]])) {
347  return ($node_data[$ua[0]]["order_nr"] - $node_data[$ua[1]]["order_nr"]);
348  }
349  // if we did not find a first uncommon ancestor, we are in the same node in the
350  // main tree, here, if we have tref ids, we let the template tree decide
351  if ($vida[1] > 0 && $vidb[1] > 0) {
352  $ua = $this->getFirstUncommonAncestors($vida[1], $vidb[1], $node_data);
353  if (is_array($ua) && isset($node_data[$ua[0]]) && isset($node_data[$ua[1]])) {
354  return ($node_data[$ua[0]]["order_nr"] - $node_data[$ua[1]]["order_nr"]);
355  }
356  }
357 
358  return 0;
359  });
360 
361  return $c_skill_ids;
362  }
363 
367  protected function getPath(string $a, array $node_data): array
368  {
369  $path[] = $a;
370  if (isset($node_data[$a]) && isset($node_data[$a]["parent"])) {
371  while ($node_data[$a]["parent"] != 0) {
372  $a = $node_data[$a]["parent"];
373  $path[] = $a;
374  }
375  }
376  return array_reverse($path);
377  }
378 
384  protected function getFirstUncommonAncestors(string $a, string $b, array $node_data)
385  {
386  $path_a = $this->getPath($a, $node_data);
387  $path_b = $this->getPath($b, $node_data);
388  foreach ($path_a as $k => $v) {
389  if ($v != $path_b[$k]) {
390  return array($v, $path_b[$k]);
391  }
392  }
393  return false;
394  }
395 }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupStatus(int $a_obj_id)
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$c
Definition: deliver.php:9
static _lookupType(int $a_obj_id)
getVTreeIdForCSkillId(string $a_cskill_id)
$path
Definition: ltiservices.php:30
getSubTreeForCSkillId(string $a_cskill_id, bool $a_only_basic=false)
getOrderedNodeset(array $c_skill_ids, string $a_skill_id_key="", string $a_tref_id_key="")
Get ordererd nodeset for common skill ids.
global $DIC
Definition: shib_login.php:25
isOutdated(string $a_node_id)
getNode(string $a_vtree_id)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:24
getFirstUncommonAncestors(string $a, string $b, array $node_data)
get first uncommon ancestors of $a and $b in $node_data
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
getCSkillIdForVTreeId(string $a_vtree_id)
__getSubTreeRec(string $id, bool $a_only_basic)
getChildsOfNodeForCSkillId(string $a_cskill_id)
getChildsOfNode(string $a_parent_id)
getPath(string $a, array $node_data)
get path in node data