1<?php
2/*
3    +-----------------------------------------------------------------------------+
4    | ILIAS open source                                                           |
5    +-----------------------------------------------------------------------------+
6    | Copyright (c) 1998-2005 ILIAS open source, University of Cologne            |
7    |                                                                             |
8    | This program is free software; you can redistribute it and/or               |
9    | modify it under the terms of the GNU General Public License                 |
10    | as published by the Free Software Foundation; either version 2              |
11    | of the License, or (at your option) any later version.                      |
12    |                                                                             |
13    | This program is distributed in the hope that it will be useful,             |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of              |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
16    | GNU General Public License for more details.                                |
17    |                                                                             |
18    | You should have received a copy of the GNU General Public License           |
19    | along with this program; if not, write to the Free Software                 |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. |
21    +-----------------------------------------------------------------------------+
22*/
23
24/**
25* Class ilObj<module_name>
26*
27* @author Stefan Meyer <meyer@leifos.com>
28* @version $Id$
29*
30*/
31class ilObjCourseGrouping
32{
33    public $db;
34
35    protected static $assignedObjects = array();
36
37    /**
38     * @var null | \ilLogger
39     */
40    private $logger = null;
41
42    /**
43     * Constructor
44     * @access	public
45     * @param	int	reference_id or object_id
46     */
47    public function __construct($a_id = 0)
48    {
49        global $DIC;
50
51        $ilDB = $DIC['ilDB'];
52
53        $this->logger = $DIC->logger()->crs();
54
55        $this->setType('crsg');
56        $this->db = $ilDB;
57
58        $this->setId($a_id);
59
60        if ($a_id) {
61            $this->read();
62        }
63    }
64    public function setId($a_id)
65    {
66        $this->id = $a_id;
67    }
68    public function getId()
69    {
70        return $this->id;
71    }
72
73    public function setContainerRefId($a_ref_id)
74    {
75        $this->ref_id = $a_ref_id;
76    }
77    public function getContainerRefId()
78    {
79        return $this->ref_id;
80    }
81    public function setContainerObjId($a_obj_id)
82    {
83        $this->obj_id = $a_obj_id;
84    }
85    public function getContainerObjId()
86    {
87        return $this->obj_id;
88    }
89    public function getContainerType()
90    {
91        return $this->container_type;
92    }
93    public function setContainerType($a_type)
94    {
95        $this->container_type = $a_type;
96    }
97
98    public function setType($a_type)
99    {
100        $this->type = $a_type;
101    }
102    public function getType()
103    {
104        return $this->type;
105    }
106
107    public function setTitle($a_title)
108    {
109        $this->title = $a_title;
110    }
111    public function getTitle()
112    {
113        return $this->title;
114    }
115    public function setDescription($a_desc)
116    {
117        $this->description = $a_desc;
118    }
119    public function getDescription()
120    {
121        return $this->description;
122    }
123    public function setUniqueField($a_uni)
124    {
125        $this->unique_field = $a_uni;
126    }
127    public function getUniqueField()
128    {
129        return $this->unique_field;
130    }
131
132    public function getCountAssignedItems()
133    {
134        return count($this->getAssignedItems());
135    }
136
137    public function getAssignedItems()
138    {
139        global $DIC;
140
141        $tree = $DIC['tree'];
142
143        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
144        $condition_data = ilConditionHandler::_getPersistedConditionsOfTrigger($this->getType(), $this->getId());
145        $conditions = array();
146        foreach ($condition_data as $condition) {
147            if ($tree->isDeleted($condition['target_ref_id'])) {
148                continue;
149            }
150            $conditions[] = $condition;
151        }
152        return count($conditions) ? $conditions : array();
153    }
154
155    public function delete()
156    {
157        global $DIC;
158
159        $ilDB = $DIC['ilDB'];
160
161        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
162
163        if ($this->getId() and $this->getType() === 'crsg') {
164            $query = "DELETE FROM object_data WHERE obj_id = " . $ilDB->quote($this->getId(), 'integer') . " ";
165            $res = $ilDB->manipulate($query);
166
167            $query = "DELETE FROM crs_groupings " .
168                "WHERE crs_grp_id = " . $ilDB->quote($this->getId(), 'integer') . " ";
169            $res = $ilDB->manipulate($query);
170
171            // Delete conditions
172            $condh = new ilConditionHandler();
173            $condh->deleteByObjId($this->getId());
174
175            return true;
176        }
177        return false;
178    }
179
180    public function create($a_course_ref_id, $a_course_id)
181    {
182        global $DIC;
183
184        $ilUser = $DIC['ilUser'];
185        $ilDB = $DIC['ilDB'];
186
187        // INSERT IN object_data
188        $this->setId($ilDB->nextId("object_data"));
189        $query = "INSERT INTO object_data " .
190            "(obj_id, type,title,description,owner,create_date,last_update) " .
191            "VALUES " .
192            "(" .
193            $ilDB->quote($this->getId(), "integer") . "," .
194            $ilDB->quote($this->type, "text") . "," .
195            $ilDB->quote($this->getTitle(), "text") . "," .
196            $ilDB->quote($this->getDescription(), "text") . "," .
197            $ilDB->quote($ilUser->getId(), "integer") . "," .
198            $ilDB->now() . "," .
199            $ilDB->now() .
200            ')';
201
202        $ilDB->manipulate($query);
203
204        // INSERT in crs_groupings
205        $query = "INSERT INTO crs_groupings (crs_grp_id,crs_ref_id,crs_id,unique_field) " .
206            "VALUES (" .
207            $ilDB->quote($this->getId(), 'integer') . ", " .
208            $ilDB->quote($a_course_ref_id, 'integer') . ", " .
209            $ilDB->quote($a_course_id, 'integer') . ", " .
210            $ilDB->quote($this->getUniqueField(), 'text') . " " .
211            ")";
212        $res = $ilDB->manipulate($query);
213
214        return $this->getId();
215    }
216
217    public function update()
218    {
219        global $DIC;
220
221        $ilDB = $DIC['ilDB'];
222
223        if ($this->getId() and $this->getType() === 'crsg') {
224            // UPDATe object_data
225            $query = "UPDATE object_data " .
226                "SET title = " . $ilDB->quote($this->getTitle(), 'text') . ", " .
227                "description = " . $ilDB->quote($this->getDescription(), 'text') . " " .
228                "WHERE obj_id = " . $ilDB->quote($this->getId(), 'integer') . " " .
229                "AND type = " . $ilDB->quote($this->getType(), 'text') . " ";
230            $res = $ilDB->manipulate($query);
231
232            // UPDATE crs_groupings
233            $query = "UPDATE crs_groupings " .
234                "SET unique_field = " . $ilDB->quote($this->getUniqueField(), 'text') . " " .
235                "WHERE crs_grp_id = " . $ilDB->quote($this->getId(), 'integer') . " ";
236            $res = $ilDB->manipulate($query);
237
238            // UPDATE conditions
239            $query = "UPDATE conditions " .
240                "SET value = " . $ilDB->quote($this->getUniqueField(), 'text') . " " .
241                "WHERE trigger_obj_id = " . $ilDB->quote($this->getId(), 'integer') . " " .
242                "AND trigger_type = 'crsg'";
243            $res = $ilDB->manipulate($query);
244
245            return true;
246        }
247        return false;
248    }
249
250    public function isAssigned($a_course_id)
251    {
252        foreach ($this->getAssignedItems() as $condition_data) {
253            if ($a_course_id == $condition_data['target_obj_id']) {
254                return true;
255            }
256        }
257        return false;
258    }
259
260    public function read()
261    {
262        global $DIC;
263
264        $ilObjDataCache = $DIC['ilObjDataCache'];
265        $ilDB = $DIC['ilDB'];
266
267        $query = "SELECT * FROM object_data " .
268            "WHERE obj_id = " . $ilDB->quote($this->getId(), 'integer') . " ";
269
270        $res = $this->db->query($query);
271        while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
272            $this->setTitle($row->title);
273            $this->setDescription($row->description);
274        }
275
276        $query = "SELECT * FROM crs_groupings " .
277            "WHERE crs_grp_id = " . $ilDB->quote($this->getId(), 'integer') . " ";
278        $res = $ilDB->query($query);
279
280        while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
281            $this->setUniqueField($row->unique_field);
282            $this->setContainerRefId($row->crs_ref_id);
283            $this->setContainerObjId($row->crs_id);
284            $this->setContainerType($ilObjDataCache->lookupType($this->getContainerObjId()));
285        }
286
287        return true;
288    }
289
290    public function _checkAccess($grouping_id)
291    {
292        global $DIC;
293
294        $ilAccess = $DIC['ilAccess'];
295        $tree = $DIC['tree'];
296
297        $tmp_grouping_obj = new ilObjCourseGrouping($grouping_id);
298
299        $found_invisible = false;
300        foreach ($tmp_grouping_obj->getAssignedItems() as $condition) {
301            if (!$ilAccess->checkAccess('write', '', $condition['target_ref_id'])) {
302                $found_invisible = true;
303                break;
304            }
305        }
306        return $found_invisible ? false : true;
307    }
308
309
310    /**
311     * @param int $a_obj_id
312     * @return array
313     *
314     * Returns a list of all groupings for which the current user hast write permission on all assigned objects. Or groupings
315     * the given object id is assigned to.
316     */
317    public static function _getVisibleGroupings($a_obj_id)
318    {
319        global $DIC;
320
321        $ilObjDataCache = $DIC['ilObjDataCache'];
322        $ilAccess = $DIC['ilAccess'];
323        $ilDB = $DIC['ilDB'];
324
325        $container_type = $ilObjDataCache->lookupType($a_obj_id) == 'grp' ? 'grp' : 'crs';
326
327
328        // First get all groupings
329        $query = "SELECT * FROM object_data WHERE type = 'crsg' ORDER BY title";
330        $res = $ilDB->query($query);
331        $groupings = array();
332        while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
333            $groupings[] = $row->obj_id;
334        }
335
336        //check access
337        foreach ($groupings as $grouping_id) {
338            $tmp_grouping_obj = new ilObjCourseGrouping($grouping_id);
339
340            // Check container type
341            if ($tmp_grouping_obj->getContainerType() != $container_type) {
342                continue;
343            }
344            // Check if container is current container
345            if ($tmp_grouping_obj->getContainerObjId() == $a_obj_id) {
346                $visible_groupings[] = $grouping_id;
347                continue;
348            }
349            // check if items are assigned
350            if (count($items = $tmp_grouping_obj->getAssignedItems())) {
351                foreach ($items as $condition_data) {
352                    if ($ilAccess->checkAccess('write', '', $condition_data['target_ref_id'])) {
353                        $visible_groupings[] = $grouping_id;
354                        break;
355                    }
356                }
357            }
358        }
359        return $visible_groupings ? $visible_groupings : array();
360    }
361
362    public function assign($a_crs_ref_id, $a_course_id)
363    {
364        // Add the parent course of grouping
365        $this->__addCondition($this->getContainerRefId(), $this->getContainerObjId());
366        $this->__addCondition($a_crs_ref_id, $a_course_id);
367
368        return true;
369    }
370
371    public function deassign($a_crs_ref_id, $a_course_id)
372    {
373        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
374
375
376        $condh = new ilConditionHandler();
377
378        // DELETE also original course if its the last
379        if ($this->getCountAssignedCourses() == 2) {
380            $condh->deleteByObjId($this->getId());
381
382            return true;
383        }
384
385        foreach (ilConditionHandler::_getPersistedConditionsOfTrigger('crsg', $this->getId()) as $cond_data) {
386            if ($cond_data['target_ref_id'] == $a_crs_ref_id and
387               $cond_data['target_obj_id'] == $a_course_id) {
388                $condh->deleteCondition($cond_data['id']);
389            }
390        }
391
392        return true;
393    }
394
395    /**
396     * @param int $a_target_id
397     * @param int $a_copy_id
398     */
399    public function cloneGrouping($a_target_id, $a_copy_id)
400    {
401        $this->logger->debug('Start cloning membership limitations...');
402        $mappings = \ilCopyWizardOptions::_getInstance($a_copy_id)->getMappings();
403        $target_ref_id = 0;
404        $target_obj_id = 0;
405
406        if (array_key_exists($this->getContainerRefId(), $mappings) && $mappings[$this->getContainerRefId()]) {
407            $target_ref_id = $mappings[$this->getContainerRefId()];
408            $target_obj_id = \ilObject::_lookupObjId($target_ref_id);
409            $this->logger->dump($target_ref_id);
410            $this->logger->dump($target_obj_id);
411        }
412        if (!$target_ref_id || !$target_obj_id) {
413            $this->logger->debug('No target ref_id found.');
414            return false;
415        }
416
417        $new_grouping = new \ilObjCourseGrouping();
418        $new_grouping->setTitle($this->getTitle());
419        $new_grouping->setDescription($this->getDescription());
420        $new_grouping->setContainerRefId($target_ref_id);
421        $new_grouping->setContainerObjId($target_obj_id);
422        $new_grouping->setContainerType(\ilObject::_lookupType($target_obj_id));
423        $new_grouping->setUniqueField($this->getUniqueField());
424        $new_grouping->create($target_ref_id, $target_obj_id);
425
426        $obj_instance = \ilObjectFactory::getInstanceByRefId($this->getContainerRefId(), false);
427        if (!$obj_instance instanceof \ilObject) {
428            $this->logger->info('Cannot create object instance for membership limitation');
429            return false;
430        }
431        $limitation_items = self::_getGroupingItems($obj_instance);
432        $this->logger->dump($limitation_items);
433
434        foreach ($limitation_items as $item_ref_id) {
435            $target_item_ref_id = 0;
436            $target_item_obj_id = 0;
437            if (array_key_exists($item_ref_id, $mappings) && $mappings[$item_ref_id]) {
438                $target_item_ref_id = $mappings[$item_ref_id];
439                $target_item_obj_id = \ilObject::_lookupObjId($target_item_ref_id);
440            }
441            if (!$target_item_ref_id || !$target_item_obj_id) {
442                $this->logger->info('No mapping found for: ' . $item_ref_id);
443                continue;
444            }
445            $new_grouping->assign($target_item_ref_id, $target_item_obj_id);
446        }
447
448        return true;
449    }
450
451
452    // PRIVATE
453    public function __addCondition($a_target_ref_id, $a_target_obj_id)
454    {
455        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
456
457        $tmp_condh = new ilConditionHandler();
458        $tmp_condh->enableAutomaticValidation(false);
459
460        $tmp_condh->setTargetRefId($a_target_ref_id);
461        $tmp_condh->setTargetObjId($a_target_obj_id);
462        $tmp_condh->setTargetType(\ilObject::_lookupType($a_target_obj_id));
463        $tmp_condh->setTriggerRefId(0);
464        $tmp_condh->setTriggerObjId($this->getId());
465        $tmp_condh->setTriggerType('crsg');
466        $tmp_condh->setOperator('not_member');
467        $tmp_condh->setValue($this->getUniqueField());
468
469        if (!$tmp_condh->checkExists()) {
470            $tmp_condh->storeCondition();
471
472            return true;
473        }
474        return false;
475    }
476
477    // STATIC
478    public static function _deleteAll($a_course_id)
479    {
480        global $DIC;
481
482        $ilDB = $DIC['ilDB'];
483
484        // DELETE CONDITIONS
485        foreach ($groupings = ilObjCourseGrouping::_getGroupings($a_course_id) as $grouping_id) {
486            include_once './Services/Conditions/classes/class.ilConditionHandler.php';
487
488            $condh = new ilConditionHandler();
489            $condh->deleteByObjId($grouping_id);
490        }
491
492        $query = "DELETE FROM crs_groupings " .
493            "WHERE crs_id = " . $ilDB->quote($a_course_id, 'integer') . " ";
494        $res = $ilDB->manipulate($query);
495
496        return true;
497    }
498
499    /**
500     * @param $a_course_id
501     * @return int[]
502     */
503    public static function _getGroupings($a_course_id)
504    {
505        global $DIC;
506
507        $ilDB = $DIC['ilDB'];
508
509        $query = "SELECT * FROM crs_groupings " .
510            "WHERE crs_id = " . $ilDB->quote($a_course_id, 'integer') . " ";
511
512        $res = $ilDB->query($query);
513        while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
514            $groupings[] = $row->crs_grp_id;
515        }
516        return $groupings ? $groupings : array();
517    }
518
519    public static function _checkCondition($trigger_obj_id, $operator, $value, $a_usr_id = 0)
520    {
521        // in the moment i alway return true, there are some problems with presenting the condition if it fails,
522        // only course register class check manually if this condition is fullfilled
523        return true;
524    }
525
526
527    /**
528    * Get all ids of courses that are grouped with another course
529    * @access	static
530    * @param	integer	 object_id of one course
531    * @param	array integer ids of courses or empty array if course is not in grouping
532    */
533    public static function _getGroupingCourseIds($a_course_ref_id, $a_course_id)
534    {
535        global $DIC;
536
537        $tree = $DIC['tree'];
538
539        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
540
541        // get all grouping ids the course is assigned to
542        foreach (ilConditionHandler::_getPersistedConditionsOfTarget($a_course_ref_id, $a_course_id, 'crs') as $condition) {
543            if ($condition['trigger_type'] == 'crsg') {
544                foreach (ilConditionHandler::_getPersistedConditionsOfTrigger('crsg', $condition['trigger_obj_id']) as $target_condition) {
545                    if ($tree->isDeleted($target_condition['target_ref_id'])) {
546                        continue;
547                    }
548                    $course_ids[] = array('id' => $target_condition['target_obj_id'],
549                                          'unique' => $target_condition['value']);
550                }
551            }
552        }
553        return $course_ids ? $course_ids : array();
554    }
555
556
557    /**
558     * Alway call checkGroupingDependencies before
559     * @return array Assigned objects
560     */
561    public static function getAssignedObjects()
562    {
563        return self::$assignedObjects ? self::$assignedObjects : array();
564    }
565
566    public static function _checkGroupingDependencies(&$container_obj, $a_user_id = null)
567    {
568        global $DIC;
569
570        $ilUser = $DIC['ilUser'];
571        $lng = $DIC['lng'];
572        $tree = $DIC['tree'];
573
574        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
575
576        $user_id = is_null($a_user_id) ? $ilUser->getId() : $a_user_id;
577
578
579        $trigger_ids = array();
580        foreach (ilConditionHandler::_getPersistedConditionsOfTarget(
581            $container_obj->getRefId(),
582            $container_obj->getId(),
583            $container_obj->getType()
584        ) as $condition) {
585            if ($condition['operator'] == 'not_member') {
586                $trigger_ids[] = $condition['trigger_obj_id'];
587                break;
588            }
589        }
590        if (!count($trigger_ids)) {
591            return true;
592        }
593        $matriculation_message = $assigned_message = '';
594        self::$assignedObjects = array();
595        foreach ($trigger_ids as $trigger_id) {
596            foreach (ilConditionHandler::_getPersistedConditionsOfTrigger('crsg', $trigger_id) as $condition) {
597                // Handle deleted items
598                if ($tree->isDeleted($condition['target_ref_id'])) {
599                    continue;
600                }
601                if ($condition['operator'] == 'not_member') {
602                    switch ($condition['value']) {
603                        case 'matriculation':
604                            if (!strlen(ilObjUser::lookupMatriculation($user_id))) {
605                                if (!$matriculation_message) {
606                                    $matriculation_message = $lng->txt('crs_grp_matriculation_required');
607                                }
608                            }
609                    }
610                    if ($container_obj->getType() == 'crs') {
611                        include_once('Modules/Course/classes/class.ilCourseParticipants.php');
612                        $members = ilCourseParticipants::_getInstanceByObjId($condition['target_obj_id']);
613                        if ($members->isGroupingMember($user_id, $condition['value'])) {
614                            if (!$assigned_message) {
615                                self::$assignedObjects[] = $condition['target_obj_id'];
616                                $assigned_message = $lng->txt('crs_grp_already_assigned');
617                            }
618                        }
619                    } elseif ($container_obj->getType() == 'grp') {
620                        include_once('Modules/Group/classes/class.ilGroupParticipants.php');
621                        $members = ilGroupParticipants::_getInstanceByObjId($condition['target_obj_id']);
622                        if ($members->isGroupingMember($user_id, $condition['value'])) {
623                            if (!$assigned_message) {
624                                self::$assignedObjects[] = $condition['target_obj_id'];
625                                $assigned_message = $lng->txt('grp_grp_already_assigned');
626                            }
627                        }
628                    } else {
629                        if (ilObjGroup::_isMember($user_id, $condition['target_ref_id'], $condition['value'])) {
630                            if (!$assigned_message) {
631                                self::$assignedObjects[] = $condition['target_obj_id'];
632                                $assigned_message = $lng->txt('crs_grp_already_assigned');
633                            }
634                        }
635                    }
636                }
637            }
638        }
639        if ($matriculation_message) {
640            $container_obj->appendMessage($matriculation_message);
641            return false;
642        } elseif ($assigned_message) {
643            $container_obj->appendMessage($assigned_message);
644            return false;
645        }
646        return true;
647    }
648
649
650    /**
651     * Get courses/groups that are assigned to the same membership limitation
652     *
653     * @param object container object
654     * @return array array of reference ids
655     */
656    public static function _getGroupingItems($container_obj)
657    {
658        global $DIC;
659
660        $tree = $DIC['tree'];
661        $ilObjDataCache = $DIC['ilObjDataCache'];
662        $ilAccess = $DIC['ilAccess'];
663        $tree = $DIC['tree'];
664
665        include_once './Services/Conditions/classes/class.ilConditionHandler.php';
666
667        $trigger_ids = array();
668        foreach (ilConditionHandler::_getPersistedConditionsOfTarget(
669            $container_obj->getRefId(),
670            $container_obj->getId(),
671            $container_obj->getType()
672        ) as $condition) {
673            if ($condition['operator'] == 'not_member') {
674                $trigger_ids[] = $condition['trigger_obj_id'];
675            }
676        }
677        if (!count($trigger_ids)) {
678            return false;
679        }
680        $hash_table = array();
681        foreach ($trigger_ids as $trigger_id) {
682            foreach (ilConditionHandler::_getPersistedConditionsOfTrigger('crsg', $trigger_id) as $condition) {
683                // Continue if trigger is deleted
684                if ($tree->isDeleted($condition['target_ref_id'])) {
685                    continue;
686                }
687
688                if ($condition['operator'] == 'not_member') {
689                    if (!$hash_table[$condition['target_ref_id']]) {
690                        $items[] = $condition['target_ref_id'];
691                    }
692                    $hash_table[$condition['target_ref_id']] = true;
693                }
694            }
695        }
696        return $items ? $items : array();
697    }
698} // END class.ilObjCourseGrouping
699