353 lines
11 KiB
PHP
353 lines
11 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License
|
||
|
* as published by the Free Software Foundation; under version 2
|
||
|
* of the License (non-upgradable).
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*
|
||
|
* Copyright (c) 2014 (original work) Open Assessment Technologies SA;
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
namespace oat\tao\model\menu;
|
||
|
|
||
|
use oat\oatbox\PhpSerializable;
|
||
|
use oat\taoBackOffice\model\menuStructure\ClassActionRegistry;
|
||
|
use oat\taoBackOffice\model\menuStructure\Action as iAction;
|
||
|
|
||
|
class Section extends MenuElement implements PhpSerializable
|
||
|
{
|
||
|
|
||
|
const SERIAL_VERSION = 1392821334;
|
||
|
|
||
|
const POLICY_MERGE = 'merge';
|
||
|
|
||
|
const POLICY_OVERRIDE = 'override';
|
||
|
|
||
|
private $data = [];
|
||
|
|
||
|
private $trees = [];
|
||
|
|
||
|
private $actions = [];
|
||
|
|
||
|
/**
|
||
|
* @param \SimpleXMLElement $node
|
||
|
* @param $structureExtensionId extension of structures.xml
|
||
|
* @return static
|
||
|
*/
|
||
|
public static function fromSimpleXMLElement(\SimpleXMLElement $node, $structureExtensionId)
|
||
|
{
|
||
|
|
||
|
$url = isset($node['url']) ? (string) $node['url'] : '#';
|
||
|
if ($url == '#' || empty($url)) {
|
||
|
$extension = null;
|
||
|
$controller = null;
|
||
|
$action = null;
|
||
|
} else {
|
||
|
$parts = explode('/', trim($url, '/'));
|
||
|
$parts = array_replace(array_fill(0, 3, null), $parts);
|
||
|
|
||
|
list($extension, $controller, $action) = $parts;
|
||
|
}
|
||
|
|
||
|
$data = [
|
||
|
'id' => (string)$node['id'],
|
||
|
'name' => (string)$node['name'],
|
||
|
'url' => $url,
|
||
|
'extension' => $extension,
|
||
|
'controller' => $controller,
|
||
|
'action' => $action,
|
||
|
'binding' => isset($node['binding']) ? (string)$node['binding'] : null,
|
||
|
'policy' => isset($node['policy']) ? (string)$node['policy'] : self::POLICY_MERGE,
|
||
|
'disabled' => isset($node['disabled']) ? true : false
|
||
|
];
|
||
|
|
||
|
$trees = [];
|
||
|
foreach ($node->xpath("trees/tree") as $treeNode) {
|
||
|
$trees[] = Tree::fromSimpleXMLElement($treeNode, $structureExtensionId);
|
||
|
}
|
||
|
|
||
|
$actions = [];
|
||
|
foreach ($node->xpath("actions/action") as $actionNode) {
|
||
|
$actions[] = Action::fromSimpleXMLElement($actionNode, $structureExtensionId);
|
||
|
}
|
||
|
|
||
|
$includeClassActions = isset($node->actions) && isset($node->actions['allowClassActions']) && $node->actions['allowClassActions'] == 'true';
|
||
|
|
||
|
if ($includeClassActions) {
|
||
|
foreach ($trees as $tree) {
|
||
|
$rootNodeUri = $tree->get('rootNode');
|
||
|
if (!empty($rootNodeUri)) {
|
||
|
$rootNode = new \core_kernel_classes_Class($rootNodeUri);
|
||
|
foreach (ClassActionRegistry::getRegistry()->getClassActions($rootNode) as $action) {
|
||
|
$actions[] = $action;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return new static($data, $trees, $actions);
|
||
|
}
|
||
|
|
||
|
public function __construct($data, $trees, $actions, $version = self::SERIAL_VERSION)
|
||
|
{
|
||
|
parent::__construct($data['id'], $version);
|
||
|
$this->data = $data;
|
||
|
$this->trees = $trees;
|
||
|
$this->actions = $actions;
|
||
|
|
||
|
$this->migrateDataFromLegacyFormat();
|
||
|
}
|
||
|
|
||
|
public function getUrl()
|
||
|
{
|
||
|
return _url($this->getAction(), $this->getController(), $this->getExtensionId());
|
||
|
}
|
||
|
|
||
|
public function getName()
|
||
|
{
|
||
|
return $this->data['name'];
|
||
|
}
|
||
|
|
||
|
public function getExtensionId()
|
||
|
{
|
||
|
return $this->data['extension'];
|
||
|
}
|
||
|
|
||
|
public function getController()
|
||
|
{
|
||
|
return $this->data['controller'];
|
||
|
}
|
||
|
|
||
|
public function getAction()
|
||
|
{
|
||
|
return $this->data['action'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Policy on how to deal with existing structures
|
||
|
*
|
||
|
* Only merge or override are currently supported
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getPolicy()
|
||
|
{
|
||
|
return $this->data['policy'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the JavaScript binding to run instead of loading the URL
|
||
|
*
|
||
|
* @return string|null the binding name or null if none
|
||
|
*/
|
||
|
public function getBinding()
|
||
|
{
|
||
|
return $this->data['binding'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Is the section disabled ?
|
||
|
*
|
||
|
* @return boolean if the section is disabled
|
||
|
*/
|
||
|
public function getDisabled()
|
||
|
{
|
||
|
return $this->data['disabled'];
|
||
|
}
|
||
|
|
||
|
public function getTrees()
|
||
|
{
|
||
|
return $this->trees;
|
||
|
}
|
||
|
|
||
|
public function addTree(Tree $tree)
|
||
|
{
|
||
|
$this->trees[] = $tree;
|
||
|
}
|
||
|
|
||
|
public function getActions()
|
||
|
{
|
||
|
return $this->actions;
|
||
|
}
|
||
|
|
||
|
public function addAction(iAction $action)
|
||
|
{
|
||
|
$this->actions[] = $action;
|
||
|
}
|
||
|
|
||
|
public function removeAction(iAction $action)
|
||
|
{
|
||
|
$index = array_search($action, $this->actions, true);
|
||
|
if ($index !== false) {
|
||
|
unset($this->actions[$index]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $groupId
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getActionsByGroup($groupId)
|
||
|
{
|
||
|
$actions = [];
|
||
|
foreach ($this->getActions() as $action) {
|
||
|
if ($action->getGroup() === $groupId) {
|
||
|
$actions[] = $action;
|
||
|
}
|
||
|
};
|
||
|
return $actions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enables sections to be backward compatible with the structure format
|
||
|
* (before some actions were missing as they were defined in the tree part).
|
||
|
* legacy format : tao <= 2.6.x
|
||
|
* this method should be deprecated from 2.8.0 / 3.0.0
|
||
|
*/
|
||
|
private function migrateDataFromLegacyFormat()
|
||
|
{
|
||
|
|
||
|
if (count($this->trees) > 0) {
|
||
|
//tree attributes to be migrated.
|
||
|
$mapping = [
|
||
|
'editClassUrl' => [
|
||
|
'attr' => 'selectClass',
|
||
|
'action' => [
|
||
|
'id' => 'edit_class',
|
||
|
'name' => 'edit class',
|
||
|
'group' => 'none',
|
||
|
'context' => 'class',
|
||
|
'binding' => 'load'
|
||
|
]
|
||
|
],
|
||
|
'editInstanceUrl' => [
|
||
|
'attr' => 'selectInstance',
|
||
|
'action' => [
|
||
|
'id' => 'edit_instance',
|
||
|
'name' => 'edit instance',
|
||
|
'group' => 'none',
|
||
|
'context' => 'instance',
|
||
|
'binding' => 'load'
|
||
|
]
|
||
|
],
|
||
|
'addInstanceUrl' => [
|
||
|
'attr' => 'addInstance',
|
||
|
'action' => [
|
||
|
'id' => 'add_instance',
|
||
|
'name' => 'add instance',
|
||
|
'group' => 'none',
|
||
|
'context' => 'instance',
|
||
|
'binding' => 'instantiate'
|
||
|
]
|
||
|
],
|
||
|
'addSubClassUrl' => [
|
||
|
'attr' => 'addClass',
|
||
|
'action' => [
|
||
|
'id' => 'add_class',
|
||
|
'name' => 'add class',
|
||
|
'group' => 'none',
|
||
|
'context' => 'class',
|
||
|
'binding' => 'subClass'
|
||
|
]
|
||
|
],
|
||
|
'deleteUrl' => [
|
||
|
'attr' => 'addClass',
|
||
|
'action' => [
|
||
|
'id' => 'add_class',
|
||
|
'name' => 'add class',
|
||
|
'group' => 'none',
|
||
|
'context' => 'class',
|
||
|
'binding' => 'subClass'
|
||
|
]
|
||
|
],
|
||
|
'moveInstanceUrl' => [
|
||
|
'attr' => 'moveInstance',
|
||
|
'action' => [
|
||
|
'id' => 'move',
|
||
|
'name' => 'move',
|
||
|
'group' => 'none',
|
||
|
'context' => 'instance',
|
||
|
'binding' => 'moveNode'
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
|
||
|
foreach ($this->trees as $index => $tree) {
|
||
|
$needMigration = false;
|
||
|
$treeAttributes = $tree->getAttributes();
|
||
|
|
||
|
//check if this attribute needs a migration
|
||
|
foreach ($treeAttributes as $attr) {
|
||
|
if (array_key_exists($attr, $mapping)) {
|
||
|
$needMigration = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ($needMigration) {
|
||
|
$newData = [];
|
||
|
|
||
|
//migrate the tree
|
||
|
foreach ($treeAttributes as $attr) {
|
||
|
//if the attribute belongs to the mapping
|
||
|
if (array_key_exists($attr, $mapping)) {
|
||
|
$url = $tree->get($attr);
|
||
|
$actionName = false;
|
||
|
|
||
|
//try to find an action with the same url
|
||
|
foreach ($this->actions as $action) {
|
||
|
if ($action->getRelativeUrl() == $url) {
|
||
|
$actionName = $action->getId();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ($actionName) {
|
||
|
$newData[$mapping[$attr]['attr']] = $actionName;
|
||
|
} else {
|
||
|
//otherwise create a new action from the mapping
|
||
|
$newData[$mapping[$attr]['attr']] = $mapping[$attr]['action']['id'];
|
||
|
$actionData = $mapping[$attr]['action'];
|
||
|
$actionData['url'] = $url;
|
||
|
|
||
|
list($extension, $controller, $action) = explode('/', trim($url, '/'));
|
||
|
$actionData['extension'] = $extension;
|
||
|
$actionData['controller'] = $controller;
|
||
|
$actionData['action'] = $action;
|
||
|
|
||
|
$this->actions[] = new Action($actionData);
|
||
|
}
|
||
|
} else {
|
||
|
$newData[$attr] = $tree->get($attr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//the tree is replaced
|
||
|
$this->trees[$index] = new Tree($newData);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public function __toPhpCode()
|
||
|
{
|
||
|
return "new " . __CLASS__ . "("
|
||
|
. \common_Utils::toPHPVariableString($this->data) . ','
|
||
|
. \common_Utils::toPHPVariableString($this->trees) . ','
|
||
|
. \common_Utils::toPHPVariableString($this->actions) . ','
|
||
|
. \common_Utils::toPHPVariableString(self::SERIAL_VERSION)
|
||
|
. ")";
|
||
|
}
|
||
|
}
|