1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4/**
5* Class ilGlossaryTerm
6*
7* @author Alex Killing <alex.killing@gmx.de>
8* @version $Id$
9*
10* @ingroup ModulesGlossary
11*/
12class ilGlossaryTerm
13{
14    /**
15     * @var ilDB
16     */
17    protected $db;
18
19    public $lng;
20    public $tpl;
21
22    public $id;
23    public $glossary;
24    public $term;
25    public $language;
26    public $glo_id;
27    public $import_id;
28
29    /**
30    * Constructor
31    * @access	public
32    */
33    public function __construct($a_id = 0)
34    {
35        global $DIC;
36
37        $this->db = $DIC->database();
38        $lng = $DIC->language();
39        $tpl = $DIC["tpl"];
40
41        $this->lng = $lng;
42        $this->tpl = $tpl;
43
44        $this->id = $a_id;
45        $this->type = "term";
46        if ($a_id != 0) {
47            $this->read();
48        }
49    }
50
51    /**
52    * read glossary term data
53    */
54    public function read()
55    {
56        $ilDB = $this->db;
57
58        $q = "SELECT * FROM glossary_term WHERE id = " .
59            $ilDB->quote($this->id, "integer");
60        $term_set = $ilDB->query($q);
61        $term_rec = $ilDB->fetchAssoc($term_set);
62
63        $this->setTerm($term_rec["term"]);
64        $this->setImportId($term_rec["import_id"]);
65        $this->setLanguage($term_rec["language"]);
66        $this->setGlossaryId($term_rec["glo_id"]);
67    }
68
69    /**
70    * get current term id for import id (static)
71    *
72    * @param	int		$a_import_id		import id
73    *
74    * @return	int		id
75    */
76    public static function _getIdForImportId($a_import_id)
77    {
78        global $DIC;
79
80        $ilDB = $DIC->database();
81
82        if ($a_import_id == "") {
83            return 0;
84        }
85
86        $q = "SELECT * FROM glossary_term WHERE import_id = " .
87            $ilDB->quote($a_import_id, "text") .
88            " ORDER BY create_date DESC";
89        $term_set = $ilDB->query($q);
90        while ($term_rec = $ilDB->fetchAssoc($term_set)) {
91            $glo_id = ilGlossaryTerm::_lookGlossaryID($term_rec["id"]);
92
93            $ref_ids = ilObject::_getAllReferences($glo_id);	// will be 0 if import of lm is in progress (new import)
94            if (count($ref_ids) == 0 || ilObject::_hasUntrashedReference($glo_id)) {
95                return $term_rec["id"];
96            }
97        }
98
99        return 0;
100    }
101
102
103    /**
104    * checks wether a glossary term with specified id exists or not
105    *
106    * @param	int		$id		id
107    *
108    * @return	boolean		true, if glossary term exists
109    */
110    public static function _exists($a_id)
111    {
112        global $DIC;
113
114        $ilDB = $DIC->database();
115
116        include_once("./Services/Link/classes/class.ilInternalLink.php");
117        if (is_int(strpos($a_id, "_"))) {
118            $a_id = ilInternalLink::_extractObjIdOfTarget($a_id);
119        }
120
121        $q = "SELECT * FROM glossary_term WHERE id = " .
122            $ilDB->quote($a_id, "integer");
123        $obj_set = $ilDB->query($q);
124        if ($obj_rec = $ilDB->fetchAssoc($obj_set)) {
125            return true;
126        } else {
127            return false;
128        }
129    }
130
131
132    /**
133    * set glossary term id (= glossary item id)
134    *
135    * @param	int		$a_id		glossary term id
136    */
137    public function setId($a_id)
138    {
139        $this->id = $a_id;
140    }
141
142
143    /**
144    * get term id (= glossary item id)
145    *
146    * @return	int		glossary term id
147    */
148    public function getId()
149    {
150        return $this->id;
151    }
152
153    /**
154    * set glossary object
155    *
156    * @param	object		$a_glossary		glossary object
157    */
158    public function setGlossary(&$a_glossary)
159    {
160        $this->glossary = $a_glossary;
161        $this->setGlossaryId($a_glossary->getId());
162    }
163
164
165    /**
166    * set glossary id
167    *
168    * @param	int		$a_glo_id		glossary id
169    */
170    public function setGlossaryId($a_glo_id)
171    {
172        $this->glo_id = $a_glo_id;
173    }
174
175
176    /**
177    * get glossary id
178    *
179    * @return	int		glossary id
180    */
181    public function getGlossaryId()
182    {
183        return $this->glo_id;
184    }
185
186
187    /**
188    * set term
189    *
190    * @param	string		$a_term		term
191    */
192    public function setTerm($a_term)
193    {
194        $this->term = $a_term;
195    }
196
197
198    /**
199    * get term
200    *
201    * @return	string		term
202    */
203    public function getTerm()
204    {
205        return $this->term;
206    }
207
208
209    /**
210    * set language
211    *
212    * @param	string		$a_language		two letter language code
213    */
214    public function setLanguage($a_language)
215    {
216        $this->language = $a_language;
217    }
218
219    /**
220    * get language
221    * @return	string		two letter language code
222    */
223    public function getLanguage()
224    {
225        return $this->language;
226    }
227
228
229    /**
230    * set import id
231    */
232    public function setImportId($a_import_id)
233    {
234        $this->import_id = $a_import_id;
235    }
236
237
238    /**
239    * get import id
240    */
241    public function getImportId()
242    {
243        return $this->import_id;
244    }
245
246
247    /**
248    * create new glossary term
249    */
250    public function create()
251    {
252        $ilDB = $this->db;
253
254        $this->setId($ilDB->nextId("glossary_term"));
255        $ilDB->manipulate("INSERT INTO glossary_term (id, glo_id, term, language, import_id, create_date, last_update)" .
256            " VALUES (" .
257            $ilDB->quote($this->getId(), "integer") . ", " .
258            $ilDB->quote($this->getGlossaryId(), "integer") . ", " .
259            $ilDB->quote($this->term, "text") . ", " .
260            $ilDB->quote($this->language, "text") . "," .
261            $ilDB->quote($this->getImportId(), "text") . "," .
262            $ilDB->now() . ", " .
263            $ilDB->now() . ")");
264    }
265
266
267    /**
268    * delete glossary term (and all its definition objects)
269    */
270    public function delete()
271    {
272        $ilDB = $this->db;
273
274        require_once("./Modules/Glossary/classes/class.ilGlossaryDefinition.php");
275        $defs = ilGlossaryDefinition::getDefinitionList($this->getId());
276        foreach ($defs as $def) {
277            $def_obj = new ilGlossaryDefinition($def["id"]);
278            $def_obj->delete();
279        }
280
281        // delete term references
282        include_once("./Modules/Glossary/classes/class.ilGlossaryTermReferences.php");
283        ilGlossaryTermReferences::deleteReferencesOfTerm($this->getId());
284
285        // delete glossary_term record
286        $ilDB->manipulate("DELETE FROM glossary_term " .
287            " WHERE id = " . $ilDB->quote($this->getId(), "integer"));
288    }
289
290
291    /**
292    * update glossary term
293    */
294    public function update()
295    {
296        $ilDB = $this->db;
297
298        $ilDB->manipulate("UPDATE glossary_term SET " .
299            " glo_id = " . $ilDB->quote($this->getGlossaryId(), "integer") . ", " .
300            " term = " . $ilDB->quote($this->getTerm(), "text") . ", " .
301            " import_id = " . $ilDB->quote($this->getImportId(), "text") . ", " .
302            " language = " . $ilDB->quote($this->getLanguage(), "text") . ", " .
303            " last_update = " . $ilDB->now() . " " .
304            " WHERE id = " . $ilDB->quote($this->getId(), "integer"));
305    }
306
307    /**
308    * get glossary id form term id
309    */
310    public static function _lookGlossaryID($term_id)
311    {
312        global $DIC;
313
314        $ilDB = $DIC->database();
315
316        $query = "SELECT * FROM glossary_term WHERE id = " .
317            $ilDB->quote($term_id, "integer");
318        $obj_set = $ilDB->query($query);
319        $obj_rec = $ilDB->fetchAssoc($obj_set);
320
321        return $obj_rec["glo_id"];
322    }
323
324    /**
325    * get glossary term
326    */
327    public static function _lookGlossaryTerm($term_id)
328    {
329        global $DIC;
330
331        $ilDB = $DIC->database();
332
333        $query = "SELECT * FROM glossary_term WHERE id = " .
334            $ilDB->quote($term_id, "integer");
335        $obj_set = $ilDB->query($query);
336        $obj_rec = $ilDB->fetchAssoc($obj_set);
337
338        return $obj_rec["term"];
339    }
340
341    /**
342    * lookup term language
343    */
344    public static function _lookLanguage($term_id)
345    {
346        global $DIC;
347
348        $ilDB = $DIC->database();
349
350        $query = "SELECT * FROM glossary_term WHERE id = " .
351            $ilDB->quote($term_id, "integer");
352        $obj_set = $ilDB->query($query);
353        $obj_rec = $ilDB->fetchAssoc($obj_set);
354
355        return $obj_rec["language"];
356    }
357
358    /**
359     * Get all terms for given set of glossary ids.
360     *
361     * @param 	integer/array	array of glossary ids for meta glossaries
362     * @param	string			searchstring
363     * @param	string			first letter
364     * @return	array			array of terms
365     */
366    public static function getTermList(
367        $a_glo_ref_id,
368        $searchterm = "",
369        $a_first_letter = "",
370        $a_def = "",
371        $a_tax_node = 0,
372        $a_add_amet_fields = false,
373        array $a_amet_filter = null,
374        $a_include_references = false
375    ) {
376        global $DIC;
377
378        if (is_array($a_glo_ref_id)) {
379            $a_glo_id = array_map(function ($id) {
380                return ilObject::_lookupObjectId($id);
381            }, $a_glo_ref_id);
382        } else {
383            $a_glo_id = ilObject::_lookupObjectId($a_glo_ref_id);
384        }
385        $ilDB = $DIC->database();
386
387        $join = $in = "";
388
389        $terms = array();
390
391        // get all term ids under taxonomy node (if given)
392        if ($a_tax_node > 1) {
393            include_once("./Services/Taxonomy/classes/class.ilObjTaxonomy.php");
394            $tax_ids = ilObjTaxonomy::getUsageOfObject($a_glo_id);
395            if (count($tax_ids) > 0) {
396                $items = ilObjTaxonomy::getSubTreeItems("glo", $a_glo_id, "term", $tax_ids[0], $a_tax_node);
397                $sub_tree_ids = array();
398                foreach ($items as $i) {
399                    $sub_tree_ids[] = $i["item_id"];
400                }
401                $in = " AND " . $ilDB->in("gt.id", $sub_tree_ids, false, "integer");
402            }
403        }
404
405        if ($a_def != "") {
406            // meta glossary?
407            if (is_array($a_glo_id)) {
408                $glo_where = $ilDB->in("page_object.parent_id", $a_glo_id, false, "integer");
409            } else {
410                $glo_where = " page_object.parent_id = " . $ilDB->quote($a_glo_id, "integer");
411            }
412
413            $join = " JOIN glossary_definition gd ON (gd.term_id = gt.id)" .
414            " JOIN page_object ON (" .
415            $glo_where .
416            " AND page_object.parent_type = " . $ilDB->quote("gdf", "text") .
417            " AND page_object.page_id = gd.id" .
418            " AND " . $ilDB->like("page_object.content", "text", "%" . $a_def . "%") .
419            ")";
420        }
421
422        $searchterm = (!empty($searchterm))
423            ? " AND " . $ilDB->like("term", "text", "%" . $searchterm . "%") . " "
424            : "";
425
426        if ($a_first_letter != "") {
427            $searchterm .= " AND " . $ilDB->upper($ilDB->substr("term", 1, 1)) . " = " . $ilDB->upper($ilDB->quote($a_first_letter, "text")) . " ";
428        }
429
430        // include references
431        $where_glo_id_or = "";
432        if ($a_include_references) {
433            $join .= " LEFT JOIN glo_term_reference tr ON (gt.id = tr.term_id) ";
434            if (is_array($a_glo_id)) {
435                $where_glo_id_or = " OR " . $ilDB->in("tr.glo_id", $a_glo_id, false, "integer");
436            } else {
437                $where_glo_id_or = " OR tr.glo_id = " . $ilDB->quote($a_glo_id, "integer");
438            }
439        }
440
441        // meta glossary
442        if (is_array($a_glo_id)) {
443            $where = "(" . $ilDB->in("gt.glo_id", $a_glo_id, false, "integer") . $where_glo_id_or . ")";
444        } else {
445            $where = "(gt.glo_id = " . $ilDB->quote($a_glo_id, "integer") . $where_glo_id_or . ")";
446        }
447
448        $where .= $in;
449
450
451        $q = "SELECT DISTINCT(gt.term), gt.id, gt.glo_id, gt.language FROM glossary_term gt " . $join . " WHERE " . $where . $searchterm . " ORDER BY term";
452
453        //echo $q; exit;
454
455        $term_set = $ilDB->query($q);
456        $glo_ids = array();
457        while ($term_rec = $ilDB->fetchAssoc($term_set)) {
458            $terms[] = array("term" => $term_rec["term"],
459                "language" => $term_rec["language"], "id" => $term_rec["id"], "glo_id" => $term_rec["glo_id"]);
460            $glo_ids[] = $term_rec["glo_id"];
461        }
462
463        // add advanced metadata
464        if (($a_add_amet_fields || is_array($a_amet_filter)) && !is_array($a_glo_ref_id)) {
465            include_once("./Services/AdvancedMetaData/classes/class.ilAdvancedMDValues.php");
466            $terms = ilAdvancedMDValues::queryForRecords($a_glo_ref_id, "glo", "term", $glo_ids, "term", $terms, "glo_id", "id", $a_amet_filter);
467        }
468        return $terms;
469    }
470
471    /**
472     * Get all terms for given set of glossary ids.
473     *
474     * @param 	integer/array	array of glossary ids for meta glossaries
475     * @param	string			searchstring
476     * @param	string			first letter
477     * @return	array			array of terms
478     */
479    public static function getFirstLetters($a_glo_id, $a_tax_node = 0)
480    {
481        global $DIC;
482
483        $ilDB = $DIC->database();
484
485        $terms = array();
486
487        // meta glossary
488        if (is_array($a_glo_id)) {
489            $where = $ilDB->in("glo_id", $a_glo_id, false, "integer");
490        } else {
491            $where = " glo_id = " . $ilDB->quote($a_glo_id, "integer") . " ";
492
493            // get all term ids under taxonomy node (if given)
494            if ($a_tax_node > 1) {
495                include_once("./Services/Taxonomy/classes/class.ilObjTaxonomy.php");
496                $tax_ids = ilObjTaxonomy::getUsageOfObject($a_glo_id);
497                if (count($tax_ids) > 0) {
498                    $items = ilObjTaxonomy::getSubTreeItems("glo", $a_glo_id, "term", $tax_ids[0], $a_tax_node);
499                    $sub_tree_ids = array();
500                    foreach ($items as $i) {
501                        $sub_tree_ids[] = $i["item_id"];
502                    }
503                    $in = " AND " . $ilDB->in("id", $sub_tree_ids, false, "integer");
504                }
505            }
506
507            $where .= $in;
508        }
509
510        $q = "SELECT DISTINCT " . $ilDB->upper($ilDB->substr("term", 1, 1)) . " let FROM glossary_term WHERE " . $where . " ORDER BY let";
511        $let_set = $ilDB->query($q);
512
513        $lets = array();
514        while ($let_rec = $ilDB->fetchAssoc($let_set)) {
515            $let[$let_rec["let"]] = $let_rec["let"];
516        }
517        return $let;
518    }
519
520    /**
521    * export xml
522    */
523    public function exportXML(&$a_xml_writer, $a_inst)
524    {
525        $attrs = array();
526        $attrs["Language"] = $this->getLanguage();
527        $attrs["Id"] = "il_" . IL_INST_ID . "_git_" . $this->getId();
528        $a_xml_writer->xmlStartTag("GlossaryItem", $attrs);
529
530        $attrs = array();
531        $a_xml_writer->xmlElement("GlossaryTerm", $attrs, $this->getTerm());
532
533        $defs = ilGlossaryDefinition::getDefinitionList($this->getId());
534
535        foreach ($defs as $def) {
536            $definition = new ilGlossaryDefinition($def["id"]);
537            $definition->exportXML($a_xml_writer, $a_inst);
538        }
539
540        $a_xml_writer->xmlEndTag("GlossaryItem");
541    }
542
543    /**
544     * Get number of usages
545     *
546     * @param	int		term id
547     * @return	int		number of usages
548     */
549    public static function getNumberOfUsages($a_term_id)
550    {
551        return count(ilGlossaryTerm::getUsages($a_term_id));
552    }
553
554    /**
555     * Get number of usages
556     *
557     * @param	int		term id
558     * @return	int		number of usages
559     */
560    public static function getUsages($a_term_id)
561    {
562        include_once("./Services/Link/classes/class.ilInternalLink.php");
563        $usages = (ilInternalLink::_getSourcesOfTarget("git", $a_term_id, 0));
564
565        include_once("./Modules/Glossary/classes/class.ilGlossaryTermReferences.php");
566        foreach (ilGlossaryTermReferences::lookupReferencesOfTerm($a_term_id) as $glo_id) {
567            $usages["glo:termref:" . $glo_id . ":-"] = array(
568                "type" => "glo:termref",
569                "id" => $glo_id,
570                "lang" => "-"
571            );
572        }
573
574        return $usages;
575    }
576
577    /**
578     * Copy a term to a glossary
579     *
580     * @param
581     * @return
582     */
583    public static function _copyTerm($a_term_id, $a_glossary_id)
584    {
585        $old_term = new ilGlossaryTerm($a_term_id);
586
587        // copy the term
588        $new_term = new ilGlossaryTerm();
589        $new_term->setTerm($old_term->getTerm());
590        $new_term->setLanguage($old_term->getLanguage());
591        $new_term->setGlossaryId($a_glossary_id);
592        $new_term->create();
593
594        // copy the definitions
595        include_once("./Modules/Glossary/classes/class.ilGlossaryDefinition.php");
596        $def_list = ilGlossaryDefinition::getDefinitionList($a_term_id);
597        foreach ($def_list as $def) {
598            $old_def = new ilGlossaryDefinition($def["id"]);
599
600            $new_def = new ilGlossaryDefinition();
601            $new_def->setShortText($old_def->getShortText());
602            $new_def->setNr($old_def->getNr());
603            $new_def->setTermId($new_term->getId());
604            $new_def->create();
605
606            // copy meta data
607            include_once("Services/MetaData/classes/class.ilMD.php");
608            $md = new ilMD(
609                $old_term->getGlossaryId(),
610                $old_def->getPageObject()->getId(),
611                $old_def->getPageObject()->getParentType()
612            );
613            $new_md = $md->cloneMD(
614                $a_glossary_id,
615                $new_def->getPageObject()->getId(),
616                $old_def->getPageObject()->getParentType()
617            );
618
619
620            $new_page = $new_def->getPageObject();
621            $old_def->getPageObject()->copy($new_page->getId(), $new_page->getParentType(), $new_page->getParentId(), true);
622
623            // page content
624            //$new_def->getPageObject()->setXMLContent($old_def->getPageObject()->copyXmlContent(true));
625            //$new_def->getPageObject()->buildDom();
626            //$new_def->getPageObject()->update();
627        }
628
629        // adv metadata
630        include_once('Services/AdvancedMetaData/classes/class.ilAdvancedMDRecord.php');
631        include_once('Services/AdvancedMetaData/classes/class.ilAdvancedMDFieldDefinition.php');
632        $old_recs = ilAdvancedMDRecord::_getSelectedRecordsByObject("glo", $old_term->getGlossaryId(), "term");
633        $new_recs = ilAdvancedMDRecord::_getSelectedRecordsByObject("glo", $a_glossary_id, "term");
634        foreach ($old_recs as $old_record_obj) {
635            reset($new_recs);
636            foreach ($new_recs as $new_record_obj) {
637                if ($old_record_obj->getRecordId() == $new_record_obj->getRecordId()) {
638                    foreach (ilAdvancedMDFieldDefinition::getInstancesByRecordId($old_record_obj->getRecordId()) as $def) {
639                        // now we need to copy $def->getFieldId() values from old term to new term
640                        // how?
641                        // clone values
642
643                        $source_primary = array("obj_id" => array("integer", $old_term->getGlossaryId()));
644                        $source_primary["sub_type"] = array("text", "term");
645                        $source_primary["sub_id"] = array("integer", $old_term->getId());
646                        $source_primary["field_id"] = array("integer", $def->getFieldId());
647                        $target_primary = array("obj_id" => array("integer", $new_term->getGlossaryId()));
648                        $target_primary["sub_type"] = array("text", "term");
649                        $target_primary["sub_id"] = array("integer", $new_term->getId());
650
651                        ilADTFactory::getInstance()->initActiveRecordByType();
652                        $has_cloned = ilADTActiveRecordByType::cloneByPrimary(
653                            "adv_md_values",
654                            array(
655                                "obj_id" => "integer",
656                                "sub_type" => "text",
657                                "sub_id" => "integer",
658                                "field_id" => "integer"
659                            ),
660                            $source_primary,
661                            $target_primary,
662                            array("disabled" => "integer")
663                        );
664                    }
665                }
666            }
667        }
668
669
670        return $new_term->getId();
671    }
672
673    /**
674     * Get terms of glossary
675     *
676     * @param
677     * @return
678     */
679    public static function getTermsOfGlossary($a_glo_id)
680    {
681        global $DIC;
682
683        $ilDB = $DIC->database();
684
685        $set = $ilDB->query(
686            "SELECT id FROM glossary_term WHERE " .
687            " glo_id = " . $ilDB->quote($a_glo_id, "integer")
688        );
689        $ids = array();
690        while ($rec = $ilDB->fetchAssoc($set)) {
691            $ids[] = $rec["id"];
692        }
693        return $ids;
694    }
695}
696