1<?php
2/*
3    +-----------------------------------------------------------------------------+
4    | ILIAS open source                                                           |
5    +-----------------------------------------------------------------------------+
6    | Copyright (c) 1998-2006 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// note: the values are derived from ilObjCourse constants
25// to enable easy migration from course view setting to container view setting
26
27require_once "./Services/Object/classes/class.ilObject.php";
28
29/**
30* Class ilContainer
31*
32* Base class for all container objects (categories, courses, groups)
33*
34* @author Alex Killing <alex.killing@gmx.de>
35* @version $Id$
36*
37* @extends ilObject
38*/
39class ilContainer extends ilObject
40{
41    /**
42     * @var ilDB
43     */
44    protected $db;
45
46    /**
47     * @var Logger
48     */
49    protected $log;
50
51    /**
52     * @var ilAccessHandler
53     */
54    protected $access;
55
56    /**
57     * @var ilErrorHandling
58     */
59    protected $error;
60
61    /**
62     * @var ilRbacSystem
63     */
64    protected $rbacsystem;
65
66    /**
67     * @var ilTree
68     */
69    protected $tree;
70
71    /**
72     * @var ilObjUser
73     */
74    protected $user;
75
76    /**
77     * @var ilObjectDefinition
78     */
79    protected $obj_definition;
80
81    protected $order_type = 0;
82    protected $hiddenfilesfound = false;
83    protected $news_timeline = false;
84    protected $news_timeline_auto_entries = false;
85
86    // container view constants
87    const VIEW_SESSIONS = 0;
88    const VIEW_OBJECTIVE = 1;
89    const VIEW_TIMING = 2;
90    const VIEW_ARCHIVE = 3;
91    const VIEW_SIMPLE = 4;
92    const VIEW_BY_TYPE = 5;
93    const VIEW_INHERIT = 6;
94
95    const VIEW_DEFAULT = self::VIEW_BY_TYPE;
96
97
98    const SORT_TITLE = 0;
99    const SORT_MANUAL = 1;
100    const SORT_ACTIVATION = 2;
101    const SORT_INHERIT = 3;
102    const SORT_CREATION = 4;
103
104    const SORT_DIRECTION_ASC = 0;
105    const SORT_DIRECTION_DESC = 1;
106
107    const SORT_NEW_ITEMS_POSITION_TOP = 0;
108    const SORT_NEW_ITEMS_POSITION_BOTTOM = 1;
109
110    const SORT_NEW_ITEMS_ORDER_TITLE = 0;
111    const SORT_NEW_ITEMS_ORDER_CREATION = 1;
112    const SORT_NEW_ITEMS_ORDER_ACTIVATION = 2;
113
114    public static $data_preloaded = false;
115
116    /**
117     * @var ilSetting
118     */
119    protected $setting;
120
121    /**
122     * @var ilObjectTranslation
123     */
124    protected $obj_trans = null;
125
126    /**
127     * @var ilRecommendedContentManager
128     */
129    protected $recommended_content_manager;
130
131    public function __construct($a_id = 0, $a_reference = true)
132    {
133        global $DIC;
134
135        $this->db = $DIC->database();
136        $this->log = $DIC["ilLog"];
137        $this->access = $DIC->access();
138        $this->error = $DIC["ilErr"];
139        $this->rbacsystem = $DIC->rbac()->system();
140        $this->tree = $DIC->repositoryTree();
141        $this->user = $DIC->user();
142        $this->obj_definition = $DIC["objDefinition"];
143
144
145        $this->setting = $DIC["ilSetting"];
146        parent::__construct($a_id, $a_reference);
147        include_once("./Services/Object/classes/class.ilObjectTranslation.php");
148
149        if ($this->getId() > 0) {
150            $this->obj_trans = ilObjectTranslation::getInstance($this->getId());
151        }
152        $this->recommended_content_manager = new ilRecommendedContentManager();
153    }
154
155    /**
156     * Get object translation
157     * @return ilObjectTranslation
158     */
159    public function getObjectTranslation()
160    {
161        return $this->obj_trans;
162    }
163
164    /**
165     * Get object translation
166     * @param ilObjectTranslation $obj_trans
167     */
168    public function setObjectTranslation(ilObjectTranslation $obj_trans)
169    {
170        $this->obj_trans = $obj_trans;
171    }
172
173    /**
174    * Create directory for the container.
175    * It is <webspace_dir>/container_data.
176    */
177    public function createContainerDirectory()
178    {
179        $webspace_dir = ilUtil::getWebspaceDir();
180        $cont_dir = $webspace_dir . "/container_data";
181        if (!is_dir($cont_dir)) {
182            ilUtil::makeDir($cont_dir);
183        }
184        $obj_dir = $cont_dir . "/obj_" . $this->getId();
185        if (!is_dir($obj_dir)) {
186            ilUtil::makeDir($obj_dir);
187        }
188    }
189
190    /**
191    * Get the container directory.
192    *
193    * @return	string	container directory
194    */
195    public function getContainerDirectory()
196    {
197        return $this->_getContainerDirectory($this->getId());
198    }
199
200    /**
201    * Get the container directory.
202    *
203    * @return	string	container directory
204    */
205    public static function _getContainerDirectory($a_id)
206    {
207        return ilUtil::getWebspaceDir() . "/container_data/obj_" . $a_id;
208    }
209
210    /**
211    * Set Found hidden files (set by getSubItems).
212    *
213    * @param	boolean	$a_hiddenfilesfound	Found hidden files (set by getSubItems)
214    */
215    public function setHiddenFilesFound($a_hiddenfilesfound)
216    {
217        $this->hiddenfilesfound = $a_hiddenfilesfound;
218    }
219
220    /**
221    * Get Found hidden files (set by getSubItems).
222    *
223    * @return	boolean	Found hidden files (set by getSubItems)
224    */
225    public function getHiddenFilesFound()
226    {
227        return $this->hiddenfilesfound;
228    }
229
230    /**
231    * get ID of assigned style sheet object
232    */
233    public function getStyleSheetId()
234    {
235        return $this->style_id;
236    }
237
238    /**
239    * set ID of assigned style sheet object
240    */
241    public function setStyleSheetId($a_style_id)
242    {
243        $this->style_id = $a_style_id;
244    }
245
246    /**
247     * Set news timeline
248     *
249     * @param bool $a_val activate news timeline
250     */
251    public function setNewsTimeline($a_val)
252    {
253        $this->news_timeline = $a_val;
254    }
255
256    /**
257     * Get news timeline
258     *
259     * @return bool activate news timeline
260     */
261    public function getNewsTimeline()
262    {
263        return $this->news_timeline;
264    }
265
266    /**
267     * Set news timeline auto entries
268     *
269     * @param bool $a_val include automatically created entries
270     */
271    public function setNewsTimelineAutoEntries($a_val)
272    {
273        $this->news_timeline_auto_entries = $a_val;
274    }
275
276    /**
277     * Get news timeline auto entries
278     *
279     * @return bool include automatically created entries
280     */
281    public function getNewsTimelineAutoEntries()
282    {
283        return $this->news_timeline_auto_entries;
284    }
285
286    /**
287     * Set news timline is landing page
288     *
289     * @param bool $a_val is news timline landing page?
290     */
291    public function setNewsTimelineLandingPage($a_val)
292    {
293        $this->news_timeline_landing_page = $a_val;
294    }
295
296    /**
297     * Get news timline is landing page
298     *
299     * @return bool is news timline landing page?
300     */
301    public function getNewsTimelineLandingPage()
302    {
303        return $this->news_timeline_landing_page;
304    }
305
306    /**
307     * Is news timeline effective?
308     *
309     * @return bool
310     */
311    public function isNewsTimelineEffective()
312    {
313        if ($this->getUseNews()) {
314            if ($this->getNewsTimeline()) {
315                return true;
316            }
317        }
318        return false;
319    }
320
321    /**
322     * Is news timeline landing page effective?
323     *
324     * @return bool
325     */
326    public function isNewsTimelineLandingPageEffective()
327    {
328        if ($this->getUseNews()) {
329            if ($this->getNewsTimeline()) {
330                if ($this->getNewsTimelineLandingPage()) {
331                    return true;
332                }
333            }
334        }
335        return false;
336    }
337
338
339    /**
340     * Set news block activated
341     *
342     * @param bool $a_val news block activated
343     */
344    public function setNewsBlockActivated($a_val)
345    {
346        $this->news_block_activated = $a_val;
347    }
348
349    /**
350     * Get news block activated
351     *
352     * @return bool news block activated
353     */
354    public function getNewsBlockActivated()
355    {
356        return $this->news_block_activated;
357    }
358
359    /**
360     * Set use news
361     *
362     * @param bool $a_val use news system?
363     */
364    public function setUseNews($a_val)
365    {
366        $this->use_news = $a_val;
367    }
368
369    /**
370     * Get use news
371     *
372     * @return bool use news system?
373     */
374    public function getUseNews()
375    {
376        return $this->use_news;
377    }
378
379    /**
380    * Lookup a container setting.
381    *
382    * @param	int			container id
383    * @param	string		setting keyword
384    *
385    * @return	string		setting value
386    */
387    public static function _lookupContainerSetting($a_id, $a_keyword, $a_default_value = null)
388    {
389        global $DIC;
390
391        $ilDB = $DIC->database();
392
393        $q = "SELECT * FROM container_settings WHERE " .
394                " id = " . $ilDB->quote($a_id, 'integer') . " AND " .
395                " keyword = " . $ilDB->quote($a_keyword, 'text');
396        $set = $ilDB->query($q);
397        $rec = $set->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
398
399        if (isset($rec['value'])) {
400            return $rec["value"];
401        }
402        if ($a_default_value === null) {
403            return '';
404        }
405        return $a_default_value;
406    }
407
408    /**
409     * @param $a_id
410     * @param $a_keyword
411     * @param $a_value
412     */
413    public static function _writeContainerSetting($a_id, $a_keyword, $a_value)
414    {
415        global $DIC;
416
417        $ilDB = $DIC->database();
418
419        $query = "DELETE FROM container_settings WHERE " .
420            "id = " . $ilDB->quote($a_id, 'integer') . " " .
421            "AND keyword = " . $ilDB->quote($a_keyword, 'text');
422        $res = $ilDB->manipulate($query);
423
424        $log = ilLoggerFactory::getLogger("cont");
425        $log->debug("Write container setting, id: " . $a_id . ", keyword: " . $a_keyword . ", value: " . $a_value);
426
427        $query = "INSERT INTO container_settings (id, keyword, value) VALUES (" .
428            $ilDB->quote($a_id, 'integer') . ", " .
429            $ilDB->quote($a_keyword, 'text') . ", " .
430            $ilDB->quote($a_value, 'text') .
431            ")";
432
433        $res = $ilDB->manipulate($query);
434    }
435
436    public static function _getContainerSettings($a_id)
437    {
438        global $DIC;
439
440        $ilDB = $DIC->database();
441
442        $res = array();
443
444        $sql = "SELECT * FROM container_settings WHERE " .
445                " id = " . $ilDB->quote($a_id, 'integer');
446        $set = $ilDB->query($sql);
447        while ($row = $ilDB->fetchAssoc($set)) {
448            $res[$row["keyword"]] = $row["value"];
449        }
450
451        return $res;
452    }
453
454    public static function _deleteContainerSettings($a_id, $a_keyword = null, $a_keyword_like = false)
455    {
456        global $DIC;
457
458        $ilDB = $DIC->database();
459
460        if (!$a_id) {
461            return;
462        }
463
464        $sql = "DELETE FROM container_settings WHERE " .
465                " id = " . $ilDB->quote($a_id, 'integer');
466        if ($a_keyword) {
467            if (!$a_keyword_like) {
468                $sql .= " AND keyword = " . $ilDB->quote($a_keyword, "text");
469            } else {
470                $sql .= " AND " . $ilDB->like("keyword", "text", $a_keyword);
471            }
472        }
473        $ilDB->manipulate($sql);
474    }
475
476    public static function _exportContainerSettings(ilXmlWriter $a_xml, $a_obj_id)
477    {
478        // container settings
479        $settings = self::_getContainerSettings($a_obj_id);
480        if (sizeof($settings)) {
481            $a_xml->xmlStartTag("ContainerSettings");
482
483            foreach ($settings as $keyword => $value) {
484                // :TODO: proper custom icon export/import
485                if (stristr($keyword, "icon")) {
486                    continue;
487                }
488
489                $a_xml->xmlStartTag(
490                    'ContainerSetting',
491                    array(
492                        'id' => $keyword,
493                    )
494                );
495
496                $a_xml->xmlData($value);
497                $a_xml->xmlEndTag("ContainerSetting");
498            }
499
500            $a_xml->xmlEndTag("ContainerSettings");
501        }
502    }
503
504    /**
505     * Clone container settings
506     *
507     * @access public
508     * @param int target ref_id
509     * @param int copy id
510     * @return object new object
511     */
512    public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false)
513    {
514        /** @var ilObjCourse $new_obj */
515        $new_obj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree);
516
517        // translations
518        include_once("./Services/Object/classes/class.ilObjectTranslation.php");
519        $ot = ilObjectTranslation::getInstance($this->getId());
520        $ot->copy($new_obj->getId());
521
522        include_once('./Services/Container/classes/class.ilContainerSortingSettings.php');
523        #18624 - copy all sorting settings
524        ilContainerSortingSettings::_cloneSettings($this->getId(), $new_obj->getId());
525
526        // copy content page
527        include_once("./Services/Container/classes/class.ilContainerPage.php");
528        if (ilContainerPage::_exists(
529            "cont",
530            $this->getId()
531        )) {
532            $orig_page = new ilContainerPage($this->getId());
533            $orig_page->copy($new_obj->getId(), "cont", $new_obj->getId());
534        }
535
536        // #20614 - copy style
537        include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
538        $style_id = $this->getStyleSheetId();
539        if ($style_id > 0) {
540            if (!!ilObjStyleSheet::_lookupStandard($style_id)) {
541                $style_obj = ilObjectFactory::getInstanceByObjId($style_id);
542                $new_id = $style_obj->ilClone();
543                $new_obj->setStyleSheetId($new_id);
544                $new_obj->update();
545            } else {
546                $new_obj->setStyleSheetId($this->getStyleSheetId());
547            }
548        }
549
550        // #10271 - copy start objects page
551        include_once("./Services/Container/classes/class.ilContainerStartObjectsPage.php");
552        if (ilContainerStartObjectsPage::_exists(
553            "cstr",
554            $this->getId()
555        )) {
556            $orig_page = new ilContainerStartObjectsPage($this->getId());
557            $orig_page->copy($new_obj->getId(), "cstr", $new_obj->getId());
558        }
559
560        // #10271
561        foreach (self::_getContainerSettings($this->getId()) as $keyword => $value) {
562            self::_writeContainerSetting($new_obj->getId(), $keyword, $value);
563        }
564
565        $new_obj->setNewsTimeline($this->getNewsTimeline());
566        $new_obj->setNewsBlockActivated($this->getNewsBlockActivated());
567        $new_obj->setUseNews($this->getUseNews());
568        $new_obj->setNewsTimelineAutoEntries($this->getNewsTimelineAutoEntries());
569        $new_obj->setNewsTimelineLandingPage($this->getNewsTimelineLandingPage());
570        ilBlockSetting::cloneSettingsOfBlock("news", $this->getId(), $new_obj->getId());
571        $mom_noti = new ilMembershipNotifications($this->getRefId());
572        $mom_noti->cloneSettings($new_obj->getRefId());
573
574        return $new_obj;
575    }
576
577    /**
578     * Clone object dependencies (container sorting)
579     *
580     * @access public
581     * @param int target ref id of new course
582     * @param int copy id
583     * return bool
584     */
585    public function cloneDependencies($a_target_id, $a_copy_id)
586    {
587        $ilLog = $this->log;
588
589        parent::cloneDependencies($a_target_id, $a_copy_id);
590
591        include_once('./Services/Container/classes/class.ilContainerSorting.php');
592        ilContainerSorting::_getInstance($this->getId())->cloneSorting($a_target_id, $a_copy_id);
593
594        // fix internal links to other objects
595        ilContainer::fixInternalLinksAfterCopy($a_target_id, $a_copy_id, $this->getRefId());
596
597        // fix item group references in page content
598        include_once("./Modules/ItemGroup/classes/class.ilObjItemGroup.php");
599        ilObjItemGroup::fixContainerItemGroupRefsAfterCloning($this, $a_copy_id);
600
601        include_once('Services/Object/classes/class.ilObjectLP.php');
602        $olp = ilObjectLP::getInstance($this->getId());
603        $collection = $olp->getCollectionInstance();
604        if ($collection) {
605            $collection->cloneCollection($a_target_id, $a_copy_id);
606        }
607
608        return true;
609    }
610
611    /**
612     * clone all objects according to this container
613     *
614     * @param string $session_id
615     * @param string $client_id
616     * @param string $new_type
617     * @param int $ref_id
618     * @param int $clone_source
619     * @param array $options
620     * @param bool force soap
621     * @param int submode 1 => copy all, 2 => copy content
622     * @return new refid if clone has finished or parameter ref id if cloning is still in progress
623     * @return array(copy_id => xyz, ref_id => new ref_id)
624     */
625    public function cloneAllObject($session_id, $client_id, $new_type, $ref_id, $clone_source, $options, $soap_call = false, $a_submode = 1)
626    {
627        $ilLog = $this->log;
628
629        include_once('./Services/Link/classes/class.ilLink.php');
630        include_once('Services/CopyWizard/classes/class.ilCopyWizardOptions.php');
631
632        $ilAccess = $this->access;
633        $ilErr = $this->error;
634        $rbacsystem = $this->rbacsystem;
635        $tree = $this->tree;
636        $ilUser = $this->user;
637
638        // Save wizard options
639        $copy_id = ilCopyWizardOptions::_allocateCopyId();
640        $wizard_options = ilCopyWizardOptions::_getInstance($copy_id);
641        $wizard_options->saveOwner($ilUser->getId());
642        $wizard_options->saveRoot($clone_source);
643
644        // add entry for source container
645        $wizard_options->initContainer($clone_source, $ref_id);
646
647        foreach ($options as $source_id => $option) {
648            $wizard_options->addEntry($source_id, $option);
649        }
650        $wizard_options->read();
651        $wizard_options->storeTree($clone_source);
652
653        include_once './Services/Object/classes/class.ilObjectCopyGUI.php';
654        if ($a_submode == ilObjectCopyGUI::SUBMODE_CONTENT_ONLY) {
655            ilLoggerFactory::getLogger('obj')->info('Copy content only...');
656            ilLoggerFactory::getLogger('obj')->debug('Added mapping, source ID: ' . $clone_source . ', target ID: ' . $ref_id);
657            $wizard_options->read();
658            $wizard_options->dropFirstNode();
659            $wizard_options->appendMapping($clone_source, $ref_id);
660        }
661
662
663        #print_r($options);
664        // Duplicate session to avoid logout problems with backgrounded SOAP calls
665        $new_session_id = ilSession::_duplicate($session_id);
666        // Start cloning process using soap call
667        include_once 'Services/WebServices/SOAP/classes/class.ilSoapClient.php';
668
669        $soap_client = new ilSoapClient();
670        $soap_client->setResponseTimeout(5);
671        $soap_client->enableWSDL(true);
672
673        $ilLog->write(__METHOD__ . ': Trying to call Soap client...');
674        if ($soap_client->init()) {
675            ilLoggerFactory::getLogger('obj')->info('Calling soap clone method');
676            $res = $soap_client->call('ilClone', array($new_session_id . '::' . $client_id, $copy_id));
677        } else {
678            ilLoggerFactory::getLogger('obj')->warning('SOAP clone call failed. Calling clone method manually');
679            $wizard_options->disableSOAP();
680            $wizard_options->read();
681            include_once('./webservice/soap/include/inc.soap_functions.php');
682            $res = ilSoapFunctions::ilClone($new_session_id . '::' . $client_id, $copy_id);
683        }
684        return array(
685                'copy_id' => $copy_id,
686                'ref_id' => (int) $res
687        );
688    }
689
690    /**
691     * delete category and all related data
692     *
693     * @return	boolean	true if all object data were removed; false if only a references were removed
694     */
695    public function delete()
696    {
697        // always call parent delete function first!!
698        if (!parent::delete()) {
699            return false;
700        }
701        // delete translations
702        $this->obj_trans->delete();
703
704        return true;
705    }
706
707    /**
708    * Get container view mode
709    */
710    public function getViewMode()
711    {
712        return ilContainer::VIEW_BY_TYPE;
713    }
714
715    /**
716    * Get order type default implementation
717    */
718    public function getOrderType()
719    {
720        return $this->order_type ? $this->order_type : ilContainer::SORT_TITLE;
721    }
722
723    public function setOrderType($a_value)
724    {
725        $this->order_type = $a_value;
726    }
727
728    /**
729     * Is classification filter active?
730     * @return bool
731     */
732    public function isClassificationFilterActive() : bool
733    {
734        // apply container classification filters
735        $repo = new ilClassificationSessionRepository($this->getRefId());
736        foreach (ilClassificationProvider::getValidProviders($this->getRefId(), $this->getId(), $this->getType()) as $class_provider) {
737            $id = get_class($class_provider);
738            $current = $repo->getValueForProvider($id);
739            if ($current) {
740                return true;
741            }
742        }
743        return false;
744    }
745
746    /**
747     * Note grp/crs currently allow to filter in their whole subtrees
748     * Catetories only their direct childs
749     * @return bool
750     */
751    public function filteredSubtree() : bool
752    {
753        if ($this->isClassificationFilterActive() && in_array($this->getType(), ["grp", "crs"])) {
754            return true;
755        }
756        return false;
757    }
758
759    /**
760     * Get initial subitems
761     *
762     * @return array
763     */
764    protected function getInitialSubitems() : array
765    {
766        $tree = $this->tree;
767        if ($this->filteredSubtree()) {
768            $objects = $tree->getSubTree($tree->getNodeData($this->getRefId()));
769        } else {
770            $objects = $tree->getChilds($this->getRefId(), "title");
771        }
772        return $objects;
773    }
774
775    /**
776    * Get subitems of container
777    *
778    * @param bool administration panel enabled
779    * @param bool side blocks enabled
780    *
781    * @return	array
782    */
783    public function getSubItems(
784        $a_admin_panel_enabled = false,
785        $a_include_side_block = false,
786        $a_get_single = 0,
787        \ilContainerUserFilter $container_user_filter = null
788    ) {
789        $objDefinition = $this->obj_definition;
790
791        // Caching
792        if (is_array($this->items[(int) $a_admin_panel_enabled][(int) $a_include_side_block]) &&
793            !$a_get_single) {
794            return $this->items[(int) $a_admin_panel_enabled][(int) $a_include_side_block];
795        }
796
797        $objects = $this->getInitialSubitems();
798        $objects = $this->applyContainerUserFilter($objects, $container_user_filter);
799        $objects = self::getCompleteDescriptions($objects);
800
801        // apply container classification filters
802        $repo = new ilClassificationSessionRepository($this->getRefId());
803        foreach (ilClassificationProvider::getValidProviders($this->getRefId(), $this->getId(), $this->getType()) as $class_provider) {
804            $id = get_class($class_provider);
805            $current = $repo->getValueForProvider($id);
806            if ($current) {
807                $class_provider->setSelection($current);
808                $filtered = $class_provider->getFilteredObjects();
809                $objects = array_filter($objects, function ($i) use ($filtered) {
810                    return (is_array($filtered) && in_array($i["obj_id"], $filtered));
811                });
812                //if (count($filtered) > 0) {
813                //    var_dump($filtered);
814                //    echo "<br><br>";
815                //    var_dump($objects);
816                //    exit;
817                //}
818            }
819        }
820
821        $found = false;
822        $all_ref_ids = array();
823
824        if (!self::$data_preloaded) {
825            include_once("./Services/Object/classes/class.ilObjectListGUIPreloader.php");
826            $preloader = new ilObjectListGUIPreloader(ilObjectListGUI::CONTEXT_REPOSITORY);
827        }
828
829        include_once('Services/Container/classes/class.ilContainerSorting.php');
830        $sort = ilContainerSorting::_getInstance($this->getId());
831
832        // TODO: check this
833        // get items attached to a session
834        include_once './Modules/Session/classes/class.ilEventItems.php';
835        $event_items = ilEventItems::_getItemsOfContainer($this->getRefId());
836
837        $classification_filter_active = $this->isClassificationFilterActive();
838        foreach ($objects as $key => $object) {
839            if ($a_get_single > 0 && $object["child"] != $a_get_single) {
840                continue;
841            }
842
843            // hide object types in devmode
844            if ($objDefinition->getDevMode($object["type"]) || $object["type"] == "adm"
845                || $object["type"] == "rolf") {
846                continue;
847            }
848
849            // remove inactive plugins
850            if ($objDefinition->isInactivePlugin($object["type"])) {
851                continue;
852            }
853
854            // BEGIN WebDAV: Don't display hidden Files, Folders and Categories
855            if (in_array($object['type'], array('file','fold','cat'))) {
856                include_once 'Modules/File/classes/class.ilObjFileAccess.php';
857                if (ilObjFileAccess::_isFileHidden($object['title'])) {
858                    $this->setHiddenFilesFound(true);
859                    if (!$a_admin_panel_enabled) {
860                        continue;
861                    }
862                }
863            }
864            // END WebDAV: Don't display hidden Files, Folders and Categories
865
866            // including event items!
867            if (!self::$data_preloaded) {
868                $preloader->addItem($object["obj_id"], $object["type"], $object["child"]);
869            }
870
871            // filter out items that are attached to an event
872            if (in_array($object['ref_id'], $event_items) && !$classification_filter_active) {
873                continue;
874            }
875
876            // filter side block items
877            if (!$a_include_side_block && $objDefinition->isSideBlock($object['type'])) {
878                continue;
879            }
880
881            $all_ref_ids[] = $object["child"];
882        }
883
884        // data preloader
885        if (!self::$data_preloaded) {
886            $preloader->preload();
887            unset($preloader);
888
889            self::$data_preloaded = true;
890        }
891
892        foreach ($objects as $key => $object) {
893            // see above, objects were filtered
894            if (!in_array($object["child"], $all_ref_ids)) {
895                continue;
896            }
897
898            // group object type groups together (e.g. learning resources)
899            $type = $objDefinition->getGroupOfObj($object["type"]);
900            if ($type == "") {
901                $type = $object["type"];
902            }
903
904            // this will add activation properties
905            $this->addAdditionalSubItemInformation($object);
906
907            $this->items[$type][$key] = $object;
908
909            $this->items["_all"][$key] = $object;
910            if ($object["type"] != "sess") {
911                $this->items["_non_sess"][$key] = $object;
912            }
913        }
914        $this->items[(int) $a_admin_panel_enabled][(int) $a_include_side_block]
915            = $sort->sortItems($this->items);
916
917        return $this->items[(int) $a_admin_panel_enabled][(int) $a_include_side_block];
918    }
919
920    /**
921    * Check whether we got any items
922    */
923    public function gotItems()
924    {
925        if (is_array($this->items["_all"]) && count($this->items["_all"]) > 0) {
926            return true;
927        }
928        return false;
929    }
930
931    /**
932    * Add additional information to sub item, e.g. used in
933    * courses for timings information etc.
934    */
935    public function addAdditionalSubItemInformation(&$object)
936    {
937    }
938
939    /**
940    * Get grouped repository object types.
941    *
942    * @return	array	array of object types
943    */
944    public function getGroupedObjTypes()
945    {
946        $objDefinition = $this->obj_definition;
947
948        if (empty($this->type_grps)) {
949            $this->type_grps = $objDefinition->getGroupedRepositoryObjectTypes($this->getType());
950        }
951        return $this->type_grps;
952    }
953
954    /**
955    * Check whether page editing is allowed for container
956    */
957    public function enablePageEditing()
958    {
959        $ilSetting = $this->setting;
960
961        // @todo: this will need a more general approach
962        if ($ilSetting->get("enable_cat_page_edit")) {
963            return true;
964        }
965    }
966
967    /**
968    * Create
969    */
970    public function create()
971    {
972        global $DIC;
973
974        $lng = $DIC->language();
975
976        $ret = parent::create();
977
978        // set translation object, since we have an object id now
979        $this->obj_trans = ilObjectTranslation::getInstance($this->getId());
980
981        // add default translation
982        $this->addTranslation(
983            $this->getTitle(),
984            $this->getDescription(),
985            $lng->getDefaultLanguage(),
986            true
987        );
988
989        if (((int) $this->getStyleSheetId()) > 0) {
990            include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
991            ilObjStyleSheet::writeStyleUsage($this->getId(), $this->getStyleSheetId());
992        }
993
994        $log = ilLoggerFactory::getLogger("cont");
995        $log->debug("Create Container, id: " . $this->getId());
996
997        self::_writeContainerSetting($this->getId(), "news_timeline", (int) $this->getNewsTimeline());
998        self::_writeContainerSetting($this->getId(), "news_timeline_incl_auto", (int) $this->getNewsTimelineAutoEntries());
999        self::_writeContainerSetting($this->getId(), "news_timeline_landing_page", (int) $this->getNewsTimelineLandingPage());
1000        include_once("./Services/Object/classes/class.ilObjectServiceSettingsGUI.php");
1001        self::_writeContainerSetting($this->getId(), ilObjectServiceSettingsGUI::NEWS_VISIBILITY, (int) $this->getNewsBlockActivated());
1002        self::_writeContainerSetting($this->getId(), ilObjectServiceSettingsGUI::USE_NEWS, (int) $this->getUseNews());
1003
1004        return $ret;
1005    }
1006
1007    /**
1008     * @inheritdoc
1009     */
1010    public function putInTree($a_parent_ref)
1011    {
1012        parent::putInTree($a_parent_ref);
1013
1014        // copy title, icon actions visibilities
1015        if (self::_lookupContainerSetting(ilObject::_lookupObjId($a_parent_ref), "hide_header_icon_and_title")) {
1016            self::_writeContainerSetting($this->getId(), "hide_header_icon_and_title", true);
1017        }
1018        if (self::_lookupContainerSetting(ilObject::_lookupObjId($a_parent_ref), "hide_top_actions")) {
1019            self::_writeContainerSetting($this->getId(), "hide_top_actions", true);
1020        }
1021    }
1022
1023    /**
1024    * Update
1025    */
1026    public function update()
1027    {
1028        $ret = parent::update();
1029
1030        $trans = $this->getObjectTranslation();
1031        $trans->setDefaultTitle($this->getTitle());
1032        $trans->setDefaultDescription($this->getLongDescription());
1033        $trans->save();
1034
1035        include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
1036        ilObjStyleSheet::writeStyleUsage($this->getId(), $this->getStyleSheetId());
1037
1038        $log = ilLoggerFactory::getLogger("cont");
1039        $log->debug("Update Container, id: " . $this->getId());
1040
1041        self::_writeContainerSetting($this->getId(), "news_timeline", (int) $this->getNewsTimeline());
1042        self::_writeContainerSetting($this->getId(), "news_timeline_incl_auto", (int) $this->getNewsTimelineAutoEntries());
1043        self::_writeContainerSetting($this->getId(), "news_timeline_landing_page", (int) $this->getNewsTimelineLandingPage());
1044        include_once("./Services/Object/classes/class.ilObjectServiceSettingsGUI.php");
1045        self::_writeContainerSetting($this->getId(), ilObjectServiceSettingsGUI::NEWS_VISIBILITY, (int) $this->getNewsBlockActivated());
1046        self::_writeContainerSetting($this->getId(), ilObjectServiceSettingsGUI::USE_NEWS, (int) $this->getUseNews());
1047
1048        return $ret;
1049    }
1050
1051
1052    /**
1053     * read
1054     *
1055     * @access public
1056     * @param
1057     * @return
1058     */
1059    public function read()
1060    {
1061        parent::read();
1062
1063        include_once("./Services/Container/classes/class.ilContainerSortingSettings.php");
1064        $this->setOrderType(ilContainerSortingSettings::_lookupSortMode($this->getId()));
1065
1066        include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
1067        $this->setStyleSheetId((int) ilObjStyleSheet::lookupObjectStyle($this->getId()));
1068
1069        $this->readContainerSettings();
1070        $this->obj_trans = ilObjectTranslation::getInstance($this->getId());
1071    }
1072
1073    /**
1074     * Read container settings
1075     *
1076     * @param
1077     * @return
1078     */
1079    public function readContainerSettings()
1080    {
1081        $this->setNewsTimeline(self::_lookupContainerSetting($this->getId(), "news_timeline"));
1082        $this->setNewsTimelineAutoEntries(self::_lookupContainerSetting($this->getId(), "news_timeline_incl_auto"));
1083        $this->setNewsTimelineLandingPage(self::_lookupContainerSetting($this->getId(), "news_timeline_landing_page"));
1084        include_once("./Services/Object/classes/class.ilObjectServiceSettingsGUI.php");
1085        $this->setNewsBlockActivated(self::_lookupContainerSetting(
1086            $this->getId(),
1087            ilObjectServiceSettingsGUI::NEWS_VISIBILITY,
1088            $this->setting->get('block_activated_news', true)
1089        ));
1090        $this->setUseNews(self::_lookupContainerSetting($this->getId(), ilObjectServiceSettingsGUI::USE_NEWS, true));
1091    }
1092
1093
1094    /**
1095     * overwrites description fields to long or short description in an assoc array
1096     * keys needed (obj_id and description)
1097     *
1098     * @param array $objects
1099     * @return array
1100     */
1101    public static function getCompleteDescriptions(array $objects)
1102    {
1103        global $DIC;
1104
1105        $ilSetting = $DIC->settings();
1106        $ilObjDataCache = $DIC["ilObjDataCache"];
1107        // using long descriptions?
1108        $short_desc = $ilSetting->get("rep_shorten_description");
1109        $short_desc_max_length = $ilSetting->get("rep_shorten_description_length");
1110        if (!$short_desc || $short_desc_max_length != ilObject::DESC_LENGTH) {
1111            // using (part of) shortened description
1112            if ($short_desc && $short_desc_max_length && $short_desc_max_length < ilObject::DESC_LENGTH) {
1113                foreach ($objects as $key => $object) {
1114                    $objects[$key]["description"] = ilUtil::shortenText($object["description"], $short_desc_max_length, true);
1115                }
1116            }
1117            // using (part of) long description
1118            else {
1119                $obj_ids = array();
1120                foreach ($objects as $key => $object) {
1121                    $obj_ids[] = $object["obj_id"];
1122                }
1123                if (sizeof($obj_ids)) {
1124                    $long_desc = ilObject::getLongDescriptions($obj_ids);
1125                    foreach ($objects as $key => $object) {
1126                        // #12166 - keep translation, ignore long description
1127                        if ($ilObjDataCache->isTranslatedDescription($object["obj_id"])) {
1128                            $long_desc[$object["obj_id"]] = $object["description"];
1129                        }
1130                        if ($short_desc && $short_desc_max_length) {
1131                            $long_desc[$object["obj_id"]] = ilUtil::shortenText($long_desc[$object["obj_id"]], $short_desc_max_length, true);
1132                        }
1133                        $objects[$key]["description"] = $long_desc[$object["obj_id"]];
1134                    }
1135                }
1136            }
1137        }
1138        return $objects;
1139    }
1140
1141    /**
1142     * Fix internal links after copy process
1143     *
1144     * @param int $a_target_id ref if of new container
1145     * @param int $a_copy_id copy process id
1146     */
1147    protected static function fixInternalLinksAfterCopy($a_target_id, $a_copy_id, $a_source_ref_id)
1148    {
1149        global $DIC;
1150
1151        /** @var ilObjectDefinition $obj_definition */
1152        $obj_definition = $DIC["objDefinition"];
1153
1154        $obj_id = ilObject::_lookupObjId($a_target_id);
1155        include_once("./Services/Container/classes/class.ilContainerPage.php");
1156
1157        include_once("./Services/CopyWizard/classes/class.ilCopyWizardOptions.php");
1158        $cwo = ilCopyWizardOptions::_getInstance($a_copy_id);
1159        $mapping = $cwo->getMappings();
1160
1161        if (ilContainerPage::_exists("cont", $obj_id)) {
1162            $pg = new ilContainerPage($obj_id);
1163            $pg->handleRepositoryLinksOnCopy($mapping, $a_source_ref_id);
1164            $pg->update(true, true);
1165        }
1166
1167        foreach ($mapping as $old_ref_id => $new_ref_id) {
1168            if (!is_numeric($old_ref_id) || !is_numeric($new_ref_id)) {
1169                continue;
1170            }
1171
1172            $type = ilObject::_lookupType($new_ref_id, true);
1173            $class = 'il' . $obj_definition->getClassName($type) . 'PageCollector';
1174            $loc = $obj_definition->getLocation($type);
1175            $file = $loc . '/class.' . $class . '.php';
1176
1177            if (is_file($file)) {
1178                /** @var ilCOPageCollectorInterface $coll */
1179                $coll = new $class();
1180                foreach ($coll->getAllPageIds(ilObject::_lookupObjId($new_ref_id)) as $page_id) {
1181                    if (ilPageObject::_exists($page_id['parent_type'], $page_id['id'], $page_id['lang'])) {
1182                        /** @var ilPageObject $page */
1183                        $page = ilPageObjectFactory::getInstance($page_id['parent_type'], $page_id['id'], 0, $page_id['lang']);
1184                        $page->handleRepositoryLinksOnCopy($mapping, $a_source_ref_id);
1185                        $page->update(true, true);
1186                    }
1187                }
1188            }
1189        }
1190    }
1191
1192    /**
1193     * Remove all translations of container
1194     */
1195    public function removeTranslations()
1196    {
1197        $this->obj_trans->delete();
1198    }
1199
1200    /**
1201     * Delete translation
1202     *
1203     * @param $a_lang
1204     */
1205    public function deleteTranslation($a_lang)
1206    {
1207        $this->obj_trans->removeLanguage($a_lang);
1208        $this->obj_trans->save();
1209    }
1210
1211    /**
1212     * Add translation
1213     *
1214     * @param $a_title
1215     * @param $a_desc
1216     * @param $a_lang
1217     * @param $a_lang_default
1218     * @return bool
1219     */
1220    public function addTranslation($a_title, $a_desc, $a_lang, $a_lang_default)
1221    {
1222        if (empty($a_title)) {
1223            $a_title = "NO TITLE";
1224        }
1225
1226        $this->obj_trans->addLanguage($a_lang, $a_title, $a_desc, $a_lang_default, true);
1227        $this->obj_trans->save();
1228
1229        return true;
1230    }
1231
1232    /**
1233     * Apply container user filter on objects
1234     *
1235     * @todo this deserces a decentralized general concept (consumers provide object filter types)
1236     * @todo move selects to respective components
1237     *
1238     * @param $objects
1239     * @param ilContainerUserFilter|null $container_user_filter
1240     * @return array
1241     * @throws ilException
1242     */
1243    protected function applyContainerUserFilter($objects, ilContainerUserFilter $container_user_filter = null)
1244    {
1245        global $DIC;
1246        $db = $DIC->database();
1247
1248        if (is_null($container_user_filter)) {
1249            return $objects;
1250        }
1251
1252        if ($container_user_filter->isEmpty() && !ilContainer::_lookupContainerSetting($this->getId(), "filter_show_empty", false)) {
1253            return [];
1254        }
1255
1256
1257        $obj_ids = array_map(function ($i) {
1258            return $i["obj_id"];
1259        }, $objects);
1260        $filter_data = $container_user_filter->getData();
1261        foreach ($filter_data as $key => $val) {
1262            if (count($obj_ids) == 0) {    // stop if no object ids are left
1263                continue;
1264            }
1265            if (!in_array(substr($key, 0, 4), ["adv_", "std_"])) {
1266                continue;
1267            }
1268            if ($val == "") {
1269                continue;
1270            }
1271            $field_id = substr($key, 4);
1272            $val = ilUtil::stripSlashes($val);
1273            $query_parser = new ilQueryParser($val);
1274            if (substr($key, 0, 4) == "std_") {
1275                // object type
1276                if ($field_id == ilContainerFilterField::STD_FIELD_OBJECT_TYPE) {
1277                    $result = null;
1278                    $set = $db->queryF(
1279                        "SELECT obj_id FROM object_data " .
1280                        " WHERE  " . $db->in("obj_id", $obj_ids, false, "integer") .
1281                        " AND type = %s",
1282                        array("text"),
1283                        array($val)
1284                        );
1285                    $result_obj_ids = [];
1286                    while ($rec = $db->fetchAssoc($set)) {
1287                        $result_obj_ids[] = $rec["obj_id"];
1288                    }
1289                    $obj_ids = array_intersect($obj_ids, $result_obj_ids);
1290                } elseif ($field_id == ilContainerFilterField::STD_FIELD_ONLINE) {
1291                    if (in_array($val, [1,2])) {
1292                        $online_where = ($val == 1)
1293                            ? " (offline <> " . $db->quote(1, "integer") . " OR offline IS NULL) "
1294                            :" offline = " . $db->quote(1, "integer") . " ";
1295                        $result = null;
1296                        $set = $db->queryF(
1297                            "SELECT obj_id FROM object_data " .
1298                            " WHERE  " . $db->in("obj_id", $obj_ids, false, "integer") .
1299                            " AND " . $online_where,
1300                            [],
1301                            []
1302                        );
1303                        $result_obj_ids = [];
1304                        while ($rec = $db->fetchAssoc($set)) {
1305                            $result_obj_ids[] = $rec["obj_id"];
1306                        }
1307                        $obj_ids = array_intersect($obj_ids, $result_obj_ids);
1308                        $obj_ids = $this->legacyOnlineFilter($obj_ids, $objects, $val);
1309                    }
1310                } elseif ($field_id == ilContainerFilterField::STD_FIELD_TUTORIAL_SUPPORT) {
1311                    $result = null;
1312                    $set = $db->queryF(
1313                        "SELECT DISTINCT(obj_id) FROM obj_members m JOIN usr_data u ON (u.usr_id = m.usr_id) " .
1314                        " WHERE  " . $db->in("m.obj_id", $obj_ids, false, "integer") .
1315                        " AND " . $db->like("u.lastname", "text", $val) .
1316                        " AND m.contact = %s",
1317                        array("integer"),
1318                        array(1)
1319                        );
1320                    $result_obj_ids = [];
1321                    while ($rec = $db->fetchAssoc($set)) {
1322                        $result_obj_ids[] = $rec["obj_id"];
1323                    }
1324                    $obj_ids = array_intersect($obj_ids, $result_obj_ids);
1325                } elseif ($field_id == ilContainerFilterField::STD_FIELD_COPYRIGHT) {
1326                    $result = null;
1327                    $set = $db->queryF(
1328                        "SELECT DISTINCT(rbac_id) FROM il_meta_rights " .
1329                        " WHERE  " . $db->in("rbac_id", $obj_ids, false, "integer") .
1330                        " AND description = %s ",
1331                        array("text"),
1332                        array('il_copyright_entry__' . IL_INST_ID . '__' . $val)
1333                        );
1334                    $result_obj_ids = [];
1335                    while ($rec = $db->fetchAssoc($set)) {
1336                        $result_obj_ids[] = $rec["rbac_id"];
1337                    }
1338                    $obj_ids = array_intersect($obj_ids, $result_obj_ids);
1339                } else {
1340                    include_once 'Services/Search/classes/class.ilObjectSearchFactory.php';
1341                    include_once 'Services/Search/classes/class.ilQueryParser.php';
1342
1343                    #$query_parser->setCombination($this->options['title_ao']);
1344                    $query_parser->setCombination(QP_COMBINATION_OR);
1345                    $query_parser->parse();
1346                    $meta_search = ilObjectSearchFactory::_getAdvancedSearchInstance($query_parser);
1347
1348                    //$meta_search->setFilter($this->filter);		// object types ['lm', ...]
1349                    switch ($field_id) {
1350                        case ilContainerFilterField::STD_FIELD_TITLE_DESCRIPTION:
1351                        case ilContainerFilterField::STD_FIELD_DESCRIPTION:
1352                        case ilContainerFilterField::STD_FIELD_TITLE:
1353                            $meta_search->setMode('title_description');
1354                            break;
1355                        case ilContainerFilterField::STD_FIELD_KEYWORD:
1356                            $meta_search->setMode('keyword_all');
1357                            break;
1358                        case ilContainerFilterField::STD_FIELD_AUTHOR:
1359                            $meta_search->setMode('contribute');
1360                            break;
1361
1362                    }
1363                    //$meta_search->setOptions($this->options);
1364                    $result = $meta_search->performSearch();
1365                }
1366            } else {		// advanced metadata search
1367                $field = ilAdvancedMDFieldDefinition::getInstance($field_id);
1368
1369                $field_form = ilADTFactory::getInstance()->getSearchBridgeForDefinitionInstance($field->getADTDefinition(), true, false);
1370                $field_form->setElementId("query[" . $key . "]");
1371                $field_form->validate();
1372
1373                /**
1374                 * Workaround:
1375                 *
1376                 * Only text fields take care of $parser_value being passed through
1377                 * new ilQueryParser($parser_value), thus other fields pass values by setting
1378                 * directly in the ADT objects. This could go to a new bridge.
1379                 */
1380                if ($field instanceof ilAdvancedMDFieldDefinitionSelectMulti) {
1381                    $field_form->getADT()->setSelections([$val]);
1382                }
1383                if ($field instanceof ilAdvancedMDFieldDefinitionSelect) {
1384                    $adt = $field_form->getADT();
1385                    if ($adt instanceof ilADTMultiEnumText) {
1386                        $field_form->getADT()->setSelections([$val]);
1387                    } else {
1388                        $field_form->getADT()->setSelection($val);
1389                    }
1390                }
1391
1392                include_once 'Services/Search/classes/class.ilQueryParser.php';
1393                include_once 'Services/Search/classes/class.ilObjectSearchFactory.php';
1394                $adv_md_search = ilObjectSearchFactory::_getAdvancedMDSearchInstance($query_parser);
1395                //$adv_md_search->setFilter($this->filter);	// this could be set to an array of object types
1396                $adv_md_search->setDefinition($field);            // e.g. ilAdvancedMDFieldDefinitionSelectMulti
1397                $adv_md_search->setIdFilter(array(0));
1398                $adv_md_search->setSearchElement($field_form);    // e.g. ilADTEnumSearchBridgeMulti
1399                $result = $adv_md_search->performSearch();
1400            }
1401
1402            // intersect results
1403            if ($result instanceof ilSearchResult) {
1404                $result_obj_ids = array_map(
1405                    function ($i) {
1406                        return $i["obj_id"];
1407                    },
1408                    $result->getEntries()
1409                );
1410                $obj_ids = array_intersect($obj_ids, $result_obj_ids);
1411            }
1412        }
1413        $objects = array_filter($objects, function ($o) use ($obj_ids) {
1414            return in_array($o["obj_id"], $obj_ids);
1415        });
1416
1417        return $objects;
1418    }
1419
1420    /**
1421     * Legacy online filter
1422     *
1423     * This can be removed, once all objects use the central online/offline property
1424     *
1425     * @param $obj_ids
1426     * @param $objects
1427     * @param $val
1428     * @return mixed
1429     */
1430    protected function legacyOnlineFilter($obj_ids, $objects, $val)
1431    {
1432        $legacy_types = ["glo", "wiki", "qpl", "book", "dcl", "prtt"];
1433        foreach ($legacy_types as $type) {
1434            $lobjects = array_filter($objects, function($o) use ($type) {
1435                return ($o["type"] == $type);
1436            });
1437            $lobj_ids = array_map(function($i){
1438                return $i["obj_id"];
1439            }, $lobjects);
1440            switch($type) {
1441                case "glo":
1442                    $status = ilObjGlossaryAccess::_lookupOnlineStatus($lobj_ids);
1443                    break;
1444                case "wiki":
1445                    $status = ilObjWikiAccess::_lookupOnlineStatus($lobj_ids);
1446                    break;
1447                case "book":
1448                    $status = ilObjBookingPoolAccess::_lookupOnlineStatus($lobj_ids);
1449                    break;
1450                case "qpl":
1451                    $status = [];
1452                    foreach ($lobj_ids as $lid) {
1453                        $status[$lid] = ilObjQuestionPoolAccess::isOnline($lid);
1454                    }
1455                    break;
1456                case "dcl":
1457                    $status = [];
1458                    foreach ($lobj_ids as $lid) {
1459                        $status[$lid] = ilObjDataCollectionAccess::_lookupOnline($lid);
1460                    }
1461                    break;
1462                case "prtt":
1463                    $status = ilObjPortfolioTemplateAccess::_lookupOnlineStatus($lobj_ids);
1464                    break;
1465            }
1466            foreach($status as $obj_id => $online) {
1467                if ($val == 1 && !$online || $val == 2 && $online) {
1468                    if (($key = array_search($obj_id, $obj_ids)) !== false) {
1469                        unset($obj_ids[$key]);
1470                    }
1471                }  else if (!in_array($obj_id, $obj_ids)) {
1472                    $obj_ids[] = $obj_id;
1473                }
1474            }
1475        }
1476
1477        return $obj_ids;
1478    }
1479
1480} // END class ilContainer
1481