1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4/**
5 * GUI class for the workflow of copying objects
6 *
7 * @author Stefan Meyer <smeyer.ilias@gmx.de>
8 * @author Stefan Hecken <stefan.hecken@concepts-and-training.de>
9 * @version $Id$
10 *
11 * @ilCtrl_Calls ilObjectCopyGUI:
12 *
13 * @ingroup ServicesObject
14 */
15class ilObjectCopyGUI
16{
17    /**
18     * @var ilCtrl
19     */
20    protected $ctrl;
21
22    /**
23     * @var ilTree
24     */
25    protected $tree;
26
27    /**
28     * @var ilTabsGUI
29     */
30    protected $tabs;
31
32    /**
33     * @var ilToolbarGUI
34     */
35    protected $toolbar;
36
37    /**
38     * @var ilTemplate
39     */
40    protected $tpl;
41
42    /**
43     * @var ilObjectDefinition
44     */
45    protected $obj_definition;
46
47    /**
48     * @var ilObjectDataCache
49     */
50    protected $obj_data_cache;
51
52    /**
53     * @var ilAccessHandler
54     */
55    protected $access;
56
57    /**
58     * @var ilErrorHandling
59     */
60    protected $error;
61
62    /**
63     * @var ilRbacSystem
64     */
65    protected $rbacsystem;
66
67    /**
68     * @var ilObjUser
69     */
70    protected $user;
71
72    /**
73     * @var ilRbacReview
74     */
75    protected $rbacreview;
76
77    const SOURCE_SELECTION = 1;
78    const TARGET_SELECTION = 2;
79    const SEARCH_SOURCE = 3;
80
81    const SUBMODE_COMPLETE = 1;
82    const SUBMODE_CONTENT_ONLY = 2;
83
84    // tabs
85    const TAB_SELECTION_TARGET_TREE = 1;
86    const TAB_SELECTION_SOURCE_TREE = 2;
87    const TAB_SELECTION_MEMBERSHIP = 3;
88
89    // group selection of source or target
90    const TAB_GROUP_SC_SELECTION = 1;
91
92
93    private $mode = 0;
94    private $sub_mode = self::SUBMODE_COMPLETE;
95
96    private $lng;
97
98    private $parent_obj = null;
99
100    private $type = '';
101
102    private $sources = array();
103
104    // begin-patch multi copy
105    private $targets = array();
106    private $targets_copy_id = array();
107    // end-patch multi copy
108
109    /**
110     * @var ilLogger
111     */
112    private $log = null;
113
114
115    /**
116     * Constructor
117     * @return
118     */
119    public function __construct($a_parent_gui)
120    {
121        global $DIC;
122
123        $this->ctrl = $DIC->ctrl();
124        $this->tree = $DIC->repositoryTree();
125        $this->tabs = $DIC->tabs();
126        $this->toolbar = $DIC->toolbar();
127        $this->tpl = $DIC["tpl"];
128        $this->obj_definition = $DIC["objDefinition"];
129        $this->obj_data_cache = $DIC["ilObjDataCache"];
130        $this->access = $DIC->access();
131        $this->error = $DIC["ilErr"];
132        $this->rbacsystem = $DIC->rbac()->system();
133        $this->user = $DIC->user();
134        $this->rbacreview = $DIC->rbac()->review();
135        $this->log = $DIC["ilLog"];
136        $ilCtrl = $DIC->ctrl();
137        $lng = $DIC->language();
138
139        $this->lng = $lng;
140        $this->lng->loadLanguageModule('search');
141        $this->lng->loadLanguageModule('obj');
142
143        $this->parent_obj = $a_parent_gui;
144
145        $this->log = ilLoggerFactory::getLogger('obj');
146    }
147
148    /**
149     * Control class handling
150     * @return
151     */
152    public function executeCommand()
153    {
154        $ilCtrl = $this->ctrl;
155
156        $this->init();
157        $this->initTabs();
158
159        $next_class = $ilCtrl->getNextClass($this);
160        $cmd = $ilCtrl->getCmd();
161
162        switch ($next_class) {
163            default:
164                $this->$cmd();
165                break;
166        }
167    }
168
169    /**
170     * Init return, mode
171     * @return
172     */
173    protected function init()
174    {
175        $ilCtrl = $this->ctrl;
176
177        if ((int) $_REQUEST['smode']) {
178            $this->setSubMode((int) $_REQUEST['smode']);
179            $ilCtrl->setParameter($this, 'smode', $this->getSubMode());
180            ilLoggerFactory::getLogger('obj')->debug('Submode is: ' . $this->getSubMode());
181        }
182
183        // save sources
184        if ($_REQUEST['source_ids']) {
185            $this->setSource(explode('_', $_REQUEST['source_ids']));
186            $ilCtrl->setParameter($this, 'source_ids', implode('_', $this->getSources()));
187            ilLoggerFactory::getLogger('obj')->debug('Multiple sources: ' . implode('_', $this->getSources()));
188        }
189        if ($_REQUEST['source_id']) {
190            $this->setSource(array((int) $_REQUEST['source_id']));
191            $ilCtrl->setParameter($this, 'source_ids', implode('_', $this->getSources()));
192            ilLoggerFactory::getLogger('obj')->debug('source_id is set: ' . implode('_', $this->getSources()));
193        }
194        if ($this->getFirstSource()) {
195            $this->setType(
196                ilObject::_lookupType(ilObject::_lookupObjId($this->getFirstSource()))
197            );
198        }
199
200        // creation screen: copy section
201        if ($_REQUEST['new_type']) {
202            $this->setMode(self::SEARCH_SOURCE);
203            $this->setType($_REQUEST['new_type']);
204            $this->setTarget((int) $_GET['ref_id']);
205
206            $ilCtrl->setParameter($this, 'new_type', $this->getType());
207            $ilCtrl->setParameterByClass(get_class($this->getParentObject()), 'new_type', $this->getType());
208            $ilCtrl->setParameterByClass(get_class($this->getParentObject()), 'cpfl', 1);
209            $ilCtrl->setReturnByClass(get_class($this->getParentObject()), 'create');
210
211            ilLoggerFactory::getLogger('obj')->debug('Copy from object creation for type: ' . $this->getType());
212            return true;
213        }
214        // adopt content, and others?
215        elseif ($_REQUEST['selectMode'] == self::SOURCE_SELECTION) {
216            $this->setMode(self::SOURCE_SELECTION);
217
218            $ilCtrl->setParameterByClass(get_class($this->parent_obj), 'selectMode', self::SOURCE_SELECTION);
219            $this->setTarget((int) $_GET['ref_id']);
220            $ilCtrl->setReturnByClass(get_class($this->parent_obj), '');
221
222            ilLoggerFactory::getLogger('obj')->debug('Source selection mode. Target is: ' . $this->getFirstTarget());
223        } elseif ($_REQUEST['selectMode'] == self::TARGET_SELECTION) {
224            $this->setMode(self::TARGET_SELECTION);
225            $ilCtrl->setReturnByClass(get_class($this->parent_obj), '');
226            ilLoggerFactory::getLogger('obj')->debug('Target selection mode.');
227        }
228
229
230        // save targets
231        if ($_REQUEST['target_ids']) {
232            $this->setTargets(explode('_', $_REQUEST['target_ids']));
233            ilLoggerFactory::getLogger('obj')->debug('targets are: ' . print_r($this->getTargets(), true));
234        }
235    }
236
237    /**
238     * Init tabs
239     * General
240     */
241    protected function initTabs()
242    {
243        $lng = $this->lng;
244        $ilTabs = $this->tabs;
245        $ilCtrl = $this->ctrl;
246
247        $lng->loadLanguageModule('cntr');
248        $ilTabs->clearTargets();
249        $ilTabs->setBackTarget(
250            $lng->txt('tab_back_to_repository'),
251            $ilCtrl->getParentReturn($this->parent_obj)
252        );
253    }
254
255    /**
256     * Set tabs
257     * @param type $a_tab_group
258     * @param type $a_active_tab
259     */
260    protected function setTabs($a_tab_group, $a_active_tab)
261    {
262        $lng = $this->lng;
263        $ilTabs = $this->tabs;
264        $ilCtrl = $this->ctrl;
265
266        if ($a_tab_group == self::TAB_GROUP_SC_SELECTION) {
267            if ($this->getSubMode() == self::SUBMODE_CONTENT_ONLY) {
268                if ($this->getMode() == self::SOURCE_SELECTION) {
269                    $ilTabs->addTab(
270                        self::TAB_SELECTION_SOURCE_TREE,
271                        $lng->txt('cntr_copy_repo_tree'),
272                        $ilCtrl->getLinkTarget($this, 'initSourceSelection')
273                    );
274                    $ilTabs->addTab(
275                        self::TAB_SELECTION_MEMBERSHIP,
276                        $lng->txt('cntr_copy_crs_grp'),
277                        $ilCtrl->getLinkTarget($this, 'showSourceSelectionMembership')
278                    );
279                }
280            }
281        }
282        $ilTabs->activateTab($a_active_tab);
283    }
284
285
286    /**
287     * Adopt content (crs in crs, grp in grp, crs in grp or grp in crs)
288     * @return type
289     */
290    protected function adoptContent()
291    {
292        $ilCtrl = $this->ctrl;
293
294        $ilCtrl->setParameter($this, 'smode', self::SUBMODE_CONTENT_ONLY);
295        $ilCtrl->setParameter($this, 'selectMode', self::SOURCE_SELECTION);
296
297
298        $this->setSubMode(self::SUBMODE_CONTENT_ONLY);
299        $this->setMode(self::SOURCE_SELECTION);
300        $this->setTarget((int) $_GET['ref_id']);
301
302
303        return $this->initSourceSelection();
304    }
305
306    /**
307     * Init copy from repository/search list commands
308     * @return
309     */
310    protected function initTargetSelection()
311    {
312        $ilCtrl = $this->ctrl;
313        $tree = $this->tree;
314        $ilCtrl->setParameter($this, 'selectMode', self::TARGET_SELECTION);
315        // empty session on init
316        $_SESSION['paste_copy_repexpand'] = array();
317
318        // copy opened nodes from repository explorer
319        $_SESSION['paste_copy_repexpand'] = is_array($_SESSION['repexpand']) ? $_SESSION['repexpand'] : array();
320
321        // begin-patch mc
322        $this->setTargets(array());
323        // cognos-blu-patch: end
324
325        // open current position
326
327        foreach ($this->getSources() as $source_id) {
328            if ($source_id) {
329                $path = $tree->getPathId($source_id);
330                foreach ((array) $path as $node_id) {
331                    if (!in_array($node_id, $_SESSION['paste_copy_repexpand'])) {
332                        $_SESSION['paste_copy_repexpand'][] = $node_id;
333                    }
334                }
335            }
336        }
337
338        $ilCtrl->setReturnByClass(get_class($this->parent_obj), '');
339        $this->showTargetSelectionTree();
340    }
341
342    /**
343     * Init source selection
344     * @return
345     */
346    protected function initSourceSelection()
347    {
348        $ilCtrl = $this->ctrl;
349        $tree = $this->tree;
350
351        // empty session on init
352        $_SESSION['paste_copy_repexpand'] = array();
353
354        // copy opened nodes from repository explorer
355        $_SESSION['paste_copy_repexpand'] = is_array($_SESSION['repexpand']) ? $_SESSION['repexpand'] : array();
356
357        $this->setTabs(self::TAB_GROUP_SC_SELECTION, self::TAB_SELECTION_SOURCE_TREE);
358
359
360        // open current position
361        // begin-patch mc
362        foreach ($this->getTargets() as $target_ref_id) {
363            $path = $tree->getPathId($target_ref_id);
364            foreach ((array) $path as $node_id) {
365                if (!in_array($node_id, $_SESSION['paste_copy_repexpand'])) {
366                    $_SESSION['paste_copy_repexpand'][] = $node_id;
367                }
368            }
369        }
370        // end-patch multi copy
371        $ilCtrl->setReturnByClass(get_class($this->parent_obj), '');
372        $this->showSourceSelectionTree();
373    }
374
375
376    /**
377     * show target selection membership
378     */
379    protected function showSourceSelectionMembership()
380    {
381        $user = $this->user;
382        $tpl = $this->tpl;
383
384        ilUtil::sendInfo($this->lng->txt('msg_copy_clipboard_source'));
385        $this->setTabs(self::TAB_GROUP_SC_SELECTION, self::TAB_SELECTION_MEMBERSHIP);
386
387        include_once './Services/Object/classes/class.ilObjectCopyCourseGroupSelectionTableGUI.php';
388        $cgs = new ilObjectCopyCourseGroupSelectionTableGUI($this, 'showSourceSelectionMembership', 'copy_selection_membership');
389        $cgs->init();
390        $cgs->setObjects(
391            array_merge(
392                ilParticipants::_getMembershipByType($user->getId(), 'crs', false),
393                ilParticipants::_getMembershipByType($user->getId(), 'grp', false)
394                )
395        );
396        $cgs->parse();
397
398        $tpl->setContent($cgs->getHTML());
399    }
400
401
402    /**
403     * Show target selection
404     */
405    public function showTargetSelectionTree()
406    {
407        $ilTabs = $this->tabs;
408        $ilToolbar = $this->toolbar;
409        $ilCtrl = $this->ctrl;
410        $tree = $this->tree;
411        $tpl = $this->tpl;
412        $objDefinition = $this->obj_definition;
413        $lng = $this->lng;
414
415        $this->tpl = $tpl;
416
417        if ($objDefinition->isContainer($this->getType())) {
418            ilUtil::sendInfo($this->lng->txt('msg_copy_clipboard_container'));
419        } else {
420            ilUtil::sendInfo($this->lng->txt('msg_copy_clipboard'));
421        }
422
423        //
424        include_once("./Services/Repository/classes/class.ilRepositorySelectorExplorerGUI.php");
425        $exp = new ilRepositorySelectorExplorerGUI($this, "showTargetSelectionTree");
426        $exp->setTypeWhiteList(array("root", "cat", "grp", "crs", "fold", "lso", "prg"));
427        $exp->setSelectMode("target", true);
428        if ($exp->handleCommand()) {
429            return;
430        }
431        $output = $exp->getHTML();
432
433        // toolbars
434        $t = new ilToolbarGUI();
435        $t->setFormAction($ilCtrl->getFormAction($this, "saveTarget"));
436        if ($objDefinition->isContainer($this->getType())) {
437            $btn = ilSubmitButton::getInstance();
438            $btn->setCaption('btn_next');
439            $btn->setCommand('saveTarget');
440            $btn->setPrimary(true);
441            $t->addButtonInstance($btn);
442        } else {
443            $btn = ilSubmitButton::getInstance();
444            $btn->setCaption('paste');
445            $btn->setCommand('saveTarget');
446            $btn->setPrimary(true);
447            $t->addButtonInstance($btn);
448        }
449        $t->addSeparator();
450        $clipboard_btn = ilSubmitButton::getInstance();
451        $clipboard_btn->setCaption('obj_insert_into_clipboard');
452        $clipboard_btn->setCommand('keepObjectsInClipboard');
453        $t->addButtonInstance($clipboard_btn);
454        $cancel_btn = ilSubmitButton::getInstance();
455        $cancel_btn->setCaption('cancel');
456        $cancel_btn->setCommand('cancel');
457        $t->addButtonInstance($cancel_btn);
458        $t->setCloseFormTag(false);
459        $t->setLeadingImage(ilUtil::getImagePath("arrow_upright.svg"), " ");
460        $output = $t->getHTML() . $output;
461        $t->setLeadingImage(ilUtil::getImagePath("arrow_downright.svg"), " ");
462        $t->setCloseFormTag(true);
463        $t->setOpenFormTag(false);
464        $output .= "<br />" . $t->getHTML();
465
466        $this->tpl->setContent($output);
467
468        return;
469    }
470
471    /**
472     * Show target selection
473     */
474    public function showSourceSelectionTree()
475    {
476        $ilTabs = $this->tabs;
477        $ilToolbar = $this->toolbar;
478        $ilCtrl = $this->ctrl;
479        $tree = $this->tree;
480        $tpl = $this->tpl;
481        $objDefinition = $this->obj_definition;
482
483        $this->tpl = $tpl;
484        $this->tpl->addBlockfile(
485            'ADM_CONTENT',
486            'adm_content',
487            'tpl.paste_into_multiple_objects.html',
488            "Services/Object"
489        );
490
491        ilUtil::sendInfo($this->lng->txt('msg_copy_clipboard_source'));
492        include_once './Services/Object/classes/class.ilPasteIntoMultipleItemsExplorer.php';
493        $exp = new ilPasteIntoMultipleItemsExplorer(
494            ilPasteIntoMultipleItemsExplorer::SEL_TYPE_RADIO,
495            'ilias.php?baseClass=ilRepositoryGUI&amp;cmd=goto',
496            'paste_copy_repexpand'
497        );
498        $exp->setRequiredFormItemPermission('visible,read,copy');
499
500        $ilCtrl->setParameter($this, 'selectMode', self::SOURCE_SELECTION);
501        $exp->setExpandTarget($ilCtrl->getLinkTarget($this, 'showSourceSelectionTree'));
502        $exp->setTargetGet('ref_id');
503        $exp->setPostVar('source');
504        $exp->setCheckedItems($this->getSources());
505
506        // Filter to container
507        foreach (array('cat','root','fold') as $container) {
508            $exp->removeFormItemForType($container);
509        }
510
511
512        if ($_GET['paste_copy_repexpand'] == '') {
513            $expanded = $tree->readRootId();
514        } else {
515            $expanded = $_GET['paste_copy_repexpand'];
516        }
517
518        $this->tpl->setVariable('FORM_TARGET', '_self');
519        $this->tpl->setVariable('FORM_ACTION', $ilCtrl->getFormAction($this, 'copySelection'));
520
521        $exp->setExpand($expanded);
522        // build html-output
523        $exp->setOutput(0);
524        $output = $exp->getOutput();
525
526        $this->tpl->setVariable('OBJECT_TREE', $output);
527
528        $this->tpl->setVariable('CMD_SUBMIT', 'saveSource');
529        $this->tpl->setVariable('TXT_SUBMIT', $this->lng->txt('btn_next'));
530
531        $ilToolbar->addButton($this->lng->txt('cancel'), $ilCtrl->getLinkTarget($this, 'cancel'));
532    }
533
534    /**
535     * Save target selection
536     * @return
537     */
538    protected function saveTarget()
539    {
540        $objDefinition = $this->obj_definition;
541        $tree = $this->tree;
542        $ilCtrl = $this->ctrl;
543
544
545        // begin-patch mc
546        if (is_array($_REQUEST['target']) and $_REQUEST['target']) {
547            $this->setTargets($_REQUEST['target']);
548            $ilCtrl->setParameter($this, 'target_ids', implode('_', $this->getTargets()));
549        }
550        // paste from clipboard
551        elseif ((int) $_REQUEST['target']) {
552            $this->setTarget($_REQUEST['target']);
553            $ilCtrl->setParameter($this, 'target_ids', implode('_', $this->getTargets()));
554        }
555        // end-patch multi copy
556        else {
557            $ilCtrl->setParameter($this, 'selectMode', self::TARGET_SELECTION);
558            ilUtil::sendFailure($this->lng->txt('select_one'));
559            $this->showTargetSelectionTree();
560            return false;
561        }
562
563        // validate allowed subtypes
564        foreach ($this->getSources() as $source_ref_id) {
565            foreach ((array) $this->getTargets() as $target_ref_id) {
566                $target_type = ilObject::_lookupType($target_ref_id, true);
567                $target_class_name = ilObjectFactory::getClassByType($target_type);
568                $target_object = new $target_class_name($target_ref_id);
569                $possible_subtypes = $target_object->getPossibleSubObjects();
570
571                $source_type = ilObject::_lookupType($source_ref_id, true);
572
573                if (!array_key_exists($source_type, (array) $possible_subtypes)) {
574                    ilUtil::sendFailure(
575                        sprintf(
576                            $this->lng->txt('msg_obj_may_not_contain_objects_of_type'),
577                            $this->lng->txt('obj_' . $target_type),
578                            $this->lng->txt('obj_' . $source_type)
579                            )
580                    );
581                    $this->showTargetSelectionTree();
582                    return false;
583                }
584            }
585        }
586
587        if (count($this->getSources()) == 1 && $objDefinition->isContainer($this->getType())) {
588            // check, if object should be copied into itself
589            // begin-patch mc
590            $is_child = array();
591            foreach ($this->getTargets() as $target_ref_id) {
592                if ($tree->isGrandChild($this->getFirstSource(), $target_ref_id)) {
593                    $is_child[] = ilObject::_lookupTitle(ilObject::_lookupObjId($this->getFirstSource()));
594                }
595                if ($this->getFirstSource() == $target_ref_id) {
596                    $is_child[] = ilObject::_lookupTitle(ilObject::_lookupObjId($this->getFirstSource()));
597                }
598            }
599            // end-patch multi copy
600            if (count($is_child) > 0) {
601                ilUtil::sendFailure($this->lng->txt("msg_not_in_itself") . " " . implode(',', $is_child));
602                $this->showTargetSelectionTree();
603                return false;
604            }
605
606            $this->showItemSelection();
607        } else {
608            if (count($this->getSources()) == 1) {
609                $this->copySingleObject();
610            } else {
611                $this->copyMultipleNonContainer($this->getSources());
612            }
613        }
614    }
615
616    /**
617     * set copy mode
618     * @param int $a_mode
619     * @return
620     */
621    public function setMode($a_mode)
622    {
623        $this->mode = $a_mode;
624    }
625
626    /**
627     * get copy mode
628     * @return
629     */
630    public function getMode()
631    {
632        return $this->mode;
633    }
634
635    public function setSubMode($a_mode)
636    {
637        $this->sub_mode = $a_mode;
638    }
639
640    public function getSubMode()
641    {
642        return $this->sub_mode;
643    }
644
645    /**
646     * Get parent gui object
647     * @return object	parent gui
648     */
649    public function getParentObject()
650    {
651        return $this->parent_obj;
652    }
653
654    /**
655     * Returns $type.
656     *
657     * @see ilObjectCopyGUI::$type
658     */
659    public function getType()
660    {
661        return $this->type;
662    }
663
664    /**
665     * Sets $type.
666     *
667     * @param object $type
668     * @see ilObjectCopyGUI::$type
669     */
670    public function setType($type)
671    {
672        $this->type = $type;
673    }
674
675    /**
676     * Set source id
677     * @param array $a_source_id
678     * @return
679     */
680    public function setSource(array $a_source_ids)
681    {
682        $this->sources = $a_source_ids;
683    }
684
685    /**
686     * Get sources
687     * @return array
688     */
689    public function getSources()
690    {
691        return (array) $this->sources;
692    }
693
694    public function getFirstSource()
695    {
696        if (count($this->sources)) {
697            return $this->sources[0];
698        }
699        return 0;
700    }
701
702    // begin-patch mc
703
704    /**
705     * Set single object target
706     * @param type $a_ref_id
707     */
708    public function setTarget($a_ref_id)
709    {
710        $this->setTargets(array($a_ref_id));
711    }
712
713
714    /**
715     * Set target id
716     * @param int $a_target
717     * @return
718     */
719    public function setTargets(array $a_target)
720    {
721        $this->targets = $a_target;
722    }
723
724    /**
725     * Get copy target
726     * @return
727     */
728    public function getTargets()
729    {
730        return (array) $this->targets;
731    }
732
733    /**
734     * Get first target
735     * @return int
736     */
737    public function getFirstTarget()
738    {
739        if (array_key_exists(0, $this->getTargets())) {
740            $targets = $this->getTargets();
741            return $targets[0];
742        }
743        return 0;
744    }
745    // end-patch multi copy
746
747    /**
748     * Cancel workflow
749     */
750    protected function cancel()
751    {
752        $ilCtrl = $this->ctrl;
753        $ilCtrl->setReturnByClass(get_class($this->parent_obj), 'cancel');
754        $ilCtrl->returnToParent($this);
755    }
756
757    /**
758     * Keep objects in clipboard
759     */
760    public function keepObjectsInClipboard()
761    {
762        ilUtil::sendSuccess($this->lng->txt("obj_inserted_clipboard"), true);
763        $ilCtrl = $this->ctrl;
764        $_SESSION['clipboard']['cmd'] = "copy";
765        $_SESSION['clipboard']['ref_ids'] = $this->getSources();
766        $ilCtrl->returnToParent($this);
767    }
768
769
770    /**
771     * Search source
772     * @return
773     */
774    protected function searchSource()
775    {
776        $tree = $this->tree;
777        $ilObjDataCache = $this->obj_data_cache;
778        $lng = $this->lng;
779        $ilCtrl = $this->ctrl;
780        $tpl = $this->tpl;
781
782        if (isset($_POST['tit'])) {
783            ilUtil::sendInfo($this->lng->txt('wizard_search_list'));
784            $_SESSION['source_query'] = $_POST['tit'];
785        } else {
786            $_POST['tit'] = $_SESSION['source_query'];
787        }
788
789        $this->initFormSearch();
790        $this->form->setValuesByPost();
791
792        if (!$this->form->checkInput()) {
793            ilUtil::sendFailure($lng->txt('msg_no_search_string'), true);
794            $ilCtrl->returnToParent($this);
795            return false;
796        }
797
798        include_once './Services/Search/classes/class.ilQueryParser.php';
799        $query_parser = new ilQueryParser($this->form->getInput('tit'));
800        $query_parser->setMinWordLength(1, true);
801        $query_parser->setCombination(QP_COMBINATION_AND);
802        $query_parser->parse();
803        if (!$query_parser->validate()) {
804            ilUtil::sendFailure($query_parser->getMessage(), true);
805            $ilCtrl->returnToParent($this);
806        }
807
808        // only like search since fulltext does not support search with less than 3 characters
809        include_once 'Services/Search/classes/Like/class.ilLikeObjectSearch.php';
810        $object_search = new ilLikeObjectSearch($query_parser);
811        $object_search->setFilter(array($_REQUEST['new_type']));
812        $res = $object_search->performSearch();
813        $res->setRequiredPermission('copy');
814        $res->filter(ROOT_FOLDER_ID, true);
815
816        if (!count($results = $res->getResultsByObjId())) {
817            ilUtil::sendFailure($this->lng->txt('search_no_match'), true);
818            $ilCtrl->returnToParent($this);
819        }
820
821
822        include_once './Services/Object/classes/class.ilObjectCopySearchResultTableGUI.php';
823        $table = new ilObjectCopySearchResultTableGUI($this, 'searchSource', $this->getType());
824        $table->setFormAction($ilCtrl->getFormAction($this));
825        $table->setSelectedReference($this->getFirstSource());
826        $table->parseSearchResults($results);
827        $tpl->setContent($table->getHTML());
828    }
829
830    /**
831     * select source object
832     * @return
833     */
834    protected function saveSource()
835    {
836        $objDefinition = $this->obj_definition;
837        $ilCtrl = $this->ctrl;
838
839        if (isset($_POST['source'])) {
840            $this->setSource(array((int) $_REQUEST['source']));
841            $this->setType(ilObject::_lookupType((int) $_REQUEST['source'], true));
842            $ilCtrl->setParameter($this, 'source_id', (int) $_REQUEST['source']);
843        } else {
844            ilUtil::sendFailure($this->lng->txt('select_one'));
845            $this->searchSource();
846            return false;
847        }
848
849        // validate allowed subtypes
850        foreach ($this->getSources() as $source_ref_id) {
851            foreach ((array) $this->getTargets() as $target_ref_id) {
852                $target_type = ilObject::_lookupType($target_ref_id, true);
853                $target_class_name = ilObjectFactory::getClassByType($target_type);
854                $target_object = new $target_class_name($target_ref_id);
855                $possible_subtypes = $target_object->getPossibleSubObjects();
856
857                $source_type = ilObject::_lookupType($source_ref_id, true);
858
859                if (!array_key_exists($source_type, $possible_subtypes)) {
860                    #ilLoggerFactory::getLogger('obj')->debug('Source type: '.  $source_type);
861                    #ilLoggerFactory::getLogger('obj')->debug('Target type: '.  $target_type);
862                    #ilLoggerFactory::getLogger('obj')->debug('Submode: '.  $this->getSubMode());
863
864                    // adopt content mode
865                    if (
866                        $this->getSubMode() != self::SUBMODE_CONTENT_ONLY and
867                        ($source_type != 'crs' or $target_type != 'crs')
868                    ) {
869                        ilUtil::sendFailure(
870                            sprintf(
871                                $this->lng->txt('msg_obj_may_not_contain_objects_of_type'),
872                                $this->lng->txt('obj_' . $target_type),
873                                $this->lng->txt('obj_' . $source_type)
874                                )
875                        );
876                        $this->searchSource();
877                        return false;
878                    }
879                }
880            }
881        }
882
883
884        if ($objDefinition->isContainer($this->getType())) {
885            $this->showItemSelection();
886        } else {
887            $this->copySingleObject();
888        }
889    }
890
891    /**
892     * Save selected source from membership screen
893     */
894    protected function saveSourceMembership()
895    {
896        $objDefinition = $this->obj_definition;
897        $ilCtrl = $this->ctrl;
898
899        if (!isset($_REQUEST['source'])) {
900            ilUtil::sendFailure($this->lng->txt('select_one'));
901            $ilCtrl->redirect($this, 'showSourceSelectionMembership');
902            return false;
903        }
904
905        $this->setSource(array((int) $_REQUEST['source']));
906        $this->setType(ilObject::_lookupType((int) $this->getFirstSource(), true));
907        $ilCtrl->setParameter($this, 'source_id', (int) $_REQUEST['source']);
908
909        if ($objDefinition->isContainer($this->getType())) {
910            $this->showItemSelection();
911        } else {
912            $this->copySingleObject();
913        }
914    }
915
916    /**
917     *
918     * @return
919     */
920    protected function showItemSelection()
921    {
922        $tpl = $this->tpl;
923
924        if (!count($this->getSources())) {
925            ilUtil::sendFailure($this->lng->txt('select_one'));
926            $this->searchSource();
927            return false;
928        }
929
930        ilLoggerFactory::getLogger('obj')->debug('Source(s): ' . print_r($this->getSources(), true));
931        ilLoggerFactory::getLogger('obj')->debug('Target(s): ' . print_r($this->getTargets(), true));
932
933        ilUtil::sendInfo($this->lng->txt($this->getType() . '_copy_threads_info'));
934        include_once './Services/Object/classes/class.ilObjectCopySelectionTableGUI.php';
935
936        $tpl->addJavaScript('./Services/CopyWizard/js/ilContainer.js');
937        $tpl->setVariable('BODY_ATTRIBUTES', 'onload="ilDisableChilds(\'cmd\');"');
938
939        switch ($this->getMode()) {
940            case self::SOURCE_SELECTION:
941                $back_cmd = 'showSourceSelectionTree';
942                break;
943
944            case self::TARGET_SELECTION:
945                $back_cmd = 'showTargetSelectionTree';
946                break;
947
948            case self::SEARCH_SOURCE:
949                $back_cmd = 'searchSource';
950                break;
951        }
952
953        $table = new ilObjectCopySelectionTableGUI($this, 'showItemSelection', $this->getType(), $back_cmd);
954        $table->parseSource($this->getFirstSource());
955
956        $tpl->setContent($table->getHTML());
957    }
958
959    /**
960     * Start cloning a single (not container) object
961     * @return
962     */
963    protected function copySingleObject()
964    {
965        include_once('./Services/Link/classes/class.ilLink.php');
966        include_once('Services/CopyWizard/classes/class.ilCopyWizardOptions.php');
967
968        $ilAccess = $this->access;
969        $ilErr = $this->error;
970        $rbacsystem = $this->rbacsystem;
971        $ilUser = $this->user;
972        $ilCtrl = $this->ctrl;
973        $rbacreview = $this->rbacreview;
974
975        // Source defined
976        if (!count($this->getSources())) {
977            ilUtil::sendFailure($this->lng->txt('select_one'), true);
978            $ilCtrl->returnToParent($this);
979        }
980
981        $this->copyMultipleNonContainer($this->getSources());
982        return;
983    }
984
985    /**
986     * Copy multiple non container
987     *
988     * @param array $a_sources array of source ref ids
989     */
990    public function copyMultipleNonContainer($a_sources)
991    {
992        $ilAccess = $this->access;
993        $objDefinition = $this->obj_definition;
994        $rbacsystem = $this->rbacsystem;
995        $ilUser = $this->user;
996        $ilCtrl = $this->ctrl;
997        $rbacreview = $this->rbacreview;
998
999
1000        include_once('./Services/Link/classes/class.ilLink.php');
1001        include_once('Services/CopyWizard/classes/class.ilCopyWizardOptions.php');
1002
1003        // check permissions
1004        foreach ($a_sources as $source_ref_id) {
1005            $source_type = ilObject::_lookupType($source_ref_id, true);
1006
1007            // Create permission
1008            // begin-patch mc
1009            foreach ($this->getTargets() as $target_ref_id) {
1010                if (!$rbacsystem->checkAccess('create', $target_ref_id, $source_type)) {
1011                    $this->log->notice('Permission denied for target_id: ' . $target_ref_id . ' source_type: ' . $source_type . ' CREATE');
1012                    ilUtil::sendFailure($this->lng->txt('permission_denied'), true);
1013                    $ilCtrl->returnToParent($this);
1014                }
1015            }
1016
1017            // Copy permission
1018            if (!$ilAccess->checkAccess('copy', '', $source_ref_id)) {
1019                $this->log->notice('Permission denied for source_ref_id: ' . $source_ref_id . ' COPY');
1020                ilUtil::sendFailure($this->lng->txt('permission_denied'), true);
1021                $ilCtrl->returnToParent($this);
1022            }
1023
1024            // check that these objects are really not containers
1025            if ($objDefinition->isContainer($source_type) and $this->getSubMode() != self::SUBMODE_CONTENT_ONLY) {
1026                ilUtil::sendFailure($this->lng->txt('cntr_container_only_on_their_own'), true);
1027                $ilCtrl->returnToParent($this);
1028            }
1029        }
1030
1031        reset($a_sources);
1032
1033
1034        ilLoggerFactory::getLogger('obj')->debug('Copy multiple non containers. Sources: ' . print_r($a_sources, true));
1035
1036        // clone
1037        foreach ($a_sources as $source_ref_id) {
1038            ilLoggerFactory::getLogger('obj')->debug('Copying source ref_id : ' . $source_ref_id);
1039
1040            // begin-patch mc
1041            foreach ($this->getTargets() as $target_ref_id) {
1042                // Save wizard options
1043                $copy_id = ilCopyWizardOptions::_allocateCopyId();
1044                $wizard_options = ilCopyWizardOptions::_getInstance($copy_id);
1045                $wizard_options->saveOwner($ilUser->getId());
1046                $wizard_options->saveRoot((int) $source_ref_id);
1047                $wizard_options->read();
1048
1049                $orig = ilObjectFactory::getInstanceByRefId((int) $source_ref_id);
1050                $new_obj = $orig->cloneObject($target_ref_id, $copy_id);
1051
1052                // Delete wizard options
1053                $wizard_options->deleteAll();
1054
1055                // rbac log
1056                include_once "Services/AccessControl/classes/class.ilRbacLog.php";
1057                if (ilRbacLog::isActive()) {
1058                    $rbac_log_roles = $rbacreview->getParentRoleIds($new_obj->getRefId(), false);
1059                    $rbac_log = ilRbacLog::gatherFaPa($new_obj->getRefId(), array_keys($rbac_log_roles), true);
1060                    ilRbacLog::add(ilRbacLog::COPY_OBJECT, $new_obj->getRefId(), $rbac_log, (int) $source_ref_id);
1061                }
1062            }
1063        }
1064
1065        unset($_SESSION["clipboard"]["ref_ids"]);
1066        unset($_SESSION["clipboard"]["cmd"]);
1067
1068        if (count($a_sources) == 1) {
1069            ilLoggerFactory::getLogger('obj')->info('Object copy completed.');
1070            ilUtil::sendSuccess($this->lng->txt("object_duplicated"), true);
1071            $ref_id = $new_obj->getRefId();
1072        } else {
1073            ilLoggerFactory::getLogger('obj')->info('Object copy completed.');
1074            ilUtil::sendSuccess($this->lng->txt("objects_duplicated"), true);
1075            $ref_id = $this->getFirstTarget();
1076        }
1077
1078        ilUtil::sendSuccess($this->lng->txt("objects_duplicated"), true);
1079        ilUtil::redirect(ilLink::_getLink($ref_id));
1080
1081        // see bug discussion 24472
1082        /*
1083        $gui_fac = new ilObjectGUIFactory();
1084        $obj_gui = $gui_fac->getInstanceByRefId($ref_id);
1085        $obj_gui->redirectAfterCreation();
1086        */
1087    }
1088
1089    /**
1090     * Copy to multiple targets
1091     */
1092    protected function copyContainerToTargets()
1093    {
1094        $ilCtrl = $this->ctrl;
1095
1096        ilLoggerFactory::getLogger('obj')->debug('Copy container to targets: ' . print_r($_REQUEST, true));
1097        ilLoggerFactory::getLogger('obj')->debug('Source(s): ' . print_r($this->getSources(), true));
1098        ilLoggerFactory::getLogger('obj')->debug('Target(s): ' . print_r($this->getTargets(), true));
1099
1100
1101        $last_target = 0;
1102        $result = 1;
1103        foreach ($this->getTargets() as $target_ref_id) {
1104            $result = $this->copyContainer($target_ref_id);
1105            $last_target = $target_ref_id;
1106        }
1107
1108        unset($_SESSION["clipboard"]["ref_ids"]);
1109        unset($_SESSION["clipboard"]["cmd"]);
1110
1111        include_once './Services/CopyWizard/classes/class.ilCopyWizardOptions.php';
1112        if (ilCopyWizardOptions::_isFinished($result['copy_id'])) {
1113            ilLoggerFactory::getLogger('obj')->info('Object copy completed.');
1114            ilUtil::sendSuccess($this->lng->txt("object_duplicated"), true);
1115            if ($this->getSubMode() == self::SUBMODE_CONTENT_ONLY) {
1116                // return to parent container
1117                return $this->ctrl->returnToParent($this);
1118            }
1119            // return to last target
1120            $link = ilLink::_getLink($result['ref_id']);
1121            $ilCtrl->redirectToUrl($link);
1122        } else {
1123            // show progress
1124            ilLoggerFactory::getLogger('obj')->debug('Object copy in progress.');
1125            return $this->showCopyProgress();
1126        }
1127    }
1128
1129    /**
1130     * Show progress for copying
1131     */
1132    protected function showCopyProgress()
1133    {
1134        $ilCtrl = $this->ctrl;
1135        $tpl = $this->tpl;
1136
1137        include_once './Services/Object/classes/class.ilObjectCopyProgressTableGUI.php';
1138        $progress = new ilObjectCopyProgressTableGUI(
1139            $this,
1140            'showCopyProgress',
1141            (int) $_GET['ref_id']
1142        );
1143        $progress->setObjectInfo($this->targets_copy_id);
1144        $progress->parse();
1145        $progress->init();
1146        $progress->setRedirectionUrl($ilCtrl->getParentReturn($this->parent_obj));
1147
1148        $tpl->setContent($progress->getHTML());
1149    }
1150
1151    /**
1152     * Update progress
1153     */
1154    protected function updateProgress()
1155    {
1156        $json = new stdClass();
1157        $json->percentage = null;
1158        $json->performed_steps = null;
1159
1160        include_once './Services/CopyWizard/classes/class.ilCopyWizardOptions.php';
1161        $options = ilCopyWizardOptions::_getInstance((int) $_REQUEST['copy_id']);
1162        $json->required_steps = $options->getRequiredSteps();
1163        $json->id = (int) $_REQUEST['copy_id'];
1164
1165        ilLoggerFactory::getLogger('obj')->debug('Update copy progress: ' . json_encode($json));
1166
1167        echo json_encode($json);
1168        exit;
1169    }
1170
1171
1172    /**
1173     * Copy a container
1174     * @return
1175     */
1176    protected function copyContainer($a_target)
1177    {
1178        $ilLog = $this->log;
1179        $ilCtrl = $this->ctrl;
1180
1181        include_once('./Services/Link/classes/class.ilLink.php');
1182        include_once('Services/CopyWizard/classes/class.ilCopyWizardOptions.php');
1183
1184        $ilAccess = $this->access;
1185        $ilErr = $this->error;
1186        $rbacsystem = $this->rbacsystem;
1187        $tree = $this->tree;
1188        $ilUser = $this->user;
1189        $ilCtrl = $this->ctrl;
1190
1191        // Workaround for course in course copy
1192
1193        $target_type = ilObject::_lookupType(ilObject::_lookupObjId($a_target));
1194        $source_type = ilObject::_lookupType(ilObject::_lookupObjId($this->getFirstSource()));
1195
1196        if ($this->getSubMode() != self::SUBMODE_CONTENT_ONLY) {
1197            if (!$rbacsystem->checkAccess('create', $a_target, $this->getType())) {
1198                $this->log->notice('Permission denied for target: ' . $a_target . ' type: ' . $this->getType() . ' CREATE');
1199                ilUtil::sendFailure($this->lng->txt('permission_denied'), true);
1200                $ilCtrl->returnToParent($this);
1201            }
1202        }
1203        if (!$this->getFirstSource()) {
1204            ilUtil::sendFailure($this->lng->txt('select_one'), true);
1205            $ilCtrl->returnToParent($this);
1206            return false;
1207        }
1208
1209        $options = $_POST['cp_options'] ? $_POST['cp_options'] : array();
1210
1211
1212        ilLoggerFactory::getLogger('obj')->debug('Copy container (sources): ' . print_r($this->getSources(), true));
1213
1214        $orig = ilObjectFactory::getInstanceByRefId($this->getFirstSource());
1215        $result = $orig->cloneAllObject(
1216            $_COOKIE[session_name()],
1217            $_COOKIE['ilClientId'],
1218            $this->getType(),
1219            $a_target,
1220            $this->getFirstSource(),
1221            $options,
1222            false,
1223            $this->getSubMode()
1224        );
1225
1226        $this->targets_copy_id[$a_target] = $result['copy_id'];
1227
1228        return $result;
1229    }
1230
1231
1232
1233    /**
1234     * Show init screen
1235     * Normally shown below the create and import form when creating a new object
1236     *
1237     * @param string $a_tplvar The tpl variable to fill
1238     * @return
1239     */
1240    public function showSourceSearch($a_tplvar)
1241    {
1242        $tpl = $this->tpl;
1243
1244        // Disabled for performance
1245        #if(!$this->sourceExists())
1246        #{
1247        #	return false;
1248        #}
1249
1250        $this->unsetSession();
1251        $this->initFormSearch();
1252
1253        if ($a_tplvar) {
1254            $tpl->setVariable($a_tplvar, $this->form->getHTML());
1255        } else {
1256            return $this->form;
1257        }
1258    }
1259
1260
1261    /**
1262     * Check if there is any source object
1263     * @return bool
1264     */
1265    protected function sourceExists()
1266    {
1267        $ilUser = $this->user;
1268
1269        return (bool) ilUtil::_getObjectsByOperations($this->getType(), 'copy', $ilUser->getId(), 1);
1270    }
1271
1272    /**
1273     * Init search form
1274     * @return
1275     */
1276    protected function initFormSearch()
1277    {
1278        $lng = $this->lng;
1279        $ilCtrl = $this->ctrl;
1280
1281        include_once './Services/Form/classes/class.ilPropertyFormGUI.php';
1282        $this->form = new ilPropertyFormGUI();
1283        $this->form->setTableWidth('600px');
1284
1285        $ilCtrl->setParameter($this, 'new_type', $this->getType());
1286
1287        #$ilCtrl->setParameter($this, 'cp_mode', self::SOURCE_SELECTION);
1288        $this->form->setFormAction($ilCtrl->getFormAction($this));
1289        $this->form->setTitle($lng->txt($this->getType() . '_copy'));
1290
1291        $this->form->addCommandButton('searchSource', $lng->txt('btn_next'));
1292        $this->form->addCommandButton('cancel', $this->lng->txt('cancel'));
1293
1294        $tit = new ilTextInputGUI($lng->txt('title'), 'tit');
1295        $tit->setSize(40);
1296        $tit->setMaxLength(70);
1297        $tit->setRequired(true);
1298        $tit->setInfo($lng->txt('wizard_title_info'));
1299        $this->form->addItem($tit);
1300    }
1301
1302    /**
1303     * Unset session variables
1304     * @return
1305     */
1306    protected function unsetSession()
1307    {
1308        unset($_SESSION['source_query']);
1309        $this->setSource(array());
1310    }
1311}
1312