Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 159
0.00% covered (danger)
0.00%
0 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 1
Section
0.00% covered (danger)
0.00%
0 / 159
0.00% covered (danger)
0.00%
0 / 18
2070
0.00% covered (danger)
0.00%
0 / 1
 fromSimpleXMLElement
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
240
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getUrl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getExtensionId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getController
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAction
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPolicy
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBinding
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTrees
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addTree
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getActions
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addAction
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 removeAction
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getActionsByGroup
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 migrateDataFromLegacyFormat
0.00% covered (danger)
0.00%
0 / 92
0.00% covered (danger)
0.00%
0 / 1
132
 __toPhpCode
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2014 (original work) Open Assessment Technologies SA;
19 *
20 *
21 */
22
23namespace oat\tao\model\menu;
24
25use oat\oatbox\PhpSerializable;
26use oat\taoBackOffice\model\menuStructure\ClassActionRegistry;
27use oat\taoBackOffice\model\menuStructure\Action as iAction;
28
29class Section extends MenuElement implements PhpSerializable
30{
31    public const SERIAL_VERSION = 1392821334;
32
33    public const POLICY_MERGE = 'merge';
34
35    public const POLICY_OVERRIDE = 'override';
36
37    private $data = [];
38
39    private $trees = [];
40
41    private $actions = [];
42
43    /**
44     * @param \SimpleXMLElement $node
45     * @param $structureExtensionId extension of structures.xml
46     * @return static
47     */
48    public static function fromSimpleXMLElement(\SimpleXMLElement $node, $structureExtensionId)
49    {
50
51        $url = isset($node['url']) ? (string) $node['url'] : '#';
52        if ($url == '#' || empty($url)) {
53            $extension  = null;
54            $controller = null;
55            $action     = null;
56        } else {
57            $parts = explode('/', trim($url, '/'));
58            $parts = array_replace(array_fill(0, 3, null), $parts);
59
60            list($extension, $controller, $action) = $parts;
61        }
62
63        $data = [
64            'id'         => (string)$node['id'],
65            'name'       => (string)$node['name'],
66            'url'        => $url,
67            'extension'  => $extension,
68            'controller' => $controller,
69            'action'     => $action,
70            'binding'    => isset($node['binding']) ? (string)$node['binding'] : null,
71            'policy'     => isset($node['policy']) ? (string)$node['policy'] : self::POLICY_MERGE,
72            'disabled'   => isset($node['disabled']) ? true : false
73        ];
74
75        $trees = [];
76        foreach ($node->xpath("trees/tree") as $treeNode) {
77            $trees[] = Tree::fromSimpleXMLElement($treeNode, $structureExtensionId);
78        }
79
80        $actions = [];
81        foreach ($node->xpath("actions/action") as $actionNode) {
82            $actions[] = Action::fromSimpleXMLElement($actionNode, $structureExtensionId);
83        }
84
85        $includeClassActions = isset($node->actions)
86            && isset($node->actions['allowClassActions'])
87            && $node->actions['allowClassActions'] == 'true';
88
89        if ($includeClassActions) {
90            foreach ($trees as $tree) {
91                $rootNodeUri = $tree->get('rootNode');
92                if (!empty($rootNodeUri)) {
93                    $rootNode = new \core_kernel_classes_Class($rootNodeUri);
94                    foreach (ClassActionRegistry::getRegistry()->getClassActions($rootNode) as $action) {
95                        $actions[] = $action;
96                    }
97                }
98            }
99        }
100
101        return new static($data, $trees, $actions);
102    }
103
104    public function __construct($data, $trees, $actions, $version = self::SERIAL_VERSION)
105    {
106        parent::__construct($data['id'], $version);
107        $this->data    = $data;
108        $this->trees   = $trees;
109        $this->actions = $actions;
110
111        $this->migrateDataFromLegacyFormat();
112    }
113
114    public function getUrl()
115    {
116        return _url($this->getAction(), $this->getController(), $this->getExtensionId());
117    }
118
119    public function getName()
120    {
121        return $this->data['name'];
122    }
123
124    public function getExtensionId()
125    {
126        return $this->data['extension'];
127    }
128
129    public function getController()
130    {
131        return $this->data['controller'];
132    }
133
134    public function getAction()
135    {
136        return $this->data['action'];
137    }
138
139    /**
140     * Policy on how to deal with existing structures
141     *
142     * Only merge or override are currently supported
143     *
144     * @return string
145     */
146    public function getPolicy()
147    {
148        return $this->data['policy'];
149    }
150
151    /**
152     * Get the JavaScript binding to run instead of loading the URL
153     *
154     * @return string|null the binding name or null if none
155     */
156    public function getBinding()
157    {
158        return $this->data['binding'];
159    }
160
161    /**
162     * Is the section disabled ?
163     *
164     * @return boolean if the section is disabled
165     */
166    public function getDisabled()
167    {
168        return $this->data['disabled'];
169    }
170
171    public function getTrees()
172    {
173        return $this->trees;
174    }
175
176    public function addTree(Tree $tree)
177    {
178        $this->trees[] = $tree;
179    }
180
181    public function getActions()
182    {
183        return $this->actions;
184    }
185
186    public function addAction(iAction $action)
187    {
188        $this->actions[] = $action;
189    }
190
191    public function removeAction(iAction $action)
192    {
193        $index = array_search($action, $this->actions, true);
194        if ($index !== false) {
195            unset($this->actions[$index]);
196        }
197    }
198
199    /**
200     * @param string $groupId
201     * @return array
202     */
203    public function getActionsByGroup($groupId)
204    {
205        $actions = [];
206        foreach ($this->getActions() as $action) {
207            if ($action->getGroup() === $groupId) {
208                $actions[] = $action;
209            }
210        };
211        return $actions;
212    }
213
214    /**
215     * Enables sections to be backward compatible with the structure format
216     * (before some actions were missing as they were defined in the tree part).
217     * legacy format : tao <= 2.6.x
218     * this method should be deprecated from 2.8.0 / 3.0.0
219     */
220    private function migrateDataFromLegacyFormat()
221    {
222
223        if (count($this->trees) > 0) {
224            //tree attributes to be migrated.
225            $mapping = [
226              'editClassUrl' => [
227                'attr'   => 'selectClass',
228                'action' => [
229                    'id'      => 'edit_class',
230                    'name'    => 'edit class',
231                    'group'   => 'none',
232                    'context' => 'class',
233                    'binding' => 'load'
234                ]
235              ],
236              'editInstanceUrl' => [
237                'attr'   => 'selectInstance',
238                'action' => [
239                    'id'      => 'edit_instance',
240                    'name'    => 'edit instance',
241                    'group'   => 'none',
242                    'context' => 'instance',
243                    'binding' => 'load'
244                ]
245              ],
246              'addInstanceUrl'  => [
247                'attr'   => 'addInstance',
248                'action' => [
249                    'id'      => 'add_instance',
250                    'name'    => 'add instance',
251                    'group'   => 'none',
252                    'context' => 'instance',
253                    'binding' => 'instantiate'
254                ]
255              ],
256              'addSubClassUrl'  => [
257                'attr'   => 'addClass',
258                'action' => [
259                    'id'      => 'add_class',
260                    'name'    => 'add class',
261                    'group'   => 'none',
262                    'context' => 'class',
263                    'binding' => 'subClass'
264                ]
265              ],
266              'deleteUrl' => [
267                'attr'   => 'addClass',
268                'action' => [
269                    'id'      => 'add_class',
270                    'name'    => 'add class',
271                    'group'   => 'none',
272                    'context' => 'class',
273                    'binding' => 'subClass'
274                ]
275              ],
276              'moveInstanceUrl' => [
277                'attr'   => 'moveInstance',
278                'action' => [
279                    'id'      => 'move',
280                    'name'    => 'move',
281                    'group'   => 'none',
282                    'context' => 'instance',
283                    'binding' => 'moveNode'
284                ]
285              ]
286            ];
287
288            foreach ($this->trees as $index => $tree) {
289                $needMigration = false;
290                $treeAttributes = $tree->getAttributes();
291
292                //check if this attribute needs a migration
293                foreach ($treeAttributes as $attr) {
294                    if (array_key_exists($attr, $mapping)) {
295                        $needMigration = true;
296                        break;
297                    }
298                }
299                if ($needMigration) {
300                    $newData = [];
301
302                    //migrate the tree
303                    foreach ($treeAttributes as $attr) {
304                        //if the attribute belongs to the mapping
305                        if (array_key_exists($attr, $mapping)) {
306                            $url = $tree->get($attr);
307                            $actionName = false;
308
309                            //try to find an action with the same url
310                            foreach ($this->actions as $action) {
311                                if ($action->getRelativeUrl() == $url) {
312                                    $actionName = $action->getId();
313                                    break;
314                                }
315                            }
316                            if ($actionName) {
317                                $newData[$mapping[$attr]['attr']] = $actionName;
318                            } else {
319                                //otherwise create a new action from the mapping
320                                $newData[$mapping[$attr]['attr']] = $mapping[$attr]['action']['id'];
321                                $actionData = $mapping[$attr]['action'];
322                                $actionData['url'] = $url;
323
324                                list($extension, $controller, $action) = explode('/', trim($url, '/'));
325                                $actionData['extension'] = $extension;
326                                $actionData['controller'] = $controller;
327                                $actionData['action'] = $action;
328
329                                $this->actions[] = new Action($actionData);
330                            }
331                        } else {
332                            $newData[$attr] = $tree->get($attr);
333                        }
334                    }
335
336                    //the tree is replaced
337                    $this->trees[$index] = new Tree($newData);
338                }
339            }
340        }
341    }
342
343
344    public function __toPhpCode()
345    {
346        return "new " . __CLASS__ . "("
347        . \common_Utils::toPHPVariableString($this->data) . ','
348        . \common_Utils::toPHPVariableString($this->trees) . ','
349        . \common_Utils::toPHPVariableString($this->actions) . ','
350        . \common_Utils::toPHPVariableString(self::SERIAL_VERSION)
351        . ")";
352    }
353}