N°2060 [WIP] Initialisation of the portal application: Huge code cleanup

- Rename variables and methods in iTop files to match coding conventions
- Format code accordingly to coding conventions
- Add / update PHPDoc all over the place
- Suppress most of the warnings that did not have a big impact on code's logic
This commit is contained in:
Molkobain
2019-07-09 19:08:40 +02:00
parent c1258d0527
commit 9e9187b169
63 changed files with 3998 additions and 3088 deletions

View File

@@ -1,21 +1,24 @@
<?php
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
/**
* Executes a portal without having a dedicated module.
@@ -23,15 +26,15 @@
*/
// Load current environment
if (file_exists(__DIR__ . '/../../approot.inc.php'))
if (file_exists(__DIR__.'/../../approot.inc.php'))
{
require_once __DIR__ . '/../../approot.inc.php'; // When in env-xxxx folder
require_once __DIR__.'/../../approot.inc.php'; // When in env-xxxx folder
}
else
{
require_once __DIR__ . '/../../../approot.inc.php'; // When in datamodels/x.x folder
require_once __DIR__.'/../../../approot.inc.php'; // When in datamodels/x.x folder
}
require_once APPROOT . 'application/startup.inc.php';
require_once APPROOT.'application/startup.inc.php';
// Load frontal
require_once MODULESROOT . 'itop-portal-base/portal/public/index.php';
require_once MODULESROOT.'itop-portal-base/portal/public/index.php';

View File

@@ -5,33 +5,35 @@ use Combodo\iTop\Portal\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
if (false === in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
echo 'Warning: The console should be invoked via the CLI version of PHP, not the '.\PHP_SAPI.' SAPI'.\PHP_EOL;
if (false === in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true))
{
echo 'Warning: The console should be invoked via the CLI version of PHP, not the '.\PHP_SAPI.' SAPI'.\PHP_EOL;
}
set_time_limit(0);
if(!defined('APPROOT'))
if (!defined('APPROOT'))
{
if (file_exists(__DIR__ . '/../../../../approot.inc.php'))
if (file_exists(__DIR__.'/../../../../approot.inc.php'))
{
require_once __DIR__ . '/../../../../approot.inc.php'; // When in env-xxxx folder
require_once __DIR__.'/../../../../approot.inc.php'; // When in env-xxxx folder
}
else
{
require_once __DIR__ . '/../../../../../approot.inc.php'; // When in datamodels/x.x folder
require_once __DIR__.'/../../../../../approot.inc.php'; // When in datamodels/x.x folder
}
}
require_once APPROOT . 'lib/composer-vendor/autoload.php';
require_once APPROOT.'lib/composer-vendor/autoload.php';
if (!class_exists(Application::class)) {
throw new RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
if (!class_exists(Application::class))
{
throw new RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
}
// Remove --portal_id from CLI params to avoid SF CLI conflicts
// Note: The parameter is needed when calling the bin/console to determine which portal to select
$aCleanedArgv = $_SERVER['argv'];
foreach($aCleanedArgv as $iArg => $sArg)
foreach ($aCleanedArgv as $iArg => $sArg)
{
if (preg_match('/^--portal_id=(.*)$/', $sArg, $aMatches))
{
@@ -40,17 +42,20 @@ foreach($aCleanedArgv as $iArg => $sArg)
}
}
$input = new ArgvInput($aCleanedArgv);
if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) {
putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
$oInput = new ArgvInput($aCleanedArgv);
if (null !== $sEnv = $oInput->getParameterOption(['--env', '-e'], null, true))
{
putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $sEnv);
}
if ($input->hasParameterOption('--no-debug', true)) {
putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
if ($oInput->hasParameterOption('--no-debug', true))
{
putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
}
require_once MODULESROOT . 'itop-portal-base/portal/config/bootstrap.php';
require_once MODULESROOT.'itop-portal-base/portal/config/bootstrap.php';
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$application = new Application($kernel);
$application->run($input);
$oKernel = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
$oApplication = new Application($oKernel);
/** @noinspection PhpUnhandledExceptionInspection */
$oApplication->run($oInput);

View File

@@ -1,63 +1,101 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
// Disable PhpUnhandledExceptionInspection as the exception handling is made by the file including this one
/** @noinspection PhpUnhandledExceptionInspection */
use Symfony\Component\Debug\Debug;
use Symfony\Component\Dotenv\Dotenv;
require_once APPROOT.'/lib/composer-vendor/autoload.php';
// Load current environment if necessary
if(!defined('MODULESROOT'))
if (!defined('MODULESROOT'))
{
if (file_exists(__DIR__ . '/../../../../approot.inc.php'))
if (file_exists(__DIR__.'/../../../../approot.inc.php'))
{
require_once __DIR__ . '/../../../../approot.inc.php'; // When in env-xxxx folder
require_once __DIR__.'/../../../../approot.inc.php'; // When in env-xxxx folder
}
else
{
require_once __DIR__ . '/../../../../../approot.inc.php'; // When in datamodels/x.x folder
require_once __DIR__.'/../../../../../approot.inc.php'; // When in datamodels/x.x folder
}
require_once APPROOT . '/application/startup.inc.php';
require_once APPROOT.'/application/startup.inc.php';
}
// Load cached env vars if the .env.local.php file exists
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
if (is_array($env = @include dirname(__DIR__).'/.env.local.php')) {
$_ENV += $env;
} elseif (!class_exists(Dotenv::class)) {
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
} else {
$path = dirname(__DIR__).'/.env';
$dotenv = new Dotenv(false);
if (is_array($sEnv = @include dirname(__DIR__).'/.env.local.php'))
{
$_ENV += $sEnv;
}
elseif (!class_exists(Dotenv::class))
{
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
}
else
{
$sPath = dirname(__DIR__).'/.env';
$oDotenv = new Dotenv(false);
// load all the .env files
if (method_exists($dotenv, 'loadEnv')) {
$dotenv->loadEnv($path);
} else {
// fallback code in case your Dotenv component is not 4.2 or higher (when loadEnv() was added)
// load all the .env files
if (method_exists($oDotenv, 'loadEnv'))
{
$oDotenv->loadEnv($sPath);
}
else
{
// fallback code in case your Dotenv component is not 4.2 or higher (when loadEnv() was added)
if (file_exists($path) || !file_exists($p = "$path.dist")) {
$dotenv->load($path);
} else {
$dotenv->load($p);
}
if (file_exists($sPath) || !file_exists($sPathDist = "$sPath.dist"))
{
$oDotenv->load($sPath);
}
else
{
$oDotenv->load($sPathDist);
}
if (null === $env = (isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : null))) {
$dotenv->populate(array('APP_ENV' => $env = 'prod'));
}
if (null === $sEnv = (isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : null)))
{
$oDotenv->populate(array('APP_ENV' => $sEnv = 'prod'));
}
if ('test' !== $env && file_exists($p = "$path.local")) {
$dotenv->load($p);
$env = isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : $env);
}
if ('test' !== $sEnv && file_exists($sPathDist = "$sPath.local"))
{
$oDotenv->load($sPathDist);
$sEnv = isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : $sEnv);
}
if (file_exists($p = "$path.$env")) {
$dotenv->load($p);
}
if (file_exists($sPathDist = "$sPath.$sEnv"))
{
$oDotenv->load($sPathDist);
}
if (file_exists($p = "$path.$env.local")) {
$dotenv->load($p);
}
}
if (file_exists($sPathDist = "$sPath.$sEnv.local"))
{
$oDotenv->load($sPathDist);
}
}
}
// Set debug mode only when necessary
@@ -69,27 +107,30 @@ if (utils::ReadParam('debug', 'false') === 'true')
$_SERVER += $_ENV;
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = (isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : null)) ?: 'prod';
$_SERVER['APP_DEBUG'] = isset($_SERVER['APP_DEBUG']) ? $_SERVER['APP_DEBUG'] : (isset($_ENV['APP_DEBUG']) ? $_ENV['APP_DEBUG'] : ('prod' !== $_SERVER['APP_ENV']));
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int)$_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'],
FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
if ($_SERVER['APP_DEBUG']) {
if ($_SERVER['APP_DEBUG'])
{
umask(0000);
if (class_exists(Debug::class)) {
if (class_exists(Debug::class))
{
Debug::enable();
}
}
if(isset($_ENV['PORTAL_ID']))
if (isset($_ENV['PORTAL_ID']))
{
// Nothing to do
}
// Note: Default value is set to "false" to differentiate an empty value from a non given parameter
elseif($sPortalId = utils::ReadParam('portal_id', false, true))
elseif ($sPortalId = utils::ReadParam('portal_id', false, true))
{
$_ENV['PORTAL_ID'] = $sPortalId;
}
elseif(defined('PORTAL_ID'))
elseif (defined('PORTAL_ID'))
{
$_ENV['PORTAL_ID'] = PORTAL_ID;
@trigger_error(
@@ -101,7 +142,7 @@ elseif(defined('PORTAL_ID'))
);
}
if(empty($_ENV['PORTAL_ID']))
if (empty($_ENV['PORTAL_ID']))
{
echo "Missing argument 'portal_id'";
exit;
@@ -110,7 +151,7 @@ if(empty($_ENV['PORTAL_ID']))
// Env. vars to be used in templates and others
$_ENV['COMBODO_CURRENT_ENVIRONMENT'] = utils::GetCurrentEnvironment();
$_ENV['COMBODO_ABSOLUTE_URL'] = utils::GetAbsoluteUrlAppRoot();
$_ENV['COMBODO_MODULES_ABSOLUTE_URL'] = utils::GetAbsoluteUrlModulesRoot();
$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_URL'] = utils::GetAbsoluteUrlModulesRoot() . 'itop-portal-base/portal/public/';
$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'] = MODULESROOT . '/itop-portal-base/portal/public/';
$_ENV['COMBODO_PORTAL_INSTANCE_ABSOLUTE_URL'] = utils::GetAbsoluteUrlModulesRoot() . $_ENV['PORTAL_ID'] . '/';
$_ENV['COMBODO_MODULES_ABSOLUTE_URL'] = utils::GetAbsoluteUrlModulesRoot();
$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_URL'] = utils::GetAbsoluteUrlModulesRoot().'itop-portal-base/portal/public/';
$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'] = MODULESROOT.'/itop-portal-base/portal/public/';
$_ENV['COMBODO_PORTAL_INSTANCE_ABSOLUTE_URL'] = utils::GetAbsoluteUrlModulesRoot().$_ENV['PORTAL_ID'].'/';

View File

@@ -1,7 +1,26 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true],
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true],
];

View File

@@ -20,52 +20,60 @@
*
*/
// Disable PhpUnhandledExceptionInspection as the exception handling is made by the file including this one
/** @noinspection PhpUnhandledExceptionInspection */
// Loading file
use Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration\Basic;
use Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration\Forms;
use Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration\Lists;
// Note: ModuleDesign service is not available yet as this script is processed before service generation,
// Note: ModuleDesign service is not available yet as this script is processed before services generation,
// that's why we have to instantiate it manually.
$oModuleDesign = new ModuleDesign($_ENV['PORTAL_ID']);
// TODO: The following code needs to be refactored to more independent and atomic services.
// Load portal conf. such as properties, themes, templates, ...
// Append into %combodo.portal.instance.conf%
$oBasicCompat = new Basic($oModuleDesign);
$oBasicCompat->Process($container);
// Load portal forms definition
// Append into %combodo.portal.instance.conf%
$oFormsCompat = new Forms($oModuleDesign);
$oFormsCompat->Process($container);
// Load portal lists definition
// Append into %combodo.portal.instance.conf%
$oListsCompat = new Lists($oModuleDesign);
$oListsCompat->Process($container);
// - Generating CSS files
// Generating CSS files
$aImportPaths = array($_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/');
$aPortalConf = $container->getParameter('combodo.portal.instance.conf');
foreach ($aPortalConf['properties']['themes'] as $key => $value)
foreach ($aPortalConf['properties']['themes'] as $sKey => $value)
{
if (!is_array($value))
{
$aPortalConf['properties']['themes'][$key] = $_ENV['COMBODO_ABSOLUTE_URL'].utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$value, $aImportPaths);
$aPortalConf['properties']['themes'][$sKey] = $_ENV['COMBODO_ABSOLUTE_URL'].utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$value,
$aImportPaths);
}
else
{
$aValues = array();
foreach ($value as $sSubValue)
{
$aValues[] = $_ENV['COMBODO_ABSOLUTE_URL'].utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$sSubValue, $aImportPaths);
$aValues[] = $_ENV['COMBODO_ABSOLUTE_URL'].utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$sSubValue,
$aImportPaths);
}
$aPortalConf['properties']['themes'][$key] = $aValues;
$aPortalConf['properties']['themes'][$sKey] = $aValues;
}
}
$container->setParameter('combodo.portal.instance.conf', $aPortalConf);
//TODO: The following needs to be refactored
//session messages
// Session messages
$aAllMessages = array();
if ((array_key_exists('obj_messages', $_SESSION)) && (!empty($_SESSION['obj_messages'])))
{

View File

@@ -1,19 +1,19 @@
framework:
cache:
# Put the unique name of your app here: the prefix seed
# is used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
cache:
# Put the unique name of your app here: the prefix seed
# is used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The app cache caches to the filesystem by default.
# Other options include:
# The app cache caches to the filesystem by default.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: ~
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: ~

View File

@@ -1,3 +1,3 @@
framework:
router:
strict_requirements: true
router:
strict_requirements: true

View File

@@ -1,15 +1,15 @@
framework:
secret: '%env(APP_SECRET)%'
#default_locale: en
#csrf_protection: true
#http_method_override: true
secret: '%env(APP_SECRET)%'
#default_locale: en
#csrf_protection: true
#http_method_override: true
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: ~
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: ~
#esi: true
#fragments: true
php_errors:
log: true
#esi: true
#fragments: true
php_errors:
log: true

View File

@@ -1,3 +1,3 @@
framework:
router:
strict_requirements: ~
router:
strict_requirements: ~

View File

@@ -1,4 +1,4 @@
framework:
test: true
session:
storage_id: session.storage.mock_file
test: true
session:
storage_id: session.storage.mock_file

View File

@@ -1,3 +1,3 @@
framework:
router:
strict_requirements: true
router:
strict_requirements: true

View File

@@ -3,4 +3,4 @@ web_profiler:
intercept_redirects: false
framework:
profiler: { collect: false }
profiler: { collect: falseS }

View File

@@ -1,4 +1,4 @@
twig:
default_path: '%combodo.modules.absolute_path%'
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
default_path: '%combodo.modules.absolute_path%'
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'

View File

@@ -1,3 +1,3 @@
_errors:
resource: '@TwigBundle/Resources/config/routing/errors.xml'
prefix: /_error
resource: '@TwigBundle/Resources/config/routing/errors.xml'
prefix: /_error

View File

@@ -1,34 +1,47 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 30/01/19
* Time: 18:06
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
use Combodo\iTop\Portal\Routing\ItopExtensionsExtraRoutes;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use App\Controller\BlogController;
$oRouteCollection = new RouteCollection();
$aRoutes = \Combodo\iTop\Portal\Routing\ItopExtensionsExtraRoutes::getRoutes();
$aRoutes = ItopExtensionsExtraRoutes::GetRoutes();
foreach ($aRoutes as $aRoute)
{
$aRoute['values'] = (isset($aRoute['values'])) ? $aRoute['values'] : [];
$aRoute['asserts'] = (isset($aRoute['asserts'])) ? $aRoute['asserts'] : [];
$routes = new RouteCollection();
foreach ($aRoutes as $route) {
$route['values'] = (isset($route['values'])) ? $route['values'] : [];
$route['asserts'] = (isset($route['asserts'])) ? $route['asserts'] : [];
$routes->add(
$route['bind'],
new Route(
$route['pattern'],
array_merge(
['_controller' => $route['callback']],
$route['values']
),
$route['asserts']
)
);
$oRouteCollection->add(
$aRoute['bind'],
new Route(
$aRoute['pattern'],
array_merge(
['_controller' => $aRoute['callback']],
$aRoute['values']
),
$aRoute['asserts']
)
);
}
return $routes;
return $oRouteCollection;

View File

@@ -19,115 +19,115 @@
# Files in the packages/ subdirectory configure your dependencies.
imports:
- { resource: "legacy_silex_compat_layer.php" }
- { resource: "legacy_silex_compat_layer.php" }
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
# Replace default url generator service
router.options.generator_base_class: Combodo\iTop\Portal\Routing\UrlGenerator
# Replace default url generator service
router.options.generator_base_class: Combodo\iTop\Portal\Routing\UrlGenerator
# Used in templates
combodo.current_environment: '%env(string:COMBODO_CURRENT_ENVIRONMENT)%'
combodo.absolute_url: '%env(string:COMBODO_ABSOLUTE_URL)%'
combodo.modules.absolute_url: '%env(string:COMBODO_MODULES_ABSOLUTE_URL)%'
combodo.modules.absolute_path: !php/const MODULESROOT
combodo.portal.base.absolute_url: '%env(string:COMBODO_PORTAL_BASE_ABSOLUTE_URL)%'
combodo.portal.base.absolute_path: '%env(string:COMBODO_PORTAL_BASE_ABSOLUTE_PATH)%'
combodo.portal.instance.absolute_url: '%env(string:COMBODO_PORTAL_INSTANCE_ABSOLUTE_URL)%'
combodo.portal.instance.id: '%env(string:PORTAL_ID)%'
# Used in templates
combodo.current_environment: '%env(string:COMBODO_CURRENT_ENVIRONMENT)%'
combodo.absolute_url: '%env(string:COMBODO_ABSOLUTE_URL)%'
combodo.modules.absolute_url: '%env(string:COMBODO_MODULES_ABSOLUTE_URL)%'
combodo.modules.absolute_path: !php/const MODULESROOT
combodo.portal.base.absolute_url: '%env(string:COMBODO_PORTAL_BASE_ABSOLUTE_URL)%'
combodo.portal.base.absolute_path: '%env(string:COMBODO_PORTAL_BASE_ABSOLUTE_PATH)%'
combodo.portal.instance.absolute_url: '%env(string:COMBODO_PORTAL_INSTANCE_ABSOLUTE_URL)%'
combodo.portal.instance.id: '%env(string:PORTAL_ID)%'
services:
# Default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
bind:
$bDebug: '%kernel.debug%'
$sPortalCachePath: '%kernel.cache_dir%/'
$sPortalId: '%env(string:PORTAL_ID)%'
$aCombodoPortalInstanceConf: '%combodo.portal.instance.conf%'
$sCombodoPortalInstanceAbsoluteUrl: '%env(string:COMBODO_PORTAL_INSTANCE_ABSOLUTE_URL)%'
# Default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
bind:
$bDebug: '%kernel.debug%'
$sPortalCachePath: '%kernel.cache_dir%/'
$sPortalId: '%env(string:PORTAL_ID)%'
$aCombodoPortalInstanceConf: '%combodo.portal.instance.conf%'
$sCombodoPortalInstanceAbsoluteUrl: '%env(string:COMBODO_PORTAL_INSTANCE_ABSOLUTE_URL)%'
# Makes classes in src/ available to be used as services
# This creates a service per class whose id is the fully-qualified class name
Combodo\iTop\Portal\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# Makes classes in src/ available to be used as services
# This creates a service per class whose id is the fully-qualified class name
Combodo\iTop\Portal\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# Controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
Combodo\iTop\Portal\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# Controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
Combodo\iTop\Portal\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# Tag services without defining them (see https://symfony.com/doc/current/service_container/tags.html#autoconfiguring-tags)
_instanceof:
Combodo\iTop\Portal\EventListener\UserProvider:
tags: [{ name: 'kernel.event_listener', event: 'kernel.request' }]
calls:
- [setContainer, ['@service_container']]
Combodo\iTop\Portal\EventListener\ApplicationContextSetUrlMakerClass:
tags: [{ name: 'kernel.event_listener', event: 'kernel.request' }]
# Tag services without defining them (see https://symfony.com/doc/current/service_container/tags.html#autoconfiguring-tags)
_instanceof:
Combodo\iTop\Portal\EventListener\UserProvider:
tags: [{ name: 'kernel.event_listener', event: 'kernel.request' }]
calls:
- [setContainer, ['@service_container']]
Combodo\iTop\Portal\EventListener\ApplicationContextSetUrlMakerClass:
tags: [{ name: 'kernel.event_listener', event: 'kernel.request' }]
# Add more service definitions when explicit configuration is needed
# Please note that last definitions always *replace* previous ones
# Add more service definitions when explicit configuration is needed
# Please note that last definitions always *replace* previous ones
# Legacy code as a service: since it is not in the auto-wiring path, it needs to be explicitly declared
ModuleDesign:
public: true
class: ModuleDesign
arguments:
- '%combodo.portal.instance.id%'
# Legacy code as a service: since it is not in the auto-wiring path, it needs to be explicitly declared
ModuleDesign:
public: true
class: ModuleDesign
arguments:
- '%combodo.portal.instance.id%'
# Decoration
# - Compatibility layer with Silex\Application which was used almost everywhere in the portal's templates
Combodo\iTop\Portal\Twig\AppVariable:
decorates: twig.app_variable
arguments:
- '@Combodo\iTop\Portal\Twig\AppVariable.inner'
- '@service_container'
# Decoration
# - Compatibility layer with Silex\Application which was used almost everywhere in the portal's templates
Combodo\iTop\Portal\Twig\AppVariable:
decorates: twig.app_variable
arguments:
- '@Combodo\iTop\Portal\Twig\AppVariable.inner'
- '@service_container'
# Standard services
combodo.current_contact.photo_url:
public: true
class: Combodo\iTop\Portal\VariableAccessor\CombodoCurrentContactPhotoUrl
arguments: ['@combodo.current_user']
# Note: This service is initialized with a UserLocal object as it needs a class that can be instantiated.
# Anyway, it will be replaced with the real class by UserProvider in onKernelRequestEvent.
# Note: Services relying on this one should use \User in their signature and not \UserLocal.
combodo.current_user:
public: true
class: UserLocal
# Standard services
combodo.current_contact.photo_url:
public: true
class: Combodo\iTop\Portal\VariableAccessor\CombodoCurrentContactPhotoUrl
arguments: ['@combodo.current_user']
# Note: This service is initialized with a UserLocal object as it needs a class that can be instantiated.
# Anyway, it will be replaced with the real class by UserProvider in onKernelRequestEvent.
# Note: Services relying on this one should use \User in their signature and not \UserLocal.
combodo.current_user:
public: true
class: UserLocal
# Aliases
brick_collection:
alias: Combodo\iTop\Portal\Brick\BrickCollection
public: true
request_manipulator:
alias: Combodo\iTop\Portal\Helper\RequestManipulatorHelper
public: true
scope_validator:
alias: Combodo\iTop\Portal\Helper\ScopeValidatorHelper
public: true
security_helper:
alias: Combodo\iTop\Portal\Helper\SecurityHelper
public: true
context_manipulator:
alias: Combodo\iTop\Portal\Helper\ContextManipulatorHelper
public: true
lifecycle_validator:
alias: Combodo\iTop\Portal\Helper\LifecycleValidatorHelper
public: true
url_generator:
alias: router
public: true
object_form_handler:
alias: Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper
public: true
browse_brick:
alias: Combodo\iTop\Portal\Helper\BrowseBrickHelper
public: true
# Aliases
brick_collection:
alias: Combodo\iTop\Portal\Brick\BrickCollection
public: true
request_manipulator:
alias: Combodo\iTop\Portal\Helper\RequestManipulatorHelper
public: true
scope_validator:
alias: Combodo\iTop\Portal\Helper\ScopeValidatorHelper
public: true
security_helper:
alias: Combodo\iTop\Portal\Helper\SecurityHelper
public: true
context_manipulator:
alias: Combodo\iTop\Portal\Helper\ContextManipulatorHelper
public: true
lifecycle_validator:
alias: Combodo\iTop\Portal\Helper\LifecycleValidatorHelper
public: true
url_generator:
alias: router
public: true
object_form_handler:
alias: Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper
public: true
browse_brick:
alias: Combodo\iTop\Portal\Helper\BrowseBrickHelper
public: true

View File

@@ -1,22 +1,44 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
use Combodo\iTop\Portal\Kernel;
use Symfony\Component\HttpFoundation\Request;
require_once MODULESROOT . 'itop-portal-base/portal/config/bootstrap.php';
require_once MODULESROOT.'itop-portal-base/portal/config/bootstrap.php';
// Note: Manually refactored ternary condition to be PHP 5.x compatible
if ($trustedProxies = isset($_SERVER['TRUSTED_PROXIES']) ? $_SERVER['TRUSTED_PROXIES'] : (isset($_ENV['TRUSTED_PROXIES']) ? $_ENV['TRUSTED_PROXIES'] : false) ) {
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
if ($trustedProxies = isset($_SERVER['TRUSTED_PROXIES']) ? $_SERVER['TRUSTED_PROXIES'] : (isset($_ENV['TRUSTED_PROXIES']) ? $_ENV['TRUSTED_PROXIES'] : false))
{
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
// Note: Manually refactored ternary condition to be PHP 5.x compatible
if ($trustedHosts = isset($_SERVER['TRUSTED_HOSTS']) ? $_SERVER['TRUSTED_HOSTS'] : (isset($_ENV['TRUSTED_HOSTS']) ? $_ENV['TRUSTED_HOSTS'] : false) ) {
Request::setTrustedHosts([$trustedHosts]);
if ($trustedHosts = isset($_SERVER['TRUSTED_HOSTS']) ? $_SERVER['TRUSTED_HOSTS'] : (isset($_ENV['TRUSTED_HOSTS']) ? $_ENV['TRUSTED_HOSTS'] : false))
{
Request::setTrustedHosts([$trustedHosts]);
}
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
$oKernel = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
$oRequest = Request::createFromGlobals();
/** @noinspection PhpUnhandledExceptionInspection */
$oResponse = $oKernel->handle($oRequest);
$oResponse->send();
$oKernel->terminate($oRequest, $oResponse);

View File

@@ -1,26 +1,29 @@
<?php
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\Brick;
require_once APPROOT . '/core/moduledesign.class.inc.php';
require_once APPROOT . '/setup/compiler.class.inc.php';
require_once APPROOT.'/core/moduledesign.class.inc.php';
require_once APPROOT.'/setup/compiler.class.inc.php';
use DOMFormatException;
use ModuleDesign;
@@ -28,40 +31,68 @@ use Combodo\iTop\DesignElement;
/**
* Description of AbstractBrick
*
* Bricks are used mostly in the portal for now, not the console.
* This class defines common functionnalities for the extended classes.
*
* Bricks are used mostly in the portal for now, not the console.
* This class defines common functionalities for the extended classes.
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
abstract class AbstractBrick
{
/** @var string ENUM_DATA_LOADING_LAZY */
const ENUM_DATA_LOADING_LAZY = 'lazy';
/** @var string ENUM_DATA_LOADING_FULL */
const ENUM_DATA_LOADING_FULL = 'full';
/** @var string ENUM_DATA_LOADING_AUTO */
const ENUM_DATA_LOADING_AUTO = 'auto';
/** @var bool DEFAULT_MANDATORY */
const DEFAULT_MANDATORY = true;
/** @var bool DEFAULT_ACTIVE */
const DEFAULT_ACTIVE = true;
/** @var bool DEFAULT_VISIBLE */
const DEFAULT_VISIBLE = true;
/** @var float DEFAULT_RANK */
const DEFAULT_RANK = 1.0;
/** @var string|null DEFAULT_PAGE_TEMPLATE_PATH */
const DEFAULT_PAGE_TEMPLATE_PATH = null;
/** @var string DEFAULT_TITLE */
const DEFAULT_TITLE = '';
/** @var string|null DEFAULT_DESCRIPTION */
const DEFAULT_DESCRIPTION = null;
/** @var string DEFAULT_DATA_LOADING */
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_AUTO;
/** @var string DEFAULT_ALLOWED_PROFILES_OQL */
const DEFAULT_ALLOWED_PROFILES_OQL = '';
/** @var string DEFAULT_DENIED_PROFILES_OQL */
const DEFAULT_DENIED_PROFILES_OQL = '';
/** @var string $sId */
protected $sId;
/** @var bool $bMandatory */
protected $bMandatory;
/** @var bool $bActive */
protected $bActive;
/** @var bool $bVisible */
protected $bVisible;
/** @var float $fRank */
protected $fRank;
/** @var string|null $sPageTemplatePath */
protected $sPageTemplatePath;
/** @var string $sTitle */
protected $sTitle;
/** @var string|null $sDescription */
protected $sDescription;
/** @var string $sDataLoading */
protected $sDataLoading;
/** @var array $aAllowedProfiles */
protected $aAllowedProfiles;
/** @var array $aDeniedProfiles */
protected $aDeniedProfiles;
/** @var string $sAllowedProfilesOql */
protected $sAllowedProfilesOql;
/** @var string $sDeniedProfilesOql */
protected $sDeniedProfilesOql;
/**
@@ -77,7 +108,7 @@ abstract class AbstractBrick
/**
* Default attributes values of AbstractBrick are specified in the definition, not the constructor.
*/
function __construct()
public function __construct()
{
$this->bMandatory = static::DEFAULT_MANDATORY;
$this->bActive = static::DEFAULT_ACTIVE;
@@ -253,8 +284,8 @@ abstract class AbstractBrick
* Sets if the brick is visible
*
* @param boolean $bVisible
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetVisible($bVisible)
{
@@ -344,12 +375,13 @@ abstract class AbstractBrick
* Sets the allowed profiles for the brick
*
* @param array $aAllowedProfiles
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetAllowedProfiles($aAllowedProfiles)
{
$this->aAllowedProfiles = $aAllowedProfiles;
return $this;
}
@@ -357,8 +389,8 @@ abstract class AbstractBrick
* Sets the denied profiles for the brick
*
* @param array $aDeniedProfiles
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetDeniedProfiles($aDeniedProfiles)
{
@@ -382,7 +414,7 @@ abstract class AbstractBrick
/**
* Sets the denied profiles oql query for the brick
*
* @param array $sDeniedProfilesOql
* @param string $sDeniedProfilesOql
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
@@ -396,12 +428,13 @@ abstract class AbstractBrick
* Adds $sProfile to the list of allowed profiles for that brick
*
* @param string $sProfile
*
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function AddAllowedProfile($sProfile)
{
$this->aAllowedProfiles[] = $sProfile;
return $this;
}
@@ -409,7 +442,7 @@ abstract class AbstractBrick
* Removes $sProfile from the list of allowed profiles
*
* @param string $sProfile
*
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function RemoveAllowedProfile($sProfile)
@@ -418,6 +451,7 @@ abstract class AbstractBrick
{
unset($this->aAllowedProfiles[$sProfile]);
}
return $this;
}
@@ -435,12 +469,13 @@ abstract class AbstractBrick
* Adds $sProfile to the list of denied profiles for that brick
*
* @param string $sProfile
*
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function AddDeniedProfile($sProfile)
{
$this->aDeniedProfiles[] = $sProfile;
return $this;
}
@@ -448,7 +483,7 @@ abstract class AbstractBrick
* Removes $sProfile from the list of denied profiles
*
* @param string $sProfile
*
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function RemoveDeniedProfile($sProfile)
@@ -457,6 +492,7 @@ abstract class AbstractBrick
{
unset($this->aDeniedProfiles[$sProfile]);
}
return $this;
}
@@ -477,7 +513,7 @@ abstract class AbstractBrick
* Priority is deny/allow
*
* @param string $sProfile
*
*
* @return boolean
*/
public function IsGrantedForProfile($sProfile)
@@ -492,7 +528,7 @@ abstract class AbstractBrick
* Priority is deny/allow
*
* @param array $aProfiles
*
*
* @return boolean
*/
public function IsGrantedForProfiles($aProfiles)
@@ -543,9 +579,9 @@ abstract class AbstractBrick
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @throws \DOMFormatException
*/
public function LoadFromXml(DesignElement $oMDElement)
@@ -558,28 +594,31 @@ abstract class AbstractBrick
$this->SetId($oMDElement->getAttribute('id'));
// Checking others elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
case 'mandatory':
$this->SetMandatory(($oBrickSubNode->GetText() === 'no') ? false : true );
$this->SetMandatory(($oBrickSubNode->GetText() === 'no') ? false : true);
break;
case 'active':
$this->SetActive(($oBrickSubNode->GetText() === 'false') ? false : true );
$this->SetActive(($oBrickSubNode->GetText() === 'false') ? false : true);
break;
case 'rank':
$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
if ($oOptionalNode !== null)
{
$this->SetRank((float) $oOptionalNode->GetText(static::DEFAULT_RANK));
$this->SetRank((float)$oOptionalNode->GetText(static::DEFAULT_RANK));
}
break;
case 'templates':
$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id=' . ModuleDesign::XPathQuote('page') . ']');
$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id='.ModuleDesign::XPathQuote('page').']');
if ($oTemplateNodeList->length > 0)
{
$this->SetPageTemplatePath($oTemplateNodeList->item(0)->GetText(static::DEFAULT_PAGE_TEMPLATE_PATH));
/** @var \Combodo\iTop\DesignElement $oTemplateNode */
$oTemplateNode = $oTemplateNodeList->item(0);
$this->SetPageTemplatePath($oTemplateNode->GetText(static::DEFAULT_PAGE_TEMPLATE_PATH));
}
break;
case 'title':
@@ -596,11 +635,13 @@ abstract class AbstractBrick
$this->SetDataLoading($oBrickSubNode->GetText(static::DEFAULT_DATA_LOADING));
break;
case 'security':
/** @var \Combodo\iTop\DesignElement $oSecurityNode */
foreach ($oBrickSubNode->childNodes as $oSecurityNode)
{
if ($oSecurityNode->nodeType === XML_TEXT_NODE && $oSecurityNode->GetText() === '')
{
throw new DOMFormatException('Brick security node "' . $oSecurityNode->nodeName . '" must contain an OQL query, it cannot be empty', null, null, $oMDElement);
throw new DOMFormatException('Brick security node "'.$oSecurityNode->nodeName.'" must contain an OQL query, it cannot be empty',
null, null, $oMDElement);
}
switch ($oSecurityNode->nodeName)

View File

@@ -1,35 +1,49 @@
<?php
// Copyright (c) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\Brick;
use Combodo\iTop\DesignElement;
use Dict;
use DOMFormatException;
/**
* Class AggregatePageBrick
*
* @package Combodo\iTop\Portal\Brick
* @since 2.5.0
* @author Eric Espie <eric.espie@combodo.com>
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @author Pierre Goiffon <pierre.goiffon@combodo.com>
*/
class AggregatePageBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-dashboard';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-dashboard fa-2x';
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/aggregate-page/layout.html.twig';
static $sRouteName = 'p_aggregatepage_brick';
// Overloaded variables
public static $sRouteName = 'p_aggregatepage_brick';
/**
* @var string[] list of bricks to use, ordered by rank (key=id, value=rank)
@@ -50,23 +64,25 @@ class AggregatePageBrick extends PortalBrick
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\AggregatePageBrick
*
*
* @throws \DOMFormatException
*/
public function LoadFromXml(DesignElement $oMDElement)
{
parent::LoadFromXml($oMDElement);
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
case 'aggregate_page_bricks':
/** @var \Combodo\iTop\DesignElement $oAggregatePageBrickNode */
foreach ($oBrickSubNode->GetNodes('./aggregate_page_brick') as $oAggregatePageBrickNode)
{
if (!$oAggregatePageBrickNode->hasAttribute('id'))
{
throw new \DOMFormatException('AggregatePageBrick : must have an id attribute', null,
throw new DOMFormatException('AggregatePageBrick : must have an id attribute', null,
null, $oAggregatePageBrickNode);
}
$sBrickName = $oAggregatePageBrickNode->getAttribute('id');

View File

@@ -31,24 +31,24 @@ use Combodo\iTop\Portal\Helper\ApplicationHelper;
* Class BrickCollection
*
* @package Combodo\iTop\Portal\Brick
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class BrickCollection
{
/** @var \ModuleDesign */
/** @var \ModuleDesign $oModuleDesign */
private $oModuleDesign;
/** @var array|null $aAllowedBricks Lazily computed */
private $aAllowedBricks;
/** @var int $iDisplayedInHome Lazily computed */
private $iDisplayedInHome;
/** @var int $iDisplayedInNavigationMenu Lazily computed */
private $iDisplayedInNavigationMenu;
/** @var array $aHomeOrdering */
private $aHomeOrdering;
/** @var array $aNavigationMenuOrdering */
private $aNavigationMenuOrdering;
/** @var array|null $aAllowedBricks Lazily computed */
private $aAllowedBricks;
/** @var int $iDisplayedInHome Lazily computed */
private $iDisplayedInHome;
/** @var int $iDisplayedInNavigationMenu Lazily computed */
private $iDisplayedInNavigationMenu;
/** @var array $aHomeOrdering */
private $aHomeOrdering;
/** @var array $aNavigationMenuOrdering */
private $aNavigationMenuOrdering;
/**
* BrickCollection constructor.
@@ -58,16 +58,16 @@ class BrickCollection
* @throws \Exception
*/
public function __construct(ModuleDesign $oModuleDesign)
{
$this->oModuleDesign = $oModuleDesign;
$this->aAllowedBricks = null;
$this->iDisplayedInHome = 0;
$this->iDisplayedInNavigationMenu = 0;
$this->aHomeOrdering = array();
$this->aNavigationMenuOrdering = array();
{
$this->oModuleDesign = $oModuleDesign;
$this->aAllowedBricks = null;
$this->iDisplayedInHome = 0;
$this->iDisplayedInNavigationMenu = 0;
$this->aHomeOrdering = array();
$this->aNavigationMenuOrdering = array();
$this->Load();
}
$this->Load();
}
/**
* @param $method
@@ -78,32 +78,32 @@ class BrickCollection
* @throws \Exception
*/
public function __call($method, $arguments)
{
// Made for cleaner/easier access from twig (eg. app['brick_collection'].bricks)
switch($method)
{
case 'bricks':
return $this->GetBricks();
break;
case 'home_ordering':
return $this->GetHomeOrdering();
break;
case 'navigation_menu_ordering':
return $this->GetNavigationMenuOrdering();
break;
default:
throw new PropertyNotFoundException("The property '$method' do not exists in BricksCollection");
}
}
{
// Made for cleaner/easier access from twig (eg. app['brick_collection'].bricks)
switch ($method)
{
case 'bricks':
return $this->GetBricks();
break;
case 'home_ordering':
return $this->GetHomeOrdering();
break;
case 'navigation_menu_ordering':
return $this->GetNavigationMenuOrdering();
break;
default:
throw new PropertyNotFoundException("The property '$method' do not exists in BricksCollection");
}
}
/**
* @return \Combodo\iTop\Portal\Brick\PortalBrick[]|null
* @throws \Exception
*/
public function GetBricks()
{
return $this->aAllowedBricks;
}
public function GetBricks()
{
return $this->aAllowedBricks;
}
public function GetHomeOrdering()
{
@@ -122,93 +122,95 @@ class BrickCollection
* @throws \Combodo\iTop\Portal\Brick\BrickNotFoundException
* @throws \Exception
*/
public function GetBrickById($sId)
{
foreach ($this->GetBricks() as $oBrick) {
if ($oBrick->GetId() === $sId)
{
return $oBrick;
}
}
public function GetBrickById($sId)
{
foreach ($this->GetBricks() as $oBrick)
{
if ($oBrick->GetId() === $sId)
{
return $oBrick;
}
}
throw new BrickNotFoundException('Brick with id = "'.$sId.'" was not found among loaded bricks.');
}
throw new BrickNotFoundException('Brick with id = "'.$sId.'" was not found among loaded bricks.');
}
/**
* @throws \Exception
*/
private function Load()
{
$aRawBrickList = $this->GetRawBrickList();
{
$aRawBrickList = $this->GetRawBrickList();
foreach ($aRawBrickList as $oBrick) {
ApplicationHelper::LoadBrickSecurity($oBrick);
foreach ($aRawBrickList as $oBrick)
{
ApplicationHelper::LoadBrickSecurity($oBrick);
if ($oBrick->GetActive() && $oBrick->IsGrantedForProfiles(UserRights::ListProfiles()))
{
$this->aAllowedBricks[] = $oBrick;
if ($oBrick->GetVisibleHome())
{
$this->iDisplayedInHome++;
}
if ($oBrick->GetVisibleNavigationMenu())
{
$this->iDisplayedInNavigationMenu++;
}
}
}
if ($oBrick->GetActive() && $oBrick->IsGrantedForProfiles(UserRights::ListProfiles()))
{
$this->aAllowedBricks[] = $oBrick;
if ($oBrick->GetVisibleHome())
{
$this->iDisplayedInHome++;
}
if ($oBrick->GetVisibleNavigationMenu())
{
$this->iDisplayedInNavigationMenu++;
}
}
}
// - Sorting bricks by rank
// - Home
$this->aHomeOrdering = $this->aAllowedBricks;
usort($this->aHomeOrdering, function (PortalBrick $a, PortalBrick $b) {
return $a->GetRankHome() > $b->GetRankHome();
});
// - Navigation menu
$this->aNavigationMenuOrdering = $this->aAllowedBricks;
usort($this->aNavigationMenuOrdering, function (PortalBrick $a, PortalBrick $b) {
return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu();
});
}
// - Sorting bricks by rank
// - Home
$this->aHomeOrdering = $this->aAllowedBricks;
usort($this->aHomeOrdering, function (PortalBrick $a, PortalBrick $b) {
return $a->GetRankHome() > $b->GetRankHome();
});
// - Navigation menu
$this->aNavigationMenuOrdering = $this->aAllowedBricks;
usort($this->aNavigationMenuOrdering, function (PortalBrick $a, PortalBrick $b) {
return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu();
});
}
/**
* @return array
* @throws \Exception
*/
private function GetRawBrickList()
{
$aBricks = array();
/** @var \Combodo\iTop\DesignElement $oBrickNode */
foreach ($this->oModuleDesign->GetNodes('/module_design/bricks/brick') as $oBrickNode)
{
$sBrickClass = $oBrickNode->getAttribute('xsi:type');
try
{
if (class_exists($sBrickClass))
{
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oBrick */
$oBrick = new $sBrickClass();
$oBrick->LoadFromXml($oBrickNode);
{
$aBricks = array();
/** @var \Combodo\iTop\DesignElement $oBrickNode */
foreach ($this->oModuleDesign->GetNodes('/module_design/bricks/brick') as $oBrickNode)
{
$sBrickClass = $oBrickNode->getAttribute('xsi:type');
try
{
if (class_exists($sBrickClass))
{
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oBrick */
$oBrick = new $sBrickClass();
$oBrick->LoadFromXml($oBrickNode);
$aBricks[] = $oBrick;
}
else
{
throw new DOMFormatException('Unknown brick class "'.$sBrickClass.'" from xsi:type attribute', null,
null, $oBrickNode);
}
}
catch (DOMFormatException $e)
{
throw new Exception('Could not create brick ('.$sBrickClass.') from XML because of a DOM problem : '.$e->getMessage());
}
catch (Exception $e)
{
throw new Exception('Could not create brick ('.$sBrickClass.') from XML : '.$oBrickNode->Dump().' '.$e->getMessage());
}
}
$aBricks[] = $oBrick;
}
else
{
throw new DOMFormatException('Unknown brick class "'.$sBrickClass.'" from xsi:type attribute', null,
null, $oBrickNode);
}
}
catch (DOMFormatException $e)
{
throw new Exception('Could not create brick ('.$sBrickClass.') from XML because of a DOM problem : '.$e->getMessage());
}
catch (Exception $e)
{
throw new Exception('Could not create brick ('.$sBrickClass.') from XML : '.$oBrickNode->Dump().' '.$e->getMessage());
}
}
return $aBricks;
}
return $aBricks;
}
}

View File

@@ -1,8 +1,22 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 24/01/19
* Time: 17:28
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\Brick;
@@ -14,6 +28,7 @@ use Exception;
*
* @package Combodo\iTop\Portal\Brick
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class BrickNotFoundException extends Exception
{

View File

@@ -27,49 +27,79 @@ use Combodo\iTop\DesignElement;
/**
* Description of BrowseBrick
*
*
* @package Combodo\iTop\Portal\Brick
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class BrowseBrick extends PortalBrick
{
/** @var string ENUM_BROWSE_MODE_LIST */
const ENUM_BROWSE_MODE_LIST = 'list';
const ENUM_BROWSE_MODE_TREE = 'tree';
const ENUM_BROWSE_MODE_MOSAIC = 'mosaic';
/** @var string ENUM_BROWSE_MODE_TREE */
const ENUM_BROWSE_MODE_TREE = 'tree';
/** @var string ENUM_BROWSE_MODE_MOSAIC */
const ENUM_BROWSE_MODE_MOSAIC = 'mosaic';
/** @var string ENUM_ACTION_VIEW */
const ENUM_ACTION_VIEW = 'view';
/** @var string ENUM_ACTION_EDIT */
const ENUM_ACTION_EDIT = 'edit';
/** @var string ENUM_ACTION_DRILLDOWN */
const ENUM_ACTION_DRILLDOWN = 'drilldown';
/** @var string ENUM_ACTION_CREATE_FROM_THIS */
const ENUM_ACTION_CREATE_FROM_THIS = 'create_from_this';
/** @var string ENUM_ACTION_ICON_CLASS_VIEW */
const ENUM_ACTION_ICON_CLASS_VIEW = 'glyphicon glyphicon-list-alt';
/** @var string ENUM_ACTION_ICON_CLASS_EDIT */
const ENUM_ACTION_ICON_CLASS_EDIT = 'glyphicon glyphicon-pencil';
/** @var string ENUM_ACTION_ICON_CLASS_DRILLDOWN */
const ENUM_ACTION_ICON_CLASS_DRILLDOWN = 'glyphicon glyphicon-menu-down';
/** @var string ENUM_ACTION_ICON_CLASS_CREATE_FROM_THIS */
const ENUM_ACTION_ICON_CLASS_CREATE_FROM_THIS = 'glyphicon glyphicon-edit';
/** @var string ENUM_FACTORY_TYPE_METHOD */
const ENUM_FACTORY_TYPE_METHOD = 'method';
/** @var string ENUM_FACTORY_TYPE_CLASS */
const ENUM_FACTORY_TYPE_CLASS = 'class';
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-map';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-map fa-2x';
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_FULL;
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-map fa-2x';
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_FULL;
/** @var string DEFAULT_LEVEL_NAME_ATT */
const DEFAULT_LEVEL_NAME_ATT = 'name';
/** @var string DEFAULT_BROWSE_MODE */
const DEFAULT_BROWSE_MODE = self::ENUM_BROWSE_MODE_LIST;
/** @var string DEFAULT_ACTION */
const DEFAULT_ACTION = self::ENUM_ACTION_DRILLDOWN;
/** @var string DEFAULT_ACTION_OPENING_TARGET */
const DEFAULT_ACTION_OPENING_TARGET = self::ENUM_OPENING_TARGET_MODAL;
/** @var int DEFAULT_LIST_LENGTH */
const DEFAULT_LIST_LENGTH = 20;
static $aBrowseModes = array(
self::ENUM_BROWSE_MODE_LIST,
self::ENUM_BROWSE_MODE_TREE,
self::ENUM_BROWSE_MODE_MOSAIC
);
// Overloaded variables
public static $sRouteName = 'p_browse_brick';
static $sRouteName = 'p_browse_brick';
/** @var array $aBrowseModes */
public static $aBrowseModes = array(
self::ENUM_BROWSE_MODE_LIST,
self::ENUM_BROWSE_MODE_TREE,
self::ENUM_BROWSE_MODE_MOSAIC,
);
/** @var array $aLevels */
protected $aLevels;
/** @var array $aAvailablesBrowseModes */
protected $aAvailablesBrowseModes;
/** @var string $sDefaultBrowseMode */
protected $sDefaultBrowseMode;
/**
* BrowseBrick constructor.
*/
public function __construct()
{
parent::__construct();
@@ -90,7 +120,7 @@ class BrowseBrick extends PortalBrick
}
/**
* Returns the brick availables browse modes
* Returns the brick available browse modes
*
* @return array
*/
@@ -109,42 +139,45 @@ class BrowseBrick extends PortalBrick
return $this->sDefaultBrowseMode;
}
/**
* Sets the levels of the brick
*
* @param array $aLevels
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
/**
* Sets the levels of the brick
*
* @param array $aLevels
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function SetLevels($aLevels)
{
$this->aLevels = $aLevels;
return $this;
}
/**
* Sets the availables browse modes of the brick
* Sets the available browse modes of the brick
*
* @param array $aAvailablesBrowseModes
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function SetAvailablesBrowseModes($aAvailablesBrowseModes)
{
$this->aAvailablesBrowseModes = $aAvailablesBrowseModes;
return $this;
}
/**
* Sets the adefault browse mode of the brick
* Sets the default browse mode of the brick
*
* @param string $sDefaultBrowseMode
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function SetDefaultBrowseMode($sDefaultBrowseMode)
{
$this->sDefaultBrowseMode = $sDefaultBrowseMode;
return $this;
}
@@ -162,12 +195,13 @@ class BrowseBrick extends PortalBrick
* Adds $aLevel to the list of levels for that brick
*
* @param array $aLevel
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function AddLevel($aLevel)
{
$this->aLevels[] = $aLevel;
return $this;
}
@@ -175,8 +209,8 @@ class BrowseBrick extends PortalBrick
* Removes $aLevel from the list of levels browse modes
*
* @param string $sLevel
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function RemoveLevels($sLevel)
{
@@ -184,6 +218,7 @@ class BrowseBrick extends PortalBrick
{
unset($this->aLevels[$sLevel]);
}
return $this;
}
@@ -191,13 +226,14 @@ class BrowseBrick extends PortalBrick
* Adds $sModeId to the list of availables browse modes for that brick
*
* @param string $sModeId
* @param array $aData Hash array containing 'template' => TEMPLATE_PATH
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
* @param array $aData Hash array containing 'template' => TEMPLATE_PATH
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function AddAvailableBrowseMode($sModeId, $aData = array())
{
$this->aAvailablesBrowseModes[$sModeId] = $aData;
return $this;
}
@@ -205,8 +241,8 @@ class BrowseBrick extends PortalBrick
* Removes $sModeId from the list of availables browse modes
*
* @param string $sModeId
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function RemoveAvailableBrowseMode($sModeId)
{
@@ -214,6 +250,7 @@ class BrowseBrick extends PortalBrick
{
unset($this->aAvailablesBrowseModes[$sModeId]);
}
return $this;
}
@@ -222,9 +259,9 @@ class BrowseBrick extends PortalBrick
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*
* @throws \DOMFormatException
*/
public function LoadFromXml(DesignElement $oMDElement)
@@ -232,11 +269,13 @@ class BrowseBrick extends PortalBrick
parent::LoadFromXml($oMDElement);
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
case 'levels':
/** @var \Combodo\iTop\DesignElement $oLevelNode */
foreach ($oBrickSubNode->childNodes as $oLevelNode)
{
if ($oLevelNode->nodeName === 'level')
@@ -246,16 +285,19 @@ class BrowseBrick extends PortalBrick
}
break;
case 'browse_modes':
/** @var \Combodo\iTop\DesignElement $oBrowseModeNode */
foreach ($oBrickSubNode->childNodes as $oBrowseModeNode)
{
switch ($oBrowseModeNode->nodeName)
{
case 'availables':
/** @var \Combodo\iTop\DesignElement $oModeNode */
foreach ($oBrowseModeNode->childNodes as $oModeNode)
{
if (!$oModeNode->hasAttribute('id'))
{
throw new DOMFormatException('BrowseBrick : Browse mode must have a unique ID attribute', null, null, $oModeNode);
throw new DOMFormatException('BrowseBrick : Browse mode must have a unique ID attribute', null,
null, $oModeNode);
}
$sModeId = $oModeNode->getAttribute('id');
@@ -269,7 +311,7 @@ class BrowseBrick extends PortalBrick
}
else
{
$sTemplatePath = 'itop-portal-base/portal/templates/bricks/browse/mode_' . $sModeId . '.html.twig';
$sTemplatePath = 'itop-portal-base/portal/templates/bricks/browse/mode_'.$sModeId.'.html.twig';
}
$aModeData['template'] = $sTemplatePath;
@@ -290,10 +332,11 @@ class BrowseBrick extends PortalBrick
{
throw new DOMFormatException('BrowseBrick : Must have at least one browse mode', null, null, $oMDElement);
}
// Checking that default browse mode in among the availables
// Checking that default browse mode in among the available
if (!in_array($this->sDefaultBrowseMode, array_keys($this->aAvailablesBrowseModes)))
{
throw new DOMFormatException('BrowseBrick : Default browse mode "' . $this->sDefaultBrowseMode . '" must be one of the available browse modes (' . implode(', ', $this->aAvailablesBrowseModes) . ')', null, null, $oMDElement);
throw new DOMFormatException('BrowseBrick : Default browse mode "'.$this->sDefaultBrowseMode.'" must be one of the available browse modes ('.implode(', ',
$this->aAvailablesBrowseModes).')', null, null, $oMDElement);
}
// Checking that the brick has at least a level
if (count($this->GetLevels()) === 0)
@@ -305,12 +348,12 @@ class BrowseBrick extends PortalBrick
}
/**
* Parses the ModuleDesignElement to recursivly load levels
* Parses the ModuleDesignElement to recursively load levels
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
*
* @return array
*
*
* @throws \DOMFormatException
*/
protected function LoadLevelFromXml(DesignElement $oMDElement)
@@ -318,12 +361,12 @@ class BrowseBrick extends PortalBrick
$aLevel = array(
'parent_att' => null,
'tooltip_att' => null,
'description_att' => null,
'image_att' => null,
'description_att' => null,
'image_att' => null,
'title' => null,
'name_att' => static::DEFAULT_LEVEL_NAME_ATT,
'fields' => array(),
'actions' => array('default' => array('type' => static::DEFAULT_ACTION, 'rules' => array()))
'actions' => array('default' => array('type' => static::DEFAULT_ACTION, 'rules' => array())),
);
// Getting level ID
@@ -333,9 +376,11 @@ class BrowseBrick extends PortalBrick
}
else
{
throw new DOMFormatException('BrowseBrick : level tag without "id" attribute. It must have one and it must not be empty', null, null, $oMDElement);
throw new DOMFormatException('BrowseBrick : level tag without "id" attribute. It must have one and it must not be empty', null,
null, $oMDElement);
}
// Getting level properties
/** @var \Combodo\iTop\DesignElement $oLevelPropertyNode */
foreach ($oMDElement->childNodes as $oLevelPropertyNode)
{
switch ($oLevelPropertyNode->nodeName)
@@ -344,17 +389,19 @@ class BrowseBrick extends PortalBrick
$sClass = $oLevelPropertyNode->GetText();
if ($sClass === '')
{
throw new DOMFormatException('BrowseBrick : class tag is empty. Must contain Classname', null, null, $oLevelPropertyNode);
throw new DOMFormatException('BrowseBrick : class tag is empty. Must contain Classname', null, null,
$oLevelPropertyNode);
}
$aLevel['oql'] = 'SELECT ' . $sClass;
$aLevel['oql'] = 'SELECT '.$sClass;
break;
case 'oql':
$sOql = $oLevelPropertyNode->GetText();
if ($sOql === '')
{
throw new DOMFormatException('BrowseBrick : oql tag is empty. Must contain OQL statement', null, null, $oLevelPropertyNode);
throw new DOMFormatException('BrowseBrick : oql tag is empty. Must contain OQL statement', null, null,
$oLevelPropertyNode);
}
$aLevel['oql'] = $sOql;
@@ -362,8 +409,8 @@ class BrowseBrick extends PortalBrick
case 'parent_att':
case 'tooltip_att':
case 'description_att':
case 'image_att':
case 'description_att':
case 'image_att':
case 'title':
$aLevel[$oLevelPropertyNode->nodeName] = $oLevelPropertyNode->GetText(null);
break;
@@ -378,6 +425,7 @@ class BrowseBrick extends PortalBrick
if ($oLevelPropertyNode->hasChildNodes())
{
$aLevel[$sTagName] = array();
/** @var \Combodo\iTop\DesignElement $oFieldNode */
foreach ($oLevelPropertyNode->childNodes as $oFieldNode)
{
if ($oFieldNode->hasAttribute('id') && $oFieldNode->getAttribute('id') !== '')
@@ -386,7 +434,8 @@ class BrowseBrick extends PortalBrick
}
else
{
throw new DOMFormatException('BrowseBrick : ' . $sTagName . '/* tag must have an "id" attribute and it must not be empty', null, null, $oFieldNode);
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/* tag must have an "id" attribute and it must not be empty',
null, null, $oFieldNode);
}
$oFieldSubNode = $oFieldNode->GetOptionalElement('hidden');
@@ -404,13 +453,14 @@ class BrowseBrick extends PortalBrick
if ($oLevelPropertyNode->hasChildNodes())
{
$aLevel[$sTagName] = array();
/** @var \Combodo\iTop\DesignElement $oActionNode */
foreach ($oLevelPropertyNode->childNodes as $oActionNode)
{
if ($oActionNode->hasAttribute('id') && $oActionNode->getAttribute('id') !== '')
{
$aTmpAction = array(
'type' => null,
'rules' => array()
'rules' => array(),
);
// Action type
@@ -422,14 +472,14 @@ class BrowseBrick extends PortalBrick
{
$aTmpAction['factory'] = array(
'type' => static::ENUM_FACTORY_TYPE_METHOD,
'value' => $oActionNode->GetOptionalElement('factory_method')->GetText()
'value' => $oActionNode->GetOptionalElement('factory_method')->GetText(),
);
}
else
{
$aTmpAction['factory'] = array(
'type' => static::ENUM_FACTORY_TYPE_CLASS,
'value' => $oActionNode->GetUniqueElement('class')->GetText()
'value' => $oActionNode->GetUniqueElement('class')->GetText(),
);
}
}
@@ -446,21 +496,23 @@ class BrowseBrick extends PortalBrick
$aTmpAction['icon_class'] = $oActionIconClassNode->GetText();
}
// Action opening target
$oActionOpeningTargetNode = $oActionNode->GetOptionalElement('opening_target');
if($oActionOpeningTargetNode !== null)
{
$aTmpAction['opening_target'] = $oActionOpeningTargetNode->GetText(static::DEFAULT_ACTION_OPENING_TARGET);
}
else
{
$aTmpAction['opening_target'] = static::DEFAULT_ACTION_OPENING_TARGET;
}
// - Checking that opening target is among authorized modes
if(!in_array($aTmpAction['opening_target'], static::$aOpeningTargets))
{
throw new DOMFormatException('BrowseBrick : ' . $sTagName . '/action/opening_target has a wrong value. "'.$aTmpAction['opening_target'].'" given, '.implode('|', static::$aOpeningTargets).' expected.', null, null, $oActionOpeningTargetNode);
}
$oActionOpeningTargetNode = $oActionNode->GetOptionalElement('opening_target');
if ($oActionOpeningTargetNode !== null)
{
$aTmpAction['opening_target'] = $oActionOpeningTargetNode->GetText(static::DEFAULT_ACTION_OPENING_TARGET);
}
else
{
$aTmpAction['opening_target'] = static::DEFAULT_ACTION_OPENING_TARGET;
}
// - Checking that opening target is among authorized modes
if (!in_array($aTmpAction['opening_target'], static::$aOpeningTargets))
{
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/action/opening_target has a wrong value. "'.$aTmpAction['opening_target'].'" given, '.implode('|',
static::$aOpeningTargets).' expected.', null, null, $oActionOpeningTargetNode);
}
// Action rules
/** @var \Combodo\iTop\DesignElement $oRuleNode */
foreach ($oActionNode->GetNodes('./rules/rule') as $oRuleNode)
{
if ($oRuleNode->hasAttribute('id') && $oRuleNode->getAttribute('id') !== '')
@@ -469,7 +521,8 @@ class BrowseBrick extends PortalBrick
}
else
{
throw new DOMFormatException('BrowseBrick : ' . $sTagName . '/rules/rule tag must have an "id" attribute and it must not be empty', null, null, $oRuleNode);
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/rules/rule tag must have an "id" attribute and it must not be empty',
null, null, $oRuleNode);
}
}
@@ -477,7 +530,8 @@ class BrowseBrick extends PortalBrick
}
else
{
throw new DOMFormatException('BrowseBrick : ' . $sTagName . '/* tag must have an "id" attribute and it must not be empty', null, null, $oActionNode);
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/* tag must have an "id" attribute and it must not be empty',
null, null, $oActionNode);
}
}
}
@@ -495,13 +549,13 @@ class BrowseBrick extends PortalBrick
break;
}
}
// Checking if level has an oql
if (!isset($aLevel['oql']) || $aLevel['oql'] === '')
{
throw new DOMFormatException('BrowseBrick : must have a valid <class|oql> tag', null, null, $oMDElement);
}
return $aLevel;
}

View File

@@ -27,18 +27,27 @@ use Combodo\iTop\DesignElement;
/**
* Description of CreateBrick
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*
* @package Combodo\iTop\Portal\Brick
* @since 2.4.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class CreateBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-plus';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-plus fa-2x';
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/create/modal.html.twig';
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/create/modal.html.twig';
/** @var string DEFAULT_CLASS */
const DEFAULT_CLASS = '';
static $sRouteName = 'p_create_brick';
// Overloaded variables
public static $sRouteName = 'p_create_brick';
/** @var string $sClass */
protected $sClass;
/** @var array $aRules */
protected $aRules;
/**
@@ -62,16 +71,17 @@ class CreateBrick extends PortalBrick
return $this->sClass;
}
/**
* Sets the class of the brick
*
* @param string $sClass
*
* @return \Combodo\iTop\Portal\Brick\CreateBrick
*/
/**
* Sets the class of the brick
*
* @param string $sClass
*
* @return \Combodo\iTop\Portal\Brick\CreateBrick
*/
public function SetClass($sClass)
{
$this->sClass = $sClass;
return $this;
}
@@ -89,30 +99,32 @@ class CreateBrick extends PortalBrick
* Sets the rules of the brick
*
* @param array $aRules
*
* @return \Combodo\iTop\Portal\Brick\CreateBrick
*
* @return \Combodo\iTop\Portal\Brick\CreateBrick
*/
public function SetRules($aRules)
{
$this->aRules = $aRules;
return $this;
}
/**
* Load the brick's data from the xml passed as a ModuleDesignElement.
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\CreateBrick
*
* @throws \DOMFormatException
*/
/**
* Load the brick's data from the xml passed as a ModuleDesignElement.
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\CreateBrick
*
* @throws \DOMFormatException
*/
public function LoadFromXml(DesignElement $oMDElement)
{
parent::LoadFromXml($oMDElement);
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
@@ -122,6 +134,7 @@ class CreateBrick extends PortalBrick
break;
case 'rules':
/** @var \Combodo\iTop\DesignElement $oRuleNode */
foreach ($oBrickSubNode->childNodes as $oRuleNode)
{
if ($oRuleNode->hasAttribute('id') && $oRuleNode->getAttribute('id') !== '')
@@ -130,7 +143,8 @@ class CreateBrick extends PortalBrick
}
else
{
throw new DOMFormatException('CreateBrick: /rules/rule tag must have an "id" attribute and it must not be empty', null, null, $oRuleNode);
throw new DOMFormatException('CreateBrick: /rules/rule tag must have an "id" attribute and it must not be empty',
null, null, $oRuleNode);
}
}
break;

View File

@@ -27,28 +27,44 @@ use Combodo\iTop\DesignElement;
/**
* Description of FilterBrick
*
*
* @package Combodo\iTop\Portal\Brick
* @since 2.4.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class FilterBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/filter/tile.html.twig';
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-search';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-search fa-2x';
/** @var string DEFAULT_TARGET_BRICK_CLASS */
const DEFAULT_TARGET_BRICK_CLASS = 'Combodo\\iTop\\Portal\\Brick\\BrowseBrick';
/** @var string DEFAULT_SEARCH_PLACEHOLDER_VALUE */
const DEFAULT_SEARCH_PLACEHOLDER_VALUE = 'Brick:Portal:Filter:SearchInput:Placeholder';
/** @var string DEFAULT_SEARCH_SUBMIT_LABEL */
const DEFAULT_SEARCH_SUBMIT_LABEL = 'Brick:Portal:Filter:SearchInput:Submit';
/** @var string DEFAULT_SEARCH_SUBMIT_CLASS */
const DEFAULT_SEARCH_SUBMIT_CLASS = '';
/** @var string $sTargetBrickId */
protected $sTargetBrickId;
/** @var string $sTargetBrickClass */
protected $sTargetBrickClass;
/** @var string $sTargetBrickTab */
protected $sTargetBrickTab;
/** @var string $sSearchPlaceholderValue */
protected $sSearchPlaceholderValue;
/** @var string $sSearchSubmitLabel */
protected $sSearchSubmitLabel;
/** @var string $sSearchSubmitClass */
protected $sSearchSubmitClass;
/**
* FilterBrick constructor.
*/
public function __construct()
{
parent::__construct();
@@ -59,65 +75,111 @@ class FilterBrick extends PortalBrick
$this->sSearchSubmitClass = static::DEFAULT_SEARCH_SUBMIT_CLASS;
}
/**
* @return string
*/
public function GetTargetBrickId()
{
return $this->sTargetBrickId;
}
/**
* @return string
*/
public function GetTargetBrickClass()
{
return $this->sTargetBrickClass;
}
/**
* @return string
*/
public function GetTargetBrickTab()
{
return $this->sTargetBrickTab;
}
/**
* @return string
*/
public function GetSearchPlaceholderValue()
{
return $this->sSearchPlaceholderValue;
}
/**
* @return string
*/
public function GetSearchSubmitLabel()
{
return $this->sSearchSubmitLabel;
}
/**
* @return string
*/
public function GetSearchSubmitClass()
{
return $this->sSearchSubmitClass;
}
/**
* @param string $sTargetBrickId
*
* @return $this
*/
public function SetTargetBrickId($sTargetBrickId)
{
$this->sTargetBrickId = $sTargetBrickId;
return $this;
}
/**
* @param string $sTargetBrickClass
*/
public function SetTargetBrickClass($sTargetBrickClass)
{
$this->sTargetBrickClass = $sTargetBrickClass;
}
/**
* @param string $sTargetBrickTab
*
* @return $this
*/
public function SetTargetBrickTab($sTargetBrickTab)
{
$this->sTargetBrickTab = $sTargetBrickTab;
return $this;
}
/**
* @param string $sSearchPlaceholderValue
*
* @return $this
*/
public function SetSearchPlaceholderValue($sSearchPlaceholderValue)
{
$this->sSearchPlaceholderValue = $sSearchPlaceholderValue;
return $this;
}
/**
* @param string $sSearchSubmitLabel
*
* @return $this
*/
public function SetSearchSubmitLabel($sSearchSubmitLabel)
{
$this->sSearchSubmitLabel = $sSearchSubmitLabel;
return $this;
}
/**
* @param string $sSearchSubmitClass
*
* @return $this
*/
public function SetSearchSubmitClass($sSearchSubmitClass)
{
$this->sSearchSubmitClass = $sSearchSubmitClass;
@@ -139,11 +201,13 @@ class FilterBrick extends PortalBrick
parent::LoadFromXml($oMDElement);
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
case 'target_brick':
/** @var \Combodo\iTop\DesignElement $oTargetBrickNode */
foreach ($oBrickSubNode->childNodes as $oTargetBrickNode)
{
switch ($oTargetBrickNode->nodeName)

View File

@@ -30,149 +30,188 @@ use Combodo\iTop\DesignElement;
class ManageBrick extends PortalBrick
{
/** @var string ENUM_ACTION_VIEW */
const ENUM_ACTION_VIEW = 'view';
/** @var string ENUM_ACTION_EDIT */
const ENUM_ACTION_EDIT = 'edit';
const ENUM_TILE_MODE_TEXT = 'text';
const ENUM_TILE_MODE_BADGE = 'badge';
const ENUM_TILE_MODE_PIE = 'pie-chart';
const ENUM_TILE_MODE_BAR = 'bar-chart';
const ENUM_TILE_MODE_TOP = 'top-list';
/** @var string ENUM_TILE_MODE_TEXT */
const ENUM_TILE_MODE_TEXT = 'text';
/** @var string ENUM_TILE_MODE_BADGE */
const ENUM_TILE_MODE_BADGE = 'badge';
/** @var string ENUM_TILE_MODE_PIE */
const ENUM_TILE_MODE_PIE = 'pie-chart';
/** @var string ENUM_TILE_MODE_BAR */
const ENUM_TILE_MODE_BAR = 'bar-chart';
/** @var string ENUM_TILE_MODE_TOP */
const ENUM_TILE_MODE_TOP = 'top-list';
const ENUM_DISPLAY_MODE_LIST = 'list';
const ENUM_DISPLAY_MODE_PIE = 'pie-chart';
const ENUM_DISPLAY_MODE_BAR = 'bar-chart';
/** @var string ENUM_DISPLAY_MODE_LIST */
const ENUM_DISPLAY_MODE_LIST = 'list';
/** @var string ENUM_DISPLAY_MODE_PIE */
const ENUM_DISPLAY_MODE_PIE = 'pie-chart';
/** @var string ENUM_DISPLAY_MODE_BAR */
const ENUM_DISPLAY_MODE_BAR = 'bar-chart';
/** @var string ENUM_PAGE_TEMPLATE_PATH_TABLE */
const ENUM_PAGE_TEMPLATE_PATH_TABLE = 'itop-portal-base/portal/templates/bricks/manage/layout-table.html.twig';
const ENUM_PAGE_TEMPLATE_PATH_CHART = 'itop-portal-base/portal/templates/bricks/manage/layout-chart.html.twig';
/** @var string ENUM_PAGE_TEMPLATE_PATH_CHART */
const ENUM_PAGE_TEMPLATE_PATH_CHART = 'itop-portal-base/portal/templates/bricks/manage/layout-chart.html.twig';
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-pencil-square';
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-pencil-square';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-pencil-square fa-2x';
const DEFAULT_PAGE_TEMPLATE_PATH = self::ENUM_PAGE_TEMPLATE_PATH_TABLE;
const DEFAULT_OQL = '';
const DEFAULT_OPENING_MODE = self::ENUM_ACTION_EDIT;
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_LAZY;
const DEFAULT_LIST_LENGTH = 20;
const DEFAULT_ZLIST_FIELDS = 'list';
const DEFAULT_SHOW_TAB_COUNTS = false;
const DEFAULT_DISPLAY_MODE = self::ENUM_DISPLAY_MODE_LIST;
const DEFAULT_TILE_MODE = self::ENUM_TILE_MODE_TEXT;
const DEFAULT_GROUP_LIMIT = 0;
const DEFAULT_GROUP_SHOW_OTHERS = true;
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/manage/tile-default.html.twig';
const DEFAULT_TILE_CONTROLLER_ACTION = 'Combodo\\iTop\\Portal\\Controller\\ManageBrickController::TileAction';
/** @var string DEFAULT_OQL */
const DEFAULT_OQL = '';
/** @var string DEFAULT_OPENING_MODE */
const DEFAULT_OPENING_MODE = self::ENUM_ACTION_EDIT;
/** @var int DEFAULT_LIST_LENGTH */
const DEFAULT_LIST_LENGTH = 20;
/** @var string DEFAULT_ZLIST_FIELDS */
const DEFAULT_ZLIST_FIELDS = 'list';
/** @var bool DEFAULT_SHOW_TAB_COUNTS */
const DEFAULT_SHOW_TAB_COUNTS = false;
/** @var string DEFAULT_DISPLAY_MODE */
const DEFAULT_DISPLAY_MODE = self::ENUM_DISPLAY_MODE_LIST;
/** @var string DEFAULT_TILE_MODE */
const DEFAULT_TILE_MODE = self::ENUM_TILE_MODE_TEXT;
/** @var int DEFAULT_GROUP_LIMIT */
const DEFAULT_GROUP_LIMIT = 0;
/** @var bool DEFAULT_GROUP_SHOW_OTHERS */
const DEFAULT_GROUP_SHOW_OTHERS = true;
/** @var array $aDisplayModes */
static $aDisplayModes = array(
self::ENUM_DISPLAY_MODE_LIST,
self::ENUM_DISPLAY_MODE_PIE,
self::ENUM_DISPLAY_MODE_BAR,
);
static $aTileModes = array(
self::ENUM_TILE_MODE_TEXT,
self::ENUM_TILE_MODE_BADGE,
self::ENUM_TILE_MODE_PIE,
self::ENUM_TILE_MODE_BAR,
self::ENUM_TILE_MODE_TOP,
);
static $aPresentationData = array(
self::ENUM_TILE_MODE_BADGE => array(
'decorationCssClass' => 'fa fa-id-card-o fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-badge.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_TABLE,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_LIST,
'need_details' => true,
),
self::ENUM_TILE_MODE_TOP => array(
'decorationCssClass' => 'fa fa-signal fa-rotate-270 fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-top-list.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_TABLE,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_LIST,
'need_details' => true,
),
self::ENUM_TILE_MODE_PIE => array(
'decorationCssClass' => 'fa fa-pie-chart fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-chart.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_CHART,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_PIE,
'need_details' => false,
),
self::ENUM_TILE_MODE_BAR => array(
'decorationCssClass' => 'fa fa-bar-chart fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-chart.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_CHART,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_BAR,
'need_details' => false,
),
self::ENUM_TILE_MODE_TEXT => array(
'decorationCssClass' => 'fa fa-pencil-square fa-2x',
'tileTemplate' => self::DEFAULT_TILE_TEMPLATE_PATH,
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_TABLE,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_LIST,
'need_details' => true,
),
);
self::ENUM_DISPLAY_MODE_LIST,
self::ENUM_DISPLAY_MODE_PIE,
self::ENUM_DISPLAY_MODE_BAR,
);
/** @var array $aTileModes */
public static $aTileModes = array(
self::ENUM_TILE_MODE_TEXT,
self::ENUM_TILE_MODE_BADGE,
self::ENUM_TILE_MODE_PIE,
self::ENUM_TILE_MODE_BAR,
self::ENUM_TILE_MODE_TOP,
);
/** @var array $aPresentationData */
public static $aPresentationData = array(
self::ENUM_TILE_MODE_BADGE => array(
'decorationCssClass' => 'fa fa-id-card-o fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-badge.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_TABLE,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_LIST,
'need_details' => true,
),
self::ENUM_TILE_MODE_TOP => array(
'decorationCssClass' => 'fa fa-signal fa-rotate-270 fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-top-list.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_TABLE,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_LIST,
'need_details' => true,
),
self::ENUM_TILE_MODE_PIE => array(
'decorationCssClass' => 'fa fa-pie-chart fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-chart.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_CHART,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_PIE,
'need_details' => false,
),
self::ENUM_TILE_MODE_BAR => array(
'decorationCssClass' => 'fa fa-bar-chart fa-2x',
'tileTemplate' => 'itop-portal-base/portal/templates/bricks/manage/tile-chart.html.twig',
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_CHART,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_BAR,
'need_details' => false,
),
self::ENUM_TILE_MODE_TEXT => array(
'decorationCssClass' => 'fa fa-pencil-square fa-2x',
'tileTemplate' => self::DEFAULT_TILE_TEMPLATE_PATH,
'layoutTemplate' => self::ENUM_PAGE_TEMPLATE_PATH_TABLE,
'layoutDisplayMode' => self::ENUM_DISPLAY_MODE_LIST,
'need_details' => true,
),
);
static $sRouteName = 'p_manage_brick';
// Overloaded variables
public static $sRouteName = 'p_manage_brick';
/** @var string $sOql */
protected $sOql;
/** @var string $sOpeningMode */
protected $sOpeningMode;
/** @var array $aGrouping */
protected $aGrouping;
/** @var array $aFields */
protected $aFields;
/** @var array $aExportFields */
protected $aExportFields;
/** @var bool $bShowTabCounts */
protected $bShowTabCounts;
protected $aAvailableDisplayModes = array();
protected $sDefaultDisplayMode;
protected $sTileMode;
/** @var array $aAvailableDisplayModes */
protected $aAvailableDisplayModes = array();
/** @var string $sDefaultDisplayMode */
protected $sDefaultDisplayMode;
/** @var string $sTileMode */
protected $sTileMode;
/** @var int $iGroupLimit */
protected $iGroupLimit;
/** @var bool $bGroupShowOthers */
protected $bGroupShowOthers;
/**
* Returns true if the $sDisplayMode need objects details for rendering.
*
* @param string $sDisplayMode
*
* @return bool
*/
/**
* Returns true if the $sDisplayMode need objects details for rendering.
*
* @param string $sDisplayMode
*
* @return bool
*/
static public function AreDetailsNeededForDisplayMode($sDisplayMode)
{
$bNeedDetails = false;
foreach(static::$aPresentationData as $aData)
{
if($aData['layoutDisplayMode'] === $sDisplayMode)
{
$bNeedDetails = $aData['need_details'];
break;
}
}
{
$bNeedDetails = false;
foreach (static::$aPresentationData as $aData)
{
if ($aData['layoutDisplayMode'] === $sDisplayMode)
{
$bNeedDetails = $aData['need_details'];
break;
}
}
return $bNeedDetails;
}
return $bNeedDetails;
}
/**
* Returns the page template path for the $sDisplayMode
*
* @param string $sDisplayMode
*
* @return string
*/
static public function GetPageTemplateFromDisplayMode($sDisplayMode)
{
$sTemplate = static::DEFAULT_PAGE_TEMPLATE_PATH;
foreach(static::$aPresentationData as $aData)
{
if($aData['layoutDisplayMode'] === $sDisplayMode)
{
$sTemplate = $aData['layoutTemplate'];
break;
}
}
/**
* Returns the page template path for the $sDisplayMode
*
* @param string $sDisplayMode
*
* @return string
*/
static public function GetPageTemplateFromDisplayMode($sDisplayMode)
{
$sTemplate = static::DEFAULT_PAGE_TEMPLATE_PATH;
foreach (static::$aPresentationData as $aData)
{
if ($aData['layoutDisplayMode'] === $sDisplayMode)
{
$sTemplate = $aData['layoutTemplate'];
break;
}
}
return $sTemplate;
}
return $sTemplate;
}
public function __construct()
/**
* ManageBrick constructor.
*/
public function __construct()
{
parent::__construct();
@@ -182,7 +221,7 @@ class ManageBrick extends PortalBrick
$this->aFields = array();
$this->aExportFields = array();
$this->bShowTabCounts = static::DEFAULT_SHOW_TAB_COUNTS;
$this->sDefaultDisplayMode = static::DEFAULT_DISPLAY_MODE;
$this->sDefaultDisplayMode = static::DEFAULT_DISPLAY_MODE;
$this->sTileMode = static::DEFAULT_TILE_MODE;
$this->iGroupLimit = static::DEFAULT_GROUP_LIMIT;
@@ -252,33 +291,33 @@ class ManageBrick extends PortalBrick
return $this->bShowTabCounts;
}
/**
* Returns the brick default display mode
*
* @return string
*/
public function GetDefaultDisplayMode()
{
return $this->sDefaultDisplayMode;
}
/**
* Sets the default display mode of the brick
*
* @param string $sDefaultDisplayMode
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetDefaultDisplayMode($sDefaultDisplayMode)
{
$this->sDefaultDisplayMode = $sDefaultDisplayMode;
return $this;
}
/**
* Returns the brick default display mode
*
* @return string
*/
public function GetDefaultDisplayMode()
{
return $this->sDefaultDisplayMode;
}
/**
* Returns the tile mode (display)
*
* Sets the default display mode of the brick
*
* @param string $sDefaultDisplayMode
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetDefaultDisplayMode($sDefaultDisplayMode)
{
$this->sDefaultDisplayMode = $sDefaultDisplayMode;
return $this;
}
/**
* Returns the tile mode (display)
*
* @return string
*/
public function GetTileMode()
@@ -287,11 +326,11 @@ class ManageBrick extends PortalBrick
}
/**
* Sets the tile mode (display)
*
* Sets the tile mode (display)
*
* @param string $sTileMode
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetTileMode($sTileMode)
{
@@ -349,8 +388,8 @@ class ManageBrick extends PortalBrick
* Sets the brick's objects opening mode
*
* @param string $sOpeningMode
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetOpeningMode($sOpeningMode)
{
@@ -363,8 +402,8 @@ class ManageBrick extends PortalBrick
* Sets the grouping of the brick
*
* @param array $aGrouping
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetGrouping($aGrouping)
{
@@ -377,8 +416,8 @@ class ManageBrick extends PortalBrick
* Sets the fields of the brick
*
* @param array $aFields
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetFields($aFields)
{
@@ -391,8 +430,8 @@ class ManageBrick extends PortalBrick
* Sets if the brick should display objects count on tab
*
* @param bool $bShowTabCounts
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function SetShowTabCounts($bShowTabCounts)
{
@@ -407,9 +446,9 @@ class ManageBrick extends PortalBrick
* Grouping "tabs" must be of form array("attribute" => value)
*
* @param string $sName (Must be "tabs" or -Not implemented yet, implicit grouping on y axis-)
* @param array $aGrouping
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
* @param array $aGrouping
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function AddGrouping($sName, $aGrouping)
{
@@ -430,8 +469,8 @@ class ManageBrick extends PortalBrick
* Removes a grouping by its name
*
* @param string $sName
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function RemoveGrouping($sName)
{
@@ -447,8 +486,8 @@ class ManageBrick extends PortalBrick
* Adds a field to display from its attribute_code.
*
* @param string $sAttCode
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function AddField($sAttCode)
{
@@ -464,8 +503,8 @@ class ManageBrick extends PortalBrick
* Removes a field
*
* @param string $sAttCode
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function RemoveField($sAttCode)
{
@@ -537,44 +576,46 @@ class ManageBrick extends PortalBrick
return (isset($this->aGrouping['areas'])) ? $this->aGrouping['areas'] : false;
}
/**
* @param string $sModeId
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @throws \Exception
*/
/**
* @param string $sModeId
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @throws \Exception
*/
public function AddAvailableDisplayMode($sModeId)
{
if(!in_array($sModeId, static::$aDisplayModes))
{
throw new Exception('ManageBrick: Display mode "' . $sModeId. '" must be one of the allowed display modes (' . implode(', ', static::$aDisplayModes) . ')');
}
if (!in_array($sModeId, static::$aDisplayModes))
{
throw new Exception('ManageBrick: Display mode "'.$sModeId.'" must be one of the allowed display modes ('.implode(', ',
static::$aDisplayModes).')');
}
$this->aAvailableDisplayModes[] = $sModeId;
return $this;
}
/**
* Removes $sModeId from the list of availables display modes
*
* @param string $sModeId
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function RemoveAvailableDisplayMode($sModeId)
{
if (isset($this->aAvailableDisplayModes[$sModeId]))
{
unset($this->aAvailableDisplayModes[$sModeId]);
}
return $this;
}
/**
* Removes $sModeId from the list of availables display modes
*
* @param string $sModeId
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*/
public function RemoveAvailableDisplayMode($sModeId)
{
if (isset($this->aAvailableDisplayModes[$sModeId]))
{
unset($this->aAvailableDisplayModes[$sModeId]);
}
return $this;
}
/**
* Returns the available display modes for the brick (page, not tile)
*
* Returns the available display modes for the brick (page, not tile)
*
* @return string[]
*/
public function GetAvailablesDisplayModes()
@@ -619,24 +660,25 @@ class ManageBrick extends PortalBrick
return $this->IsGroupingByDistinctValues('areas');
}
/**
* Load the brick's data from the xml passed as a ModuleDesignElement.
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @throws \Exception
* @throws \DOMFormatException
* @throws \OQLException
*/
/**
* Load the brick's data from the xml passed as a ModuleDesignElement.
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\ManageBrick
*
* @throws \Exception
* @throws \DOMFormatException
* @throws \OQLException
*/
public function LoadFromXml(DesignElement $oMDElement)
{
parent::LoadFromXml($oMDElement);
$bUseListFieldsForExport = false;
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
@@ -675,11 +717,13 @@ class ManageBrick extends PortalBrick
break;
case 'display_modes':
/** @var \Combodo\iTop\DesignElement $oDisplayNode */
foreach ($oBrickSubNode->GetNodes('./*') as $oDisplayNode)
{
switch ($oDisplayNode->nodeName)
{
case 'availables';
/** @var \Combodo\iTop\DesignElement $oModeNode */
foreach ($oDisplayNode->childNodes as $oModeNode)
{
if (!$oModeNode->hasAttribute('id'))
@@ -691,7 +735,8 @@ class ManageBrick extends PortalBrick
$sModeId = $oModeNode->getAttribute('id');
if (!in_array($sModeId, static::$aDisplayModes))
{
throw new DOMFormatException('ManageBrick: Display mode has an invalid value. Expected '.implode('/', static::$aDisplayModes.', "'.$sModeId.'" given.'),
throw new DOMFormatException('ManageBrick: Display mode has an invalid value. Expected '.implode('/',
static::$aDisplayModes.', "'.$sModeId.'" given.'),
null, null, $oModeNode);
}
@@ -699,12 +744,12 @@ class ManageBrick extends PortalBrick
}
break;
case 'default':
$this->SetDefaultDisplayMode($oDisplayNode->GetText(static::DEFAULT_DISPLAY_MODE));
break;
case 'default':
$this->SetDefaultDisplayMode($oDisplayNode->GetText(static::DEFAULT_DISPLAY_MODE));
break;
case 'tile';
$this->SetTileMode($oDisplayNode->GetText(static::DEFAULT_TILE_MODE));
$this->SetTileMode($oDisplayNode->GetText(static::DEFAULT_TILE_MODE));
$aTileParametersForType = $this->GetPresentationDataForTileMode($this->sTileMode);
$this->SetTileTemplatePath($aTileParametersForType['tileTemplate']);
@@ -715,6 +760,7 @@ class ManageBrick extends PortalBrick
break;
case 'fields':
/** @var \Combodo\iTop\DesignElement $oFieldNode */
foreach ($oBrickSubNode->GetNodes('./field') as $oFieldNode)
{
if (!$oFieldNode->hasAttribute('id'))
@@ -727,11 +773,13 @@ class ManageBrick extends PortalBrick
break;
case 'export':
/** @var \Combodo\iTop\DesignElement $oExportNode */
foreach ($oBrickSubNode->GetNodes('./*') as $oExportNode)
{
switch ($oExportNode->nodeName)
{
case 'fields':
/** @var \Combodo\iTop\DesignElement $oFieldNode */
foreach ($oExportNode->GetNodes('./field') as $oFieldNode)
{
if (!$oFieldNode->hasAttribute('id'))
@@ -754,6 +802,7 @@ class ManageBrick extends PortalBrick
case 'grouping':
// Tabs grouping
/** @var \Combodo\iTop\DesignElement $oGroupingNode */
foreach ($oBrickSubNode->GetNodes('./tabs/*') as $oGroupingNode)
{
switch ($oGroupingNode->nodeName)
@@ -781,6 +830,7 @@ class ManageBrick extends PortalBrick
break;
case 'groups':
$aGroups = array();
/** @var \Combodo\iTop\DesignElement $oGroupNode */
foreach ($oGroupingNode->GetNodes('./group') as $oGroupNode)
{
if (!$oGroupNode->hasAttribute('id'))
@@ -792,6 +842,7 @@ class ManageBrick extends PortalBrick
$aGroup = array();
$aGroup['id'] = $sGroupId; // We don't put the group id as the $aGroups key because the array will be sorted later in AddGrouping, which replace array keys by integer ordered keys
/** @var \Combodo\iTop\DesignElement $oGroupProperty */
foreach ($oGroupNode->childNodes as $oGroupProperty)
{
switch ($oGroupProperty->nodeName)
@@ -833,21 +884,23 @@ class ManageBrick extends PortalBrick
throw new DOMFormatException('ManageBrick: must have a valid <class|oql> tag', null, null, $oMDElement);
}
// Checking that the brick has at least a display mode
if (count($this->GetAvailablesDisplayModes()) === 0)
{
$this->AddAvailableDisplayMode(static::DEFAULT_DISPLAY_MODE);
}
// Checking that default display mode in among the availables
if (!in_array($this->sDefaultDisplayMode, $this->aAvailableDisplayModes))
{
throw new DOMFormatException('ManageBrick: Default display mode "' . $this->sDefaultDisplayMode . '" must be one of the available display modes (' . implode(', ', $this->aAvailableDisplayModes) . ')', null, null, $oMDElement);
}
// Checking that tile mode in among the availables
if (!in_array($this->sTileMode, static::$aTileModes))
{
throw new DOMFormatException('ManageBrick: Tile mode "' . $this->sTileMode. '" must be one of the allowed tile modes (' . implode(', ', static::$aTileModes) . ')', null, null, $oMDElement);
}
// Checking that the brick has at least a display mode
if (count($this->GetAvailablesDisplayModes()) === 0)
{
$this->AddAvailableDisplayMode(static::DEFAULT_DISPLAY_MODE);
}
// Checking that default display mode in among the availables
if (!in_array($this->sDefaultDisplayMode, $this->aAvailableDisplayModes))
{
throw new DOMFormatException('ManageBrick: Default display mode "'.$this->sDefaultDisplayMode.'" must be one of the available display modes ('.implode(', ',
$this->aAvailableDisplayModes).')', null, null, $oMDElement);
}
// Checking that tile mode in among the availables
if (!in_array($this->sTileMode, static::$aTileModes))
{
throw new DOMFormatException('ManageBrick: Tile mode "'.$this->sTileMode.'" must be one of the allowed tile modes ('.implode(', ',
static::$aTileModes).')', null, null, $oMDElement);
}
// Checking if specified fields, if not we put those from the details zlist
if (empty($this->aFields))
@@ -871,7 +924,7 @@ class ManageBrick extends PortalBrick
$sDecorationClassNavigationMenu = $this->GetDecorationClassNavigationMenu();
if (empty($sDecorationClassNavigationMenu) && isset(static::$aPresentationData[$this->sTileMode]))
{
/** @var string $sDecorationClassNavigationMenu */
/** @var string $sDecorationClassNavigationMenu */
$sDecorationClassNavigationMenu = static::$aPresentationData[$this->sTileMode]['decorationCssClass'];
if (!empty($sDecorationClassNavigationMenu))
{

View File

@@ -28,47 +28,82 @@ use Combodo\iTop\DesignElement;
/**
* Description of PortalBrick
*
*
* Classes that will be used only in the portal, not the console.
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Portal\Brick
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
abstract class PortalBrick extends AbstractBrick
{
const ENUM_OPENING_TARGET_MODAL = 'modal';
const ENUM_OPENING_TARGET_SELF = 'self';
const ENUM_OPENING_TARGET_NEW = 'new';
/** @var string ENUM_OPENING_TARGET_MODAL */
const ENUM_OPENING_TARGET_MODAL = 'modal';
/** @var string ENUM_OPENING_TARGET_SELF */
const ENUM_OPENING_TARGET_SELF = 'self';
/** @var string ENUM_OPENING_TARGET_NEW */
const ENUM_OPENING_TARGET_NEW = 'new';
/** @var int DEFAULT_WIDTH */
const DEFAULT_WIDTH = 6;
/** @var int DEFAULT_HEIGHT */
const DEFAULT_HEIGHT = 1;
/** @var bool DEFAULT_MODAL */
const DEFAULT_MODAL = false;
/** @var bool DEFAULT_VISIBLE_HOME */
const DEFAULT_VISIBLE_HOME = true;
/** @var bool DEFAULT_VISIBLE_NAVIGATION_MENU */
const DEFAULT_VISIBLE_NAVIGATION_MENU = true;
/** @var string DEFAULT_DECORATION_CLASS_HOME */
const DEFAULT_DECORATION_CLASS_HOME = '';
/** @var string DEFAULT_DECORATION_CLASS_NAVIGATION_MENU */
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = '';
/** @var string DEFAULT_TILE_TEMPLATE_PATH */
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/tile.html.twig';
/** @var string|null DEFAULT_TILE_CONTROLLER_ACTION */
const DEFAULT_TILE_CONTROLLER_ACTION = null;
const DEFAULT_OPENING_TARGET = self::ENUM_OPENING_TARGET_MODAL;
/** @var string DEFAULT_OPENING_TARGET */
const DEFAULT_OPENING_TARGET = self::ENUM_OPENING_TARGET_MODAL;
/** @var string|null $sRouteName */
static $sRouteName = null;
static $aOpeningTargets = array(self::ENUM_OPENING_TARGET_MODAL, self::ENUM_OPENING_TARGET_SELF, self::ENUM_OPENING_TARGET_NEW);
/** @var array $aOpeningTargets */
static $aOpeningTargets = array(self::ENUM_OPENING_TARGET_MODAL, self::ENUM_OPENING_TARGET_SELF, self::ENUM_OPENING_TARGET_NEW);
/** @var int $iWidth */
protected $iWidth;
/** @var int $iHeight */
protected $iHeight;
/** @var bool $bModal */
protected $bModal;
/** @var bool $bVisibleHome */
protected $bVisibleHome;
/** @var bool $bVisibleNavigationMenu */
protected $bVisibleNavigationMenu;
/** @var string $sDecorationClassHome */
protected $sDecorationClassHome;
/** @var string $sDecorationClassNavigationMenu */
protected $sDecorationClassNavigationMenu;
/** @var string $sTileTemplatePath */
protected $sTileTemplatePath;
/** @var string|null $sTileControllerAction */
protected $sTileControllerAction;
protected $sOpeningTarget;
/** @var string $sOpeningTarget */
protected $sOpeningTarget;
// Vars below are itemization from parent class
/** @var float $fRankHome */
protected $fRankHome;
/** @var float $fRankNavigationMenu */
protected $fRankNavigationMenu;
/** @var string $sTitleHome */
protected $sTitleHome;
/** @var string $sTitleNavigationMenu */
protected $sTitleNavigationMenu;
/**
* @return string|null
*/
public static function GetRouteName()
{
return static::$sRouteName;
@@ -90,7 +125,7 @@ abstract class PortalBrick extends AbstractBrick
$this->sDecorationClassNavigationMenu = static::DEFAULT_DECORATION_CLASS_NAVIGATION_MENU;
$this->sTileTemplatePath = static::DEFAULT_TILE_TEMPLATE_PATH;
$this->sTileControllerAction = static::DEFAULT_TILE_CONTROLLER_ACTION;
$this->sOpeningTarget = static::DEFAULT_OPENING_TARGET;
$this->sOpeningTarget = static::DEFAULT_OPENING_TARGET;
}
/**
@@ -223,26 +258,27 @@ abstract class PortalBrick extends AbstractBrick
return $this->sTileTemplatePath;
}
/**
* Returns the brick's objects opening target (modal, new tab, current window)
*
* @return string
*/
public function GetOpeningTarget()
{
return $this->sOpeningTarget;
}
/**
* Returns the brick's objects opening target (modal, new tab, current window)
*
* @return string
*/
public function GetOpeningTarget()
{
return $this->sOpeningTarget;
}
/**
* Sets the width of the brick
*
* @param boolean $iWidth
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetWidth($iWidth)
{
$this->iWidth = $iWidth;
return $this;
}
@@ -250,12 +286,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets the width of the brick
*
* @param integer $iHeight
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetHeight($iHeight)
{
$this->iHeight = $iHeight;
return $this;
}
@@ -263,12 +300,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick will show in a modal dialog or not
*
* @param boolean $bModal
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetModal($bModal)
{
$this->bModal = $bModal;
return $this;
}
@@ -276,12 +314,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick is visible on the portal's home
*
* @param boolean $bVisibleHome
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetVisibleHome($bVisibleHome)
{
$this->bVisibleHome = $bVisibleHome;
return $this;
}
@@ -289,12 +328,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick is visible on the portal's navigation menu
*
* @param boolean $bVisibleNavigationMenu
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetVisibleNavigationMenu($bVisibleNavigationMenu)
{
$this->bVisibleNavigationMenu = $bVisibleNavigationMenu;
return $this;
}
@@ -302,12 +342,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick's rank on the portal's home
*
* @param float $fRankHome
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetRankHome($fRankHome)
{
$this->fRankHome = $fRankHome;
return $this;
}
@@ -315,12 +356,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick's rank on the portal's navigation menu
*
* @param float $fRankNavigationMenu
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetRankNavigationMenu($fRankNavigationMenu)
{
$this->fRankNavigationMenu = $fRankNavigationMenu;
return $this;
}
@@ -328,12 +370,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick's decoration class on the portal's home
*
* @param string $sDecorationClassHome
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetDecorationClassHome($sDecorationClassHome)
{
$this->sDecorationClassHome = $sDecorationClassHome;
return $this;
}
@@ -341,12 +384,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick's decoration class on the portal's navigation menu
*
* @param string $sDecorationClassNavigationMenu
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetDecorationClassNavigationMenu($sDecorationClassNavigationMenu)
{
$this->sDecorationClassNavigationMenu = $sDecorationClassNavigationMenu;
return $this;
}
@@ -354,12 +398,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick's title on the portal's home
*
* @param string $sTitleHome
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetTitleHome($sTitleHome)
{
$this->sTitleHome = $sTitleHome;
return $this;
}
@@ -367,12 +412,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets if the brick's title on the portal's navigation menu
*
* @param string $sTitleNavigationMenu
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetTitleNavigationMenu($sTitleNavigationMenu)
{
$this->sTitleNavigationMenu = $sTitleNavigationMenu;
return $this;
}
@@ -380,12 +426,13 @@ abstract class PortalBrick extends AbstractBrick
* Sets the brick tile template path
*
* @param string $sTileTemplatePath
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetTileTemplatePath($sTileTemplatePath)
{
$this->sTileTemplatePath = $sTileTemplatePath;
return $this;
}
@@ -393,53 +440,56 @@ abstract class PortalBrick extends AbstractBrick
* Sets the brick tile controller action
*
* @param string $sTileControllerAction
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetTileControllerAction($sTileControllerAction)
{
$this->sTileControllerAction = $sTileControllerAction;
return $this;
}
/**
* Sets the brick's objects opening target
*
* @param string $sOpeningTarget
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetOpeningTarget($sOpeningTarget)
{
$this->sOpeningTarget = $sOpeningTarget;
return $this;
}
/**
* Sets the brick's objects opening target
*
* @param string $sOpeningTarget
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetOpeningTarget($sOpeningTarget)
{
$this->sOpeningTarget = $sOpeningTarget;
/**
* Load the brick's data from the xml passed as a ModuleDesignElement.
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @throws \DOMFormatException
*/
return $this;
}
/**
* Load the brick's data from the xml passed as a ModuleDesignElement.
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @throws \DOMFormatException
*/
public function LoadFromXml(DesignElement $oMDElement)
{
parent::LoadFromXml($oMDElement);
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
case 'width':
$this->SetWidth((int) $oBrickSubNode->GetText(static::DEFAULT_WIDTH));
$this->SetWidth((int)$oBrickSubNode->GetText(static::DEFAULT_WIDTH));
break;
case 'height':
$this->SetHeight((int) $oBrickSubNode->GetText(static::DEFAULT_HEIGHT));
$this->SetHeight((int)$oBrickSubNode->GetText(static::DEFAULT_HEIGHT));
break;
case 'modal':
@@ -473,10 +523,12 @@ abstract class PortalBrick extends AbstractBrick
break;
case 'templates':
$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id=' . ModuleDesign::XPathQuote('tile') . ']');
$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id='.ModuleDesign::XPathQuote('tile').']');
if ($oTemplateNodeList->length > 0)
{
$this->SetTileTemplatePath($oTemplateNodeList->item(0)->GetText(static::DEFAULT_TILE_TEMPLATE_PATH));
/** @var \Combodo\iTop\DesignElement $oTemplateNode */
$oTemplateNode = $oTemplateNodeList->item(0);
$this->SetTileTemplatePath($oTemplateNode->GetText(static::DEFAULT_TILE_TEMPLATE_PATH));
}
break;
@@ -569,15 +621,17 @@ abstract class PortalBrick extends AbstractBrick
$this->SetTileControllerAction($oBrickSubNode->GetText(static::DEFAULT_TILE_CONTROLLER_ACTION));
break;
case 'opening_target':
$sOpeningTarget = $oBrickSubNode->GetText(static::DEFAULT_OPENING_TARGET);
if (!in_array($sOpeningTarget, array(static::ENUM_OPENING_TARGET_MODAL, static::ENUM_OPENING_TARGET_NEW, static::ENUM_OPENING_TARGET_SELF)))
{
throw new DOMFormatException('PortalBrick : opening_target tag value must be modal|new|self ("' . $sOpeningTarget . '" given)', null, null, $oBrickSubNode);
}
case 'opening_target':
$sOpeningTarget = $oBrickSubNode->GetText(static::DEFAULT_OPENING_TARGET);
if (!in_array($sOpeningTarget,
array(static::ENUM_OPENING_TARGET_MODAL, static::ENUM_OPENING_TARGET_NEW, static::ENUM_OPENING_TARGET_SELF)))
{
throw new DOMFormatException('PortalBrick : opening_target tag value must be modal|new|self ("'.$sOpeningTarget.'" given)',
null, null, $oBrickSubNode);
}
$this->SetOpeningTarget($sOpeningTarget);
break;
$this->SetOpeningTarget($sOpeningTarget);
break;
}
}

View File

@@ -1,8 +1,23 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 24/01/19
* Time: 17:28
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\Brick;
@@ -14,6 +29,7 @@ use Exception;
*
* @package Combodo\iTop\Portal\Brick
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class PropertyNotFoundException extends Exception
{

View File

@@ -27,27 +27,43 @@ use Combodo\iTop\DesignElement;
/**
* Description of UserProfileBrick
*
* @package Combodo\iTop\Portal\Brick
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class UserProfileBrick extends PortalBrick
{
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/layout.html.twig';
// Overloaded constants
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/layout.html.twig';
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/tile.html.twig';
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
const DEFAULT_VISIBLE_HOME = false;
const DEFAUT_TITLE = 'Brick:Portal:UserProfile:Title';
const DEFAULT_DECORATION_CLASS_HOME = 'glyphicon glyphicon-user';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'glyphicon glyphicon-user';
const DEFAULT_SHOW_PICTURE_FORM = true;
/** @var bool DEFAULT_SHOW_PICTURE_FORM */
const DEFAULT_SHOW_PICTURE_FORM = true;
/** @var bool DEFAULT_SHOW_PREFERENCES_FORM */
const DEFAULT_SHOW_PREFERENCES_FORM = true;
/** @var bool DEFAULT_SHOW_PASSWORD_FORM */
const DEFAULT_SHOW_PASSWORD_FORM = true;
// Overloaded variables
static $sRouteName = 'p_user_profile_brick';
/** @var array $aForm */
protected $aForm;
/** @var bool $bShowPictureForm */
protected $bShowPictureForm;
/** @var bool $bShowPreferencesForm */
protected $bShowPreferencesForm;
/** @var bool $bShowPasswordForm */
protected $bShowPasswordForm;
/**
* UserProfileBrick constructor.
*/
public function __construct()
{
parent::__construct();
@@ -56,7 +72,7 @@ class UserProfileBrick extends PortalBrick
'id' => 'default-user-profile',
'type' => 'zlist',
'fields' => 'details',
'layout' => null
'layout' => null,
);
$this->bShowPictureForm = static::DEFAULT_SHOW_PICTURE_FORM;
$this->bShowPreferencesForm = static::DEFAULT_SHOW_PREFERENCES_FORM;
@@ -142,14 +158,17 @@ class UserProfileBrick extends PortalBrick
* This is used to set all the brick attributes at once.
*
* @param \Combodo\iTop\DesignElement $oMDElement
*
* @return UserProfileBrick
* @throws DOMFormatException
* @throws DOMFormatException*@throws \Exception
* @throws \Exception
*/
public function LoadFromXml(DesignElement $oMDElement)
{
parent::LoadFromXml($oMDElement);
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
@@ -162,6 +181,7 @@ class UserProfileBrick extends PortalBrick
$this->aForm['type'] = 'custom_list';
$this->aForm['fields'] = array();
/** @var \Combodo\iTop\DesignElement $oFieldNode */
foreach ($oBrickSubNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode)
{
$sFieldId = $oFieldNode->getAttribute('id');
@@ -201,7 +221,7 @@ class UserProfileBrick extends PortalBrick
$this->aForm['layout'] = array(
'type' => (preg_match('/\{\{|\{\#|\{\%/', $sXml) === 1) ? 'twig' : 'xhtml',
'content' => $sXml
'content' => $sXml,
);
}
break;

View File

@@ -28,8 +28,8 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
* Class AbstractController
*
* @package Combodo\iTop\Portal\Controller
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
abstract class AbstractController extends Controller
{

View File

@@ -26,8 +26,8 @@ namespace Combodo\iTop\Portal\Controller;
* Class BrickController
*
* @package Combodo\iTop\Portal\Controller
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
abstract class BrickController extends AbstractController
{

View File

@@ -40,8 +40,8 @@ use Combodo\iTop\Portal\Brick\BrowseBrick;
* Class BrowseBrickController
*
* @package Combodo\iTop\Portal\Controller
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
class BrowseBrickController extends BrickController
{
@@ -60,6 +60,7 @@ class BrowseBrickController extends BrickController
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \Exception
*/
public function DisplayAction(Request $oRequest, $sBrickId, $sBrowseMode = null, $sDataLoading = null)
{
@@ -77,7 +78,8 @@ class BrowseBrickController extends BrickController
// Getting current browse mode (First from router pamater, then default brick value)
$sBrowseMode = (!empty($sBrowseMode)) ? $sBrowseMode : $oBrick->GetDefaultBrowseMode();
// Getting current dataloading mode (First from router parameter, then query parameter, then default brick value)
$sDataLoading = ($sDataLoading !== null) ? $sDataLoading : $oRequestManipulator->ReadParam('sDataLoading', $oBrick->GetDataLoading());
$sDataLoading = ($sDataLoading !== null) ? $sDataLoading : $oRequestManipulator->ReadParam('sDataLoading',
$oBrick->GetDataLoading());
// Getting search value
$sSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
if (!empty($sSearchValue))
@@ -93,17 +95,22 @@ class BrowseBrickController extends BrickController
// Consistency checks
if (!in_array($sBrowseMode, array_keys($aBrowseModes)))
{
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Browse brick "' . $sBrickId . '" : Unknown browse mode "' . $sBrowseMode . '", availables are ' . implode(' / ', array_keys($aBrowseModes)));
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR,
'Browse brick "'.$sBrickId.'" : Unknown browse mode "'.$sBrowseMode.'", availables are '.implode(' / ',
array_keys($aBrowseModes)));
}
if (empty($aLevelsProperties))
{
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Browse brick "' . $sBrickId . '" : No levels to display.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Browse brick "'.$sBrickId.'" : No levels to display.');
}
// Building DBObjectSearch
$oQuery = null;
// ... In this case only we have to build a specific query for the current level only
if (in_array($sBrowseMode, array(BrowseBrick::ENUM_BROWSE_MODE_TREE, BrowseBrick::ENUM_BROWSE_MODE_MOSAIC)) && ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY))
if (in_array($sBrowseMode, array(
BrowseBrick::ENUM_BROWSE_MODE_TREE,
BrowseBrick::ENUM_BROWSE_MODE_MOSAIC,
)) && ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY))
{
// Will be handled later in the pagination part
}
@@ -123,12 +130,15 @@ class BrowseBrickController extends BrickController
if ($i < $iLoopMax)
{
$aRealiasingMap = array();
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->Join($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'], DBSearch::JOIN_REFERENCED_BY, $aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['parent_att'], TREE_OPERATOR_EQUALS, $aRealiasingMap);
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->Join($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'],
DBSearch::JOIN_REFERENCED_BY, $aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['parent_att'],
TREE_OPERATOR_EQUALS, $aRealiasingMap);
foreach ($aLevelsPropertiesKeys as $sLevelAlias)
{
if (array_key_exists($sLevelAlias, $aRealiasingMap))
{
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->RenameAlias($aRealiasingMap[$sLevelAlias], $sLevelAlias);
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->RenameAlias($aRealiasingMap[$sLevelAlias],
$sLevelAlias);
}
}
}
@@ -164,7 +174,8 @@ class BrowseBrickController extends BrickController
for ($k = 0; $k <= $iSearchLoopMax; $k++)
{
$oSearchBinExpr = new BinaryExpression(new FieldExpression($sTmpFieldAttCode, $aLevelsPropertiesKeys[$i]), 'LIKE', new VariableExpression('search_value_' . $k));
$oSearchBinExpr = new BinaryExpression(new FieldExpression($sTmpFieldAttCode, $aLevelsPropertiesKeys[$i]),
'LIKE', new VariableExpression('search_value_'.$k));
if ($k === 0)
{
$oFieldBinExpr = $oSearchBinExpr;
@@ -214,7 +225,7 @@ class BrowseBrickController extends BrickController
// Note : $iSearchloopMax was initialized on the previous loop
for ($j = 0; $j <= $iSearchLoopMax; $j++)
{
$aQueryParams['search_value_' . $j] = '%' . $aSearchValues[$j] . '%';
$aQueryParams['search_value_'.$j] = '%'.$aSearchValues[$j].'%';
}
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->SetInternalParams($aQueryParams);
}
@@ -228,7 +239,8 @@ class BrowseBrickController extends BrickController
// - Check how many records there is.
// - Update $sDataLoading with its new value regarding the number of record and the threshold
$oCountSet = new DBObjectSet($oQuery);
$fThreshold = (float) MetaModel::GetModuleSetting($this->getParameter('combodo.portal.instance.id'), 'lazy_loading_threshold');
$fThreshold = (float)MetaModel::GetModuleSetting($this->getParameter('combodo.portal.instance.id'),
'lazy_loading_threshold');
$sDataLoading = ($oCountSet->Count() > $fThreshold) ? AbstractBrick::ENUM_DATA_LOADING_LAZY : AbstractBrick::ENUM_DATA_LOADING_FULL;
unset($oCountSet);
}
@@ -241,8 +253,9 @@ class BrowseBrickController extends BrickController
{
case BrowseBrick::ENUM_BROWSE_MODE_LIST:
// Retrieving parameters
$iPageNumber = (int) $oRequestManipulator->ReadParam('iPageNumber', 1, FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int) $oRequestManipulator->ReadParam('iListLength', BrowseBrick::DEFAULT_LIST_LENGTH, FILTER_SANITIZE_NUMBER_INT);
$iPageNumber = (int)$oRequestManipulator->ReadParam('iPageNumber', 1, FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$oRequestManipulator->ReadParam('iListLength', BrowseBrick::DEFAULT_LIST_LENGTH,
FILTER_SANITIZE_NUMBER_INT);
// Getting total records number
$oCountSet = new DBObjectSet($oQuery);
@@ -293,7 +306,8 @@ class BrowseBrickController extends BrickController
if (!$bFoundLevel)
{
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Browse brick "' . $sBrickId . '" : Level alias "' . $sLevelAlias . '" is not defined for that brick.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR,
'Browse brick "'.$sBrickId.'" : Level alias "'.$sLevelAlias.'" is not defined for that brick.');
}
}

View File

@@ -31,8 +31,8 @@ use Symfony\Component\HttpFoundation\Response;
* Class DefaultController
*
* @package Combodo\iTop\Portal\Controller
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
class DefaultController extends AbstractController
{
@@ -49,7 +49,7 @@ class DefaultController extends AbstractController
// Rendering tiles
$aData['aTilesRendering'] = array();
foreach($oBricksCollection->GetBricks() as $oBrick)
foreach ($oBricksCollection->GetBricks() as $oBrick)
{
// Doing it only for tile visible on home page to avoid unnecessary rendering
if (($oBrick->GetVisibleHome() === true) && ($oBrick->GetTileControllerAction() !== null))
@@ -57,16 +57,17 @@ class DefaultController extends AbstractController
$aControllerActionParts = explode('::', $oBrick->GetTileControllerAction());
if (count($aControllerActionParts) !== 2)
{
return new Response('Tile controller action must be of form "\Namespace\ControllerClass::FunctionName" for brick "' . $oBrick->GetId() . '"', 500);
return new Response('Tile controller action must be of form "\Namespace\ControllerClass::FunctionName" for brick "'.$oBrick->GetId().'"',
500);
}
$sControllerName = $aControllerActionParts[0];
$sControllerAction = $aControllerActionParts[1];
$oController = new $sControllerName();
if(!$oController instanceof ContainerAwareInterface)
if (!$oController instanceof ContainerAwareInterface)
{
return new Response('Tile controller must be implement ContainerAwareInterface for brick "' . $oBrick->GetId() . '"', 500);
return new Response('Tile controller must be implement ContainerAwareInterface for brick "'.$oBrick->GetId().'"', 500);
}
$oController->setContainer($this->container);
/** @var Response $oResponse */

View File

@@ -50,14 +50,15 @@ use VariableExpression;
* Class ManageBrickController
*
* @package Combodo\iTop\Portal\Controller
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @author Eric Espie <eric.espie@combodo.com>
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @author Pierre Goiffon <pierre.goiffon@combodo.com>
* @since 2.3.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @author Eric Espie <eric.espie@combodo.com>
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @author Pierre Goiffon <pierre.goiffon@combodo.com>
* @since 2.3.0
*/
class ManageBrickController extends BrickController
{
/** @var string EXCEL_EXPORT_TEMPLATE_PATH */
const EXCEL_EXPORT_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig';
/**
@@ -78,9 +79,9 @@ class ManageBrickController extends BrickController
* @throws \OQLException
*/
public function DisplayAction(Request $oRequest, $sBrickId, $sGroupingTab, $sDisplayMode = null)
{
/** @var \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection */
$oBrickCollection = $this->get('brick_collection');
{
/** @var \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection */
$oBrickCollection = $this->get('brick_collection');
/** @var \Combodo\iTop\Portal\Brick\ManageBrick $oBrick */
$oBrick = $oBrickCollection->GetBrickById($sBrickId);
@@ -157,6 +158,7 @@ class ManageBrickController extends BrickController
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \Exception
*/
public function ExcelExportStartAction(Request $oRequest, $sBrickId, $sGroupingTab, $sGroupingArea)
{
@@ -266,6 +268,7 @@ class ManageBrickController extends BrickController
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \Exception
*/
public function GetData(Request $oRequest, $sBrickId, $sGroupingTab, $bNeedDetails = false)
{
@@ -395,8 +398,8 @@ class ManageBrickController extends BrickController
}
}
// - Adding search clause if necessary
$this->ManageSearchValue($aData, $oQuery, $sClass, $aColumnsAttrs);
// - Adding search clause if necessary
$this->ManageSearchValue($aData, $oQuery, $sClass, $aColumnsAttrs);
// Preparing areas
// - We need to retrieve distinct values for the grouping attribute
@@ -427,7 +430,7 @@ class ManageBrickController extends BrickController
'label' => MetaModel::GetName($aDistinctResult['grouped_by_1']),
// Caution : This works only because we froze the grouping areas on the finalclass attribute.
'condition' => $oConditionQuery,
'count' => $aDistinctResult['_itop_count_']
'count' => $aDistinctResult['_itop_count_'],
);
unset($oConditionQuery);
}
@@ -441,7 +444,7 @@ class ManageBrickController extends BrickController
'label' => MetaModel::GetName($sClass),
// Caution : This works only because we froze the grouping areas on the finalclass attribute.
'condition' => null,
'count' => 0
'count' => 0,
);
}
@@ -501,7 +504,8 @@ class ManageBrickController extends BrickController
{
// Retrieving parameters
$iPageNumber = (int)$oRequestManipulator->ReadParam('iPageNumber', 1, FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$oRequestManipulator->ReadParam('iListLength', ManageBrick::DEFAULT_LIST_LENGTH, FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$oRequestManipulator->ReadParam('iListLength', ManageBrick::DEFAULT_LIST_LENGTH,
FILTER_SANITIZE_NUMBER_INT);
// Getting total records number
$oCountSet = new DBObjectSet($oQuery);
@@ -579,7 +583,8 @@ class ManageBrickController extends BrickController
if ($sItemAttr === $sMainActionAttrCode)
{
// Checking if we can edit the object
if (($oBrick->GetOpeningMode() === ManageBrick::ENUM_ACTION_EDIT) && $oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $sCurrentClass, $oCurrentRow->GetKey()))
if (($oBrick->GetOpeningMode() === ManageBrick::ENUM_ACTION_EDIT) && $oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY,
$sCurrentClass, $oCurrentRow->GetKey()))
{
$sActionType = ManageBrick::ENUM_ACTION_EDIT;
}
@@ -605,10 +610,11 @@ class ManageBrickController extends BrickController
}
}
/** @var AttributeDefinition $oAttDef */
/** @var \AttributeDefinition $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sCurrentClass, $sItemAttr);
if ($oAttDef->IsExternalKey())
{
/** @var \AttributeExternalKey $oAttDef */
$sValue = $oCurrentRow->GetAsHTML($sItemAttr.'_friendlyname');
$sSortValue = $oCurrentRow->Get($sItemAttr.'_friendlyname');
@@ -629,19 +635,24 @@ class ManageBrickController extends BrickController
}
}
elseif ($oAttDef instanceof AttributeImage)
{
$oOrmDoc = $oCurrentRow->Get($sItemAttr);
if (is_object($oOrmDoc) && !$oOrmDoc->IsEmpty())
{
$sUrl = $oUrlGenerator->generate('p_object_document_display', array('sObjectClass' => get_class($oCurrentRow), 'sObjectId' => $oCurrentRow->GetKey(), 'sObjectField' => $sItemAttr, 'cache' => 86400));
}
else
{
$sUrl = $oAttDef->Get('default_image');
}
$sValue = '<img src="' . $sUrl . '" />';
$sSortValue = null;
}
{
$oOrmDoc = $oCurrentRow->Get($sItemAttr);
if (is_object($oOrmDoc) && !$oOrmDoc->IsEmpty())
{
$sUrl = $oUrlGenerator->generate('p_object_document_display', array(
'sObjectClass' => get_class($oCurrentRow),
'sObjectId' => $oCurrentRow->GetKey(),
'sObjectField' => $sItemAttr,
'cache' => 86400,
));
}
else
{
$sUrl = $oAttDef->Get('default_image');
}
$sValue = '<img src="'.$sUrl.'" />';
$sSortValue = null;
}
elseif ($oAttDef instanceof AttributeTagSet)
{
/** @var \ormTagSet $oSetValues */
@@ -653,8 +664,8 @@ class ManageBrickController extends BrickController
}
else
{
$sValue = $oAttDef->GetAsHTML($oCurrentRow->Get($sItemAttr));
$sSortValue = $oCurrentRow->Get($sItemAttr);
$sValue = $oAttDef->GetAsHTML($oCurrentRow->Get($sItemAttr));
$sSortValue = $oCurrentRow->Get($sItemAttr);
}
unset($oAttDef);
@@ -662,18 +673,18 @@ class ManageBrickController extends BrickController
'att_code' => $sItemAttr,
'value' => $sValue,
'sort_value' => $sSortValue,
'actions' => $aActions
'actions' => $aActions,
);
}
// ... Checking menu extensions
$aItemButtons = array();
/** @var iPopupMenuExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
{
foreach ($oExtensionInstance->EnumItems(iPopupMenuExtension::PORTAL_OBJLISTITEM_ACTIONS, array(
'portal_id' => $sPortalId,
'object' => $oCurrentRow
'object' => $oCurrentRow,
)) as $oMenuItem)
{
if (is_object($oMenuItem))
@@ -682,7 +693,7 @@ class ManageBrickController extends BrickController
{
$aItemButtons[] = $oMenuItem->GetMenuItem() + array(
'js_files' => $oMenuItem->GetLinkedScripts(),
'type' => 'button'
'type' => 'button',
);
}
elseif ($oMenuItem instanceof URLButtonItem)
@@ -722,7 +733,7 @@ class ManageBrickController extends BrickController
'sTitle' => $aGroupingAreasValues[$sKey]['label'],
'aItems' => $aItems,
'iItemsCount' => $oSet->Count(),
'aColumnsDefinition' => $aColumnsDefinition
'aColumnsDefinition' => $aColumnsDefinition,
);
}
}
@@ -736,7 +747,7 @@ class ManageBrickController extends BrickController
if ($oRequest->isXmlHttpRequest())
{
$aData = $aData + array(
'data' => $aGroupingAreasData[$sGroupingArea]['aItems']
'data' => $aGroupingAreasData[$sGroupingArea]['aItems'],
);
}
else
@@ -757,7 +768,7 @@ class ManageBrickController extends BrickController
$aUrls[] = $oUrlGenerator->generate('p_manage_brick', array(
'sBrickId' => $sBrickId,
'sDisplayMode' => 'default',
'sGroupingTab' => $aValues['value']
'sGroupingTab' => $aValues['value'],
));
}
@@ -812,16 +823,16 @@ class ManageBrickController extends BrickController
// Note : This is a very naive search at the moment
if (!empty($sSearchValue))
{
// Putting only valid attributes as one can define attributes of leaf classes in the brick definition (<fields>), but at this stage we are working on the abstract class.
// Note: This won't fix everything as the search will not be looking in all fields.
$aSearchListItems = array();
foreach($aColumnsAttrs as $sColumnAttr)
{
if(MetaModel::IsValidAttCode($sClass, $sColumnAttr))
{
$aSearchListItems[] = $sColumnAttr;
}
}
// Putting only valid attributes as one can define attributes of leaf classes in the brick definition (<fields>), but at this stage we are working on the abstract class.
// Note: This won't fix everything as the search will not be looking in all fields.
$aSearchListItems = array();
foreach ($aColumnsAttrs as $sColumnAttr)
{
if (MetaModel::IsValidAttCode($sClass, $sColumnAttr))
{
$aSearchListItems[] = $sColumnAttr;
}
}
$oFullBinExpr = null;
foreach ($aSearchListItems as $sSearchItemAttr)
@@ -857,17 +868,18 @@ class ManageBrickController extends BrickController
/**
* Get the groups using a given attribute code.
* If a limit is given, the remaining groups are aggregated (groupby result and search request).
* If a limit is given, the remaining groups are aggregated (group by result and search request).
*
* @param \DBSearch $oQuery Initial query
* @param string $sGroupingTabAttCode Attribute code to group by
* @param \Combodo\iTop\Portal\Brick\ManageBrick $oBrick
*
* @return array of results from the groupby request and the corrsponding search.
* @return array of results from the group by request and the corresponding search.
*
* @throws \CoreException
* @throws \MySQLException
* @throws \OQLException
* @throws \Exception
*/
protected function GroupByAttribute(
DBSearch $oQuery, $sGroupingTabAttCode, ManageBrick $oBrick
@@ -912,7 +924,7 @@ class ManageBrickController extends BrickController
{
$oConditionQuery = DBSearch::CloneWithAlias($oQuery, 'GTAB');
$oExpression = new BinaryExpression(new FieldExpression($sGroupingTabAttCode,
$oConditionQuery->GetClassAlias()), '=', new UnaryExpression($aDistinctResult['grouped_by_1']));
$oConditionQuery->GetClassAlias()), '=', new UnaryExpression($aDistinctResult['grouped_by_1']));
$oConditionQuery->AddConditionExpression($oExpression);
$sHtmlLabel = $oFieldExp->MakeValueLabel($oDistinctQuery, $aDistinctResult['grouped_by_1'], '');
@@ -935,7 +947,7 @@ class ManageBrickController extends BrickController
{
$iOtherCount += $aResult['_itop_count_'];
$oExpr = new BinaryExpression(new FieldExpression($sGroupingTabAttCode,
$oConditionQuery->GetClassAlias()), '=', new UnaryExpression($aResult['grouped_by_1']));
$oConditionQuery->GetClassAlias()), '=', new UnaryExpression($aResult['grouped_by_1']));
if (is_null($oExpression))
{
$oExpression = $oExpr;

View File

@@ -42,11 +42,12 @@ use Combodo\iTop\Renderer\Bootstrap\BsFormRenderer;
* Class UserProfileBrickController
*
* @package Combodo\iTop\Portal\Controller
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
class UserProfileBrickController extends BrickController
{
/** @var string ENUM_FORM_TYPE_PICTURE */
const ENUM_FORM_TYPE_PICTURE = 'picture';
/**
@@ -133,16 +134,17 @@ class UserProfileBrickController extends BrickController
$sCurContactId = $oCurContact->GetKey();
// Preparing forms
$aData['forms']['contact'] = $ObjectFormHandler->HandleForm($oRequest, $sFormMode, $sCurContactClass, $sCurContactId, $oBrick->GetForm());
$aData['forms']['contact'] = $ObjectFormHandler->HandleForm($oRequest, $sFormMode, $sCurContactClass, $sCurContactId,
$oBrick->GetForm());
$aData['forms']['preferences'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
// - If user can change password, we display the form
$aData['forms']['password'] = (UserRights::CanChangePassword()) ? $this->HandlePasswordForm($oRequest, $sFormMode) : null;
$aData = $aData + array(
'oBrick' => $oBrick,
'sFormMode' => $sFormMode,
'bDemoMode' => $bDemoMode,
);
'oBrick' => $oBrick,
'sFormMode' => $sFormMode,
'bDemoMode' => $bDemoMode,
);
$oResponse = $this->render($oBrick->GetPageTemplatePath(), $aData);
}
@@ -186,29 +188,36 @@ class UserProfileBrickController extends BrickController
}
}
// - Submit
else if ($sOperation === 'submit')
else
{
$sFormManagerClass = $oRequestManipulator->ReadParam('formmanager_class', null, FILTER_UNSAFE_RAW);
$sFormManagerData = $oRequestManipulator->ReadParam('formmanager_data', null, FILTER_UNSAFE_RAW);
if ($sFormManagerClass === null || $sFormManagerData === null)
if ($sOperation === 'submit')
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Parameters formmanager_class and formamanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameters formmanager_class and formmanager_data must be defined.');
}
$sFormManagerClass = $oRequestManipulator->ReadParam('formmanager_class', null, FILTER_UNSAFE_RAW);
$sFormManagerData = $oRequestManipulator->ReadParam('formmanager_data', null, FILTER_UNSAFE_RAW);
if ($sFormManagerClass === null || $sFormManagerData === null)
{
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Parameters formmanager_class and formamanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR,
'Parameters formmanager_class and formmanager_data must be defined.');
}
// Rebuilding manager from json
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
// Applying modification to object
$aFormData['validation'] = $oFormManager->OnSubmit(array('currentValues' => $oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW)));
// Reloading page only if preferences were changed
if (($aFormData['validation']['valid'] === true) && !empty($aFormData['validation']['messages']['success']))
{
$aFormData['validation']['redirection'] = array(
'url' => $oUrlGenerator->generate('p_user_profile_brick'),
);
// Rebuilding manager from json
/** @var \Combodo\iTop\Form\FormManager $oFormManager */
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
// Applying modification to object
$aFormData['validation'] = $oFormManager->OnSubmit(array(
'currentValues' => $oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW),
));
// Reloading page only if preferences were changed
if (($aFormData['validation']['valid'] === true) && !empty($aFormData['validation']['messages']['success']))
{
$aFormData['validation']['redirection'] = array(
'url' => $oUrlGenerator->generate('p_user_profile_brick'),
);
}
}
}
// Else, submit from another form
// Else, submit from another form
// Preparing field_set data
$aFieldSetData = array(
@@ -244,7 +253,7 @@ class UserProfileBrickController extends BrickController
// Handling form
$sOperation = /** @var \Combodo\iTop\Portal\Helper\RequestManipulatorHelper $oRequestManipulator */
$oRequestManipulator->ReadParam('operation', null);
$oRequestManipulator->ReadParam('operation', null);
// - Create
if ($sOperation === null)
{
@@ -255,27 +264,34 @@ class UserProfileBrickController extends BrickController
$oFormManager = new PasswordFormManager();
$oFormManager->SetRenderer($oFormRenderer)
->Build();
// - Checking if we have to make the form read only
if ($sFormMode === ObjectFormHandlerHelper::ENUM_MODE_VIEW)
{
$oFormManager->GetForm()->MakeReadOnly();
}
// - Checking if we have to make the form read only
if ($sFormMode === ObjectFormHandlerHelper::ENUM_MODE_VIEW)
{
$oFormManager->GetForm()->MakeReadOnly();
}
}
// - Submit
else if ($sOperation === 'submit')
else
{
$sFormManagerClass = $oRequestManipulator->ReadParam('formmanager_class', null, FILTER_UNSAFE_RAW);
$sFormManagerData = $oRequestManipulator->ReadParam('formmanager_data', null, FILTER_UNSAFE_RAW);
if ($sFormManagerClass === null || $sFormManagerData === null)
if ($sOperation === 'submit')
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Parameters formmanager_class and formamanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameters formmanager_class and formmanager_data must be defined.');
}
$sFormManagerClass = $oRequestManipulator->ReadParam('formmanager_class', null, FILTER_UNSAFE_RAW);
$sFormManagerData = $oRequestManipulator->ReadParam('formmanager_data', null, FILTER_UNSAFE_RAW);
if ($sFormManagerClass === null || $sFormManagerData === null)
{
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Parameters formmanager_class and formamanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR,
'Parameters formmanager_class and formmanager_data must be defined.');
}
// Rebuilding manager from json
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
// Applying modification to object
$aFormData['validation'] = $oFormManager->OnSubmit(array('currentValues' => $oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW)));
// Rebuilding manager from json
/** @var \Combodo\iTop\Form\FormManager $oFormManager */
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
// Applying modification to object
$aFormData['validation'] = $oFormManager->OnSubmit(array(
'currentValues' => $oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW),
));
}
}
// Else, submit from another form
@@ -316,48 +332,53 @@ class UserProfileBrickController extends BrickController
// - No operation specified
if ($sOperation === null)
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Operation parameter must be specified.');
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Operation parameter must be specified.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Operation parameter must be specified.');
}
// - Submit
else if ($sOperation === 'submit')
else
{
$oRequestFiles = $oRequest->files;
$oPictureFile = $oRequestFiles->get($sPictureAttCode);
if ($oPictureFile === null)
if ($sOperation === 'submit')
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Parameter picture must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameter picture must be defined.');
}
$oRequestFiles = $oRequest->files;
$oPictureFile = $oRequestFiles->get($sPictureAttCode);
if ($oPictureFile === null)
{
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Parameter picture must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameter picture must be defined.');
}
try
{
// Retrieving image as an ORMDocument
$oImage = utils::ReadPostedDocument($sPictureAttCode);
// Retrieving current contact
/** @var \DBObject $oCurContact */
$oCurContact = UserRights::GetContactObject();
// Resizing image
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurContact), $sPictureAttCode);
$aSize = utils::GetImageSize($oImage->GetData());
$oImage = utils::ResizeImageToFit($oImage, $aSize[0], $aSize[1], $oAttDef->Get('storage_max_width'), $oAttDef->Get('storage_max_height'));
// Setting it to the contact
$oCurContact->Set($sPictureAttCode, $oImage);
// Forcing allowed writing on the object if necessary.
$oCurContact->AllowWrite(true);
$oCurContact->DBUpdate();
}
catch (FileUploadException $e)
{
$aFormData['error'] = $e->GetMessage();
}
try
{
// Retrieving image as an ORMDocument
$oImage = utils::ReadPostedDocument($sPictureAttCode);
// Retrieving current contact
/** @var \cmdbAbstractObject $oCurContact */
$oCurContact = UserRights::GetContactObject();
// Resizing image
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurContact), $sPictureAttCode);
$aSize = utils::GetImageSize($oImage->GetData());
$oImage = utils::ResizeImageToFit($oImage, $aSize[0], $aSize[1], $oAttDef->Get('storage_max_width'),
$oAttDef->Get('storage_max_height'));
// Setting it to the contact
$oCurContact->Set($sPictureAttCode, $oImage);
// Forcing allowed writing on the object if necessary.
$oCurContact->AllowWrite(true);
$oCurContact->DBUpdate();
}
catch (FileUploadException $e)
{
$aFormData['error'] = $e->GetMessage();
}
$aFormData['picture_url'] = $oImage->GetDownloadURL(get_class($oCurContact), $oCurContact->GetKey(), $sPictureAttCode);
$aFormData['validation'] = array(
'valid' => true,
'messages' => array(),
);
$aFormData['picture_url'] = $oImage->GetDownloadURL(get_class($oCurContact), $oCurContact->GetKey(), $sPictureAttCode);
$aFormData['validation'] = array(
'valid' => true,
'messages' => array(),
);
}
}
// Else, submit from another form
return $aFormData;

View File

@@ -28,30 +28,30 @@ use ModuleDesign;
* Class AbstractConfiguration
*
* @package Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class AbstractConfiguration
{
/** @var \ModuleDesign $oModuleDesign */
private $oModuleDesign;
/** @var \ModuleDesign $oModuleDesign */
private $oModuleDesign;
/**
* AbstractConfiguration constructor.
*
* @param \ModuleDesign $oModuleDesign
*/
public function __construct(ModuleDesign $oModuleDesign)
{
$this->oModuleDesign = $oModuleDesign;
}
public function __construct(ModuleDesign $oModuleDesign)
{
$this->oModuleDesign = $oModuleDesign;
}
/**
* @return \ModuleDesign
*/
public function GetModuleDesign()
{
return $this->oModuleDesign;
}
/**
* @return \ModuleDesign
*/
public function GetModuleDesign()
{
return $this->oModuleDesign;
}
}

View File

@@ -34,8 +34,8 @@ use DOMFormatException;
* Class Basic
*
* @package Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class Basic extends AbstractConfiguration
{
@@ -44,76 +44,76 @@ class Basic extends AbstractConfiguration
*
* @throws \Exception
*/
public function Process(Container $oContainer)
{
try
{
// Parsing file
// - Default values
$aPortalConf = $this->GetInitialPortalConf();
// - Global portal properties
$aPortalConf = $this->ParseGlobalProperties($aPortalConf);
// - Rectifying portal logo url
$aPortalConf = $this->AppendLogoUri($aPortalConf);
// - User allowed portals
$aPortalConf['portals'] = UserRights::GetAllowedPortals();
public function Process(Container $oContainer)
{
try
{
// Parsing file
// - Default values
$aPortalConf = $this->GetInitialPortalConf();
// - Global portal properties
$aPortalConf = $this->ParseGlobalProperties($aPortalConf);
// - Rectifying portal logo url
$aPortalConf = $this->AppendLogoUri($aPortalConf);
// - User allowed portals
$aPortalConf['portals'] = UserRights::GetAllowedPortals();
// - class list
$aPortalConf['ui_extensions'] = $this->GetUiExtensions($oContainer);
}
catch (Exception $oException)
{
throw new Exception('Error while parsing portal configuration file : '.$oException->getMessage());
}
// - class list
$aPortalConf['ui_extensions'] = $this->GetUiExtensions($oContainer);
}
catch (Exception $oException)
{
throw new Exception('Error while parsing portal configuration file : '.$oException->getMessage());
}
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
/**
* Returns an array containing the initial portal configuration with all default values
*
* @return array
*/
private function GetInitialPortalConf()
{
$aPortalConf = array(
'properties' => array(
'id' => $_ENV['PORTAL_ID'],
'name' => 'Page:DefaultTitle',
'logo' => (file_exists(MODULESROOT.'branding/portal-logo.png')) ? utils::GetAbsoluteUrlModulesRoot().'branding/portal-logo.png' : '../images/logo-itop-dark-bg.svg',
'themes' => array(
'bootstrap' => 'itop-portal-base/portal/public/css/bootstrap-theme-combodo.scss',
'portal' => 'itop-portal-base/portal/public/css/portal.scss',
'others' => array(),
),
'templates' => array(
'layout' => 'itop-portal-base/portal/templates/layout.html.twig',
'home' => 'itop-portal-base/portal/templates/home/layout.html.twig',
),
'urlmaker_class' => null,
'triggers_query' => null,
'attachments' => array(
'allow_delete' => true,
),
'allowed_portals' => array(
'opening_mode' => null,
),
),
'portals' => array(),
'forms' => array(),
'ui_extensions' => array(
'css_files' => array(),
'css_inline' => null,
'js_files' => array(),
'js_inline' => null,
'html' => array(),
),
'bricks' => array(),
'bricks_total_width' => 0,
);
/**
* Returns an array containing the initial portal configuration with all default values
*
* @return array
*/
private function GetInitialPortalConf()
{
$aPortalConf = array(
'properties' => array(
'id' => $_ENV['PORTAL_ID'],
'name' => 'Page:DefaultTitle',
'logo' => (file_exists(MODULESROOT.'branding/portal-logo.png')) ? utils::GetAbsoluteUrlModulesRoot().'branding/portal-logo.png' : '../images/logo-itop-dark-bg.svg',
'themes' => array(
'bootstrap' => 'itop-portal-base/portal/public/css/bootstrap-theme-combodo.scss',
'portal' => 'itop-portal-base/portal/public/css/portal.scss',
'others' => array(),
),
'templates' => array(
'layout' => 'itop-portal-base/portal/templates/layout.html.twig',
'home' => 'itop-portal-base/portal/templates/home/layout.html.twig',
),
'urlmaker_class' => null,
'triggers_query' => null,
'attachments' => array(
'allow_delete' => true,
),
'allowed_portals' => array(
'opening_mode' => null,
),
),
'portals' => array(),
'forms' => array(),
'ui_extensions' => array(
'css_files' => array(),
'css_inline' => null,
'js_files' => array(),
'js_inline' => null,
'html' => array(),
),
'bricks' => array(),
'bricks_total_width' => 0,
);
return $aPortalConf;
}
return $aPortalConf;
}
/**
* @param array $aPortalConf
@@ -121,40 +121,40 @@ class Basic extends AbstractConfiguration
* @return array
* @throws \DOMFormatException
*/
private function ParseGlobalProperties(array $aPortalConf)
{
/** @var \MFElement $oPropertyNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/properties/*') as $oPropertyNode)
{
switch ($oPropertyNode->nodeName)
{
case 'name':
case 'urlmaker_class':
case 'triggers_query':
$aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
$aPortalConf['properties'][$oPropertyNode->nodeName]
);
break;
case 'logo':
$aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
$aPortalConf['properties'][$oPropertyNode->nodeName]
);
break;
case 'themes':
case 'templates':
$aPortalConf = $this->ParseTemplateAndTheme($aPortalConf, $oPropertyNode);
break;
case 'attachments':
$aPortalConf = $this->ParseAttachments($aPortalConf, $oPropertyNode);
break;
case 'allowed_portals':
$aPortalConf = $this->ParseAllowedPortals($aPortalConf, $oPropertyNode);
break;
}
}
private function ParseGlobalProperties(array $aPortalConf)
{
/** @var \MFElement $oPropertyNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/properties/*') as $oPropertyNode)
{
switch ($oPropertyNode->nodeName)
{
case 'name':
case 'urlmaker_class':
case 'triggers_query':
$aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
$aPortalConf['properties'][$oPropertyNode->nodeName]
);
break;
case 'logo':
$aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
$aPortalConf['properties'][$oPropertyNode->nodeName]
);
break;
case 'themes':
case 'templates':
$aPortalConf = $this->ParseTemplateAndTheme($aPortalConf, $oPropertyNode);
break;
case 'attachments':
$aPortalConf = $this->ParseAttachments($aPortalConf, $oPropertyNode);
break;
case 'allowed_portals':
$aPortalConf = $this->ParseAllowedPortals($aPortalConf, $oPropertyNode);
break;
}
}
return $aPortalConf;
}
return $aPortalConf;
}
/**
* @param array $aPortalConf
@@ -163,54 +163,54 @@ class Basic extends AbstractConfiguration
* @return array
* @throws \DOMFormatException
*/
private function ParseTemplateAndTheme(array $aPortalConf, DesignElement $oPropertyNode)
{
/** @var \MFElement $oSubNode */
foreach ($oPropertyNode->GetNodes('template|theme') as $oSubNode)
{
if (!$oSubNode->hasAttribute('id') || $oSubNode->GetText(null) === null)
{
throw new DOMFormatException(
'Tag ' . $oSubNode->nodeName.' must have a "id" attribute as well as a value',
null, null, $oSubNode
);
}
private function ParseTemplateAndTheme(array $aPortalConf, DesignElement $oPropertyNode)
{
/** @var \MFElement $oSubNode */
foreach ($oPropertyNode->GetNodes('template|theme') as $oSubNode)
{
if (!$oSubNode->hasAttribute('id') || $oSubNode->GetText(null) === null)
{
throw new DOMFormatException(
'Tag '.$oSubNode->nodeName.' must have a "id" attribute as well as a value',
null, null, $oSubNode
);
}
$sNodeId = $oSubNode->getAttribute('id');
switch ($oSubNode->nodeName)
{
case 'theme':
switch ($sNodeId)
{
case 'bootstrap':
case 'portal':
case 'custom':
$aPortalConf['properties']['themes'][$sNodeId] = $oSubNode->GetText(null);
break;
default:
$aPortalConf['properties']['themes']['others'][] = $oSubNode->GetText(null);
break;
}
break;
case 'template':
switch ($sNodeId)
{
case 'layout':
case 'home':
$aPortalConf['properties']['templates'][$sNodeId] = $oSubNode->GetText(null);
break;
default:
throw new DOMFormatException(
'Value "'.$sNodeId.'" is not handled for template[@id]',
null, null, $oSubNode
);
break;
}
break;
}
}
$sNodeId = $oSubNode->getAttribute('id');
switch ($oSubNode->nodeName)
{
case 'theme':
switch ($sNodeId)
{
case 'bootstrap':
case 'portal':
case 'custom':
$aPortalConf['properties']['themes'][$sNodeId] = $oSubNode->GetText(null);
break;
default:
$aPortalConf['properties']['themes']['others'][] = $oSubNode->GetText(null);
break;
}
break;
case 'template':
switch ($sNodeId)
{
case 'layout':
case 'home':
$aPortalConf['properties']['templates'][$sNodeId] = $oSubNode->GetText(null);
break;
default:
throw new DOMFormatException(
'Value "'.$sNodeId.'" is not handled for template[@id]',
null, null, $oSubNode
);
break;
}
break;
}
}
return $aPortalConf;
return $aPortalConf;
}
/**
@@ -219,26 +219,26 @@ class Basic extends AbstractConfiguration
*
* @return array
*/
private function ParseAttachments(array $aPortalConf, DesignElement $oPropertyNode)
{
/** @var \MFElement $oSubNode */
foreach ($oPropertyNode->GetNodes('*') as $oSubNode)
{
switch ($oSubNode->nodeName)
{
case 'allow_delete':
$sValue = $oSubNode->GetText();
// If the text is null, we keep the default value
// Else we set it
if ($sValue !== null)
{
$aPortalConf['properties']['attachments'][$oSubNode->nodeName] = ($sValue === 'true') ? true : false;
}
break;
}
}
private function ParseAttachments(array $aPortalConf, DesignElement $oPropertyNode)
{
/** @var \MFElement $oSubNode */
foreach ($oPropertyNode->GetNodes('*') as $oSubNode)
{
switch ($oSubNode->nodeName)
{
case 'allow_delete':
$sValue = $oSubNode->GetText();
// If the text is null, we keep the default value
// Else we set it
if ($sValue !== null)
{
$aPortalConf['properties']['attachments'][$oSubNode->nodeName] = ($sValue === 'true') ? true : false;
}
break;
}
}
return$aPortalConf;
return $aPortalConf;
}
/**
@@ -247,26 +247,26 @@ class Basic extends AbstractConfiguration
*
* @return array
*/
private function ParseAllowedPortals(array $aPortalConf, DesignElement $oPropertyNode)
{
/** @var \MFElement $oSubNode */
foreach ($oPropertyNode->GetNodes('*') as $oSubNode)
{
switch ($oSubNode->nodeName)
{
case 'opening_mode':
$sValue = $oSubNode->GetText();
// If the text is null, we keep the default value
// Else we set it
if ($sValue !== null)
{
$aPortalConf['properties']['allowed_portals'][$oSubNode->nodeName] = ($sValue === 'self') ? 'self' : 'tab';
}
break;
}
}
private function ParseAllowedPortals(array $aPortalConf, DesignElement $oPropertyNode)
{
/** @var \MFElement $oSubNode */
foreach ($oPropertyNode->GetNodes('*') as $oSubNode)
{
switch ($oSubNode->nodeName)
{
case 'opening_mode':
$sValue = $oSubNode->GetText();
// If the text is null, we keep the default value
// Else we set it
if ($sValue !== null)
{
$aPortalConf['properties']['allowed_portals'][$oSubNode->nodeName] = ($sValue === 'self') ? 'self' : 'tab';
}
break;
}
}
return $aPortalConf;
return $aPortalConf;
}
/**
@@ -275,17 +275,17 @@ class Basic extends AbstractConfiguration
* @return array
* @throws \Exception
*/
private function AppendLogoUri(array $aPortalConf)
{
$sLogoUri = $aPortalConf['properties']['logo'];
if (!preg_match('/^http/', $sLogoUri))
{
// We prefix it with the server base url
$sLogoUri = utils::GetAbsoluteUrlAppRoot().'env-'.utils::GetCurrentEnvironment().'/'.$sLogoUri;
}
$aPortalConf['properties']['logo'] = $sLogoUri;
private function AppendLogoUri(array $aPortalConf)
{
$sLogoUri = $aPortalConf['properties']['logo'];
if (!preg_match('/^http/', $sLogoUri))
{
// We prefix it with the server base url
$sLogoUri = utils::GetAbsoluteUrlAppRoot().'env-'.utils::GetCurrentEnvironment().'/'.$sLogoUri;
}
$aPortalConf['properties']['logo'] = $sLogoUri;
return $aPortalConf;
return $aPortalConf;
}
/**
@@ -295,74 +295,74 @@ class Basic extends AbstractConfiguration
* @throws \Exception
*/
private function GetUiExtensions(Container $oContainer)
{
$aUIExtensions = array(
'css_files' => array(),
'css_inline' => null,
'js_files' => array(),
'js_inline' => null,
'html' => array(),
);
$aUIExtensionHooks = array(
iPortalUIExtension::ENUM_PORTAL_EXT_UI_BODY,
iPortalUIExtension::ENUM_PORTAL_EXT_UI_NAVIGATION_MENU,
iPortalUIExtension::ENUM_PORTAL_EXT_UI_MAIN_CONTENT,
);
{
$aUIExtensions = array(
'css_files' => array(),
'css_inline' => null,
'js_files' => array(),
'js_inline' => null,
'html' => array(),
);
$aUIExtensionHooks = array(
iPortalUIExtension::ENUM_PORTAL_EXT_UI_BODY,
iPortalUIExtension::ENUM_PORTAL_EXT_UI_NAVIGATION_MENU,
iPortalUIExtension::ENUM_PORTAL_EXT_UI_MAIN_CONTENT,
);
/** @var iPortalUIExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPortalUIExtension') as $oExtensionInstance)
{
// Adding CSS files
$aImportPaths = array($oContainer->getParameter('combodo.portal.base.absolute_path').'css/');
foreach($oExtensionInstance->GetCSSFiles($oContainer) as $sCSSFile)
{
// Removing app root url as we need to pass a path on the file system (relative to app root)
$sCSSFilePath = str_replace(utils::GetAbsoluteUrlAppRoot(), '', $sCSSFile);
// Compiling SCSS file
$sCSSFileCompiled = $oContainer->getParameter('combodo.absolute_url').utils::GetCSSFromSASS($sCSSFilePath,
$aImportPaths);
/** @var iPortalUIExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPortalUIExtension') as $oExtensionInstance)
{
// Adding CSS files
$aImportPaths = array($oContainer->getParameter('combodo.portal.base.absolute_path').'css/');
foreach ($oExtensionInstance->GetCSSFiles($oContainer) as $sCSSFile)
{
// Removing app root url as we need to pass a path on the file system (relative to app root)
$sCSSFilePath = str_replace(utils::GetAbsoluteUrlAppRoot(), '', $sCSSFile);
// Compiling SCSS file
$sCSSFileCompiled = $oContainer->getParameter('combodo.absolute_url').utils::GetCSSFromSASS($sCSSFilePath,
$aImportPaths);
if(!in_array($sCSSFileCompiled, $aUIExtensions['css_files']))
{
$aUIExtensions['css_files'][] = $sCSSFileCompiled;
}
}
if (!in_array($sCSSFileCompiled, $aUIExtensions['css_files']))
{
$aUIExtensions['css_files'][] = $sCSSFileCompiled;
}
}
// Adding CSS inline
$sCSSInline = $oExtensionInstance->GetCSSInline($oContainer);
if ($sCSSInline !== null)
{
$aUIExtensions['css_inline'] .= "\n\n".$sCSSInline;
}
// Adding CSS inline
$sCSSInline = $oExtensionInstance->GetCSSInline($oContainer);
if ($sCSSInline !== null)
{
$aUIExtensions['css_inline'] .= "\n\n".$sCSSInline;
}
// Adding JS files
$aUIExtensions['js_files'] = array_merge($aUIExtensions['js_files'],
$oExtensionInstance->GetJSFiles($oContainer));
// Adding JS files
$aUIExtensions['js_files'] = array_merge($aUIExtensions['js_files'],
$oExtensionInstance->GetJSFiles($oContainer));
// Adding JS inline
$sJSInline = $oExtensionInstance->GetJSInline($oContainer);
if ($sJSInline !== null)
{
// Note: Semi-colon is to prevent previous script that would have omitted it.
$aUIExtensions['js_inline'] .= "\n\n;\n".$sJSInline;
}
// Adding JS inline
$sJSInline = $oExtensionInstance->GetJSInline($oContainer);
if ($sJSInline !== null)
{
// Note: Semi-colon is to prevent previous script that would have omitted it.
$aUIExtensions['js_inline'] .= "\n\n;\n".$sJSInline;
}
// Adding HTML for each hook
foreach ($aUIExtensionHooks as $sUIExtensionHook)
{
$sFunctionName = 'Get'.$sUIExtensionHook.'HTML';
$sHTML = $oExtensionInstance->$sFunctionName($oContainer);
if ($sHTML !== null)
{
if (!array_key_exists($sUIExtensionHook, $aUIExtensions['html']))
{
$aUIExtensions['html'][$sUIExtensionHook] = '';
}
$aUIExtensions['html'][$sUIExtensionHook] .= "\n\n".$sHTML;
}
}
}
// Adding HTML for each hook
foreach ($aUIExtensionHooks as $sUIExtensionHook)
{
$sFunctionName = 'Get'.$sUIExtensionHook.'HTML';
$sHTML = $oExtensionInstance->$sFunctionName($oContainer);
if ($sHTML !== null)
{
if (!array_key_exists($sUIExtensionHook, $aUIExtensions['html']))
{
$aUIExtensions['html'][$sUIExtensionHook] = '';
}
$aUIExtensions['html'][$sUIExtensionHook] .= "\n\n".$sHTML;
}
}
}
return $aUIExtensions;
}
return $aUIExtensions;
}
}

View File

@@ -31,8 +31,8 @@ use MetaModel;
* Class Forms
*
* @package Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class Forms extends AbstractConfiguration
{
@@ -41,239 +41,239 @@ class Forms extends AbstractConfiguration
*
* @throws \Exception
*/
public function Process(Container $oContainer)
{
$aForms = array();
public function Process(Container $oContainer)
{
$aForms = array();
/** @var \MFElement $oFormNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/forms/form') as $oFormNode)
{
try
{
// Parsing form id
if ($oFormNode->getAttribute('id') === '')
{
throw new DOMFormatException('form tag must have an id attribute', null, null, $oFormNode);
}
/** @var \MFElement $oFormNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/forms/form') as $oFormNode)
{
try
{
// Parsing form id
if ($oFormNode->getAttribute('id') === '')
{
throw new DOMFormatException('form tag must have an id attribute', null, null, $oFormNode);
}
// Parsing form object class
if ($oFormNode->GetUniqueElement('class')->GetText() !== null)
{
// Parsing class
$sFormClass = $oFormNode->GetUniqueElement('class')->GetText();
// Parsing form object class
if ($oFormNode->GetUniqueElement('class')->GetText() !== null)
{
// Parsing class
$sFormClass = $oFormNode->GetUniqueElement('class')->GetText();
// Parsing properties
$aFormProperties = array(
'display_mode' => ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE,
'always_show_submit' => ApplicationHelper::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT,
);
if ($oFormNode->GetOptionalElement('properties') !== null)
{
/** @var \MFElement $oPropertyNode */
foreach ($oFormNode->GetOptionalElement('properties')->childNodes as $oPropertyNode)
{
switch ($oPropertyNode->nodeName)
{
case 'display_mode':
$aFormProperties['display_mode'] = $oPropertyNode->GetText(ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE);
break;
case 'always_show_submit':
$aFormProperties['always_show_submit'] = ($oPropertyNode->GetText('false') === 'true') ? true : false;
break;
}
}
}
// Parsing properties
$aFormProperties = array(
'display_mode' => ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE,
'always_show_submit' => ApplicationHelper::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT,
);
if ($oFormNode->GetOptionalElement('properties') !== null)
{
/** @var \MFElement $oPropertyNode */
foreach ($oFormNode->GetOptionalElement('properties')->childNodes as $oPropertyNode)
{
switch ($oPropertyNode->nodeName)
{
case 'display_mode':
$aFormProperties['display_mode'] = $oPropertyNode->GetText(ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE);
break;
case 'always_show_submit':
$aFormProperties['always_show_submit'] = ($oPropertyNode->GetText('false') === 'true') ? true : false;
break;
}
}
}
// Parsing available modes for that form (view, edit, create, apply_stimulus)
$aFormStimuli = array();
if (($oFormNode->GetOptionalElement('modes') !== null) && ($oFormNode->GetOptionalElement('modes')->GetNodes('mode')->length > 0))
{
$aModes = array();
/** @var \MFElement $oModeNode */
foreach ($oFormNode->GetOptionalElement('modes')->GetNodes('mode') as $oModeNode)
{
if ($oModeNode->getAttribute('id') !== '')
{
$aModes[] = $oModeNode->getAttribute('id');
}
else
{
throw new DOMFormatException('Mode tag must have an id attribute', null, null,
$oFormNode);
}
// Parsing available modes for that form (view, edit, create, apply_stimulus)
$aFormStimuli = array();
if (($oFormNode->GetOptionalElement('modes') !== null) && ($oFormNode->GetOptionalElement('modes')->GetNodes('mode')->length > 0))
{
$aModes = array();
/** @var \MFElement $oModeNode */
foreach ($oFormNode->GetOptionalElement('modes')->GetNodes('mode') as $oModeNode)
{
if ($oModeNode->getAttribute('id') !== '')
{
$aModes[] = $oModeNode->getAttribute('id');
}
else
{
throw new DOMFormatException('Mode tag must have an id attribute', null, null,
$oFormNode);
}
// If apply_stimulus mode, checking if stimuli are defined
if ($oModeNode->getAttribute('id') === 'apply_stimulus')
{
$oStimuliNode = $oModeNode->GetOptionalElement('stimuli');
// if stimuli are defined, we overwrite the form that could have been set by the generic form
if ($oStimuliNode !== null)
{
/** @var \MFElement $oStimulusNode */
foreach ($oStimuliNode->GetNodes('stimulus') as $oStimulusNode)
{
$sStimulusCode = $oStimulusNode->getAttribute('id');
// If apply_stimulus mode, checking if stimuli are defined
if ($oModeNode->getAttribute('id') === 'apply_stimulus')
{
$oStimuliNode = $oModeNode->GetOptionalElement('stimuli');
// if stimuli are defined, we overwrite the form that could have been set by the generic form
if ($oStimuliNode !== null)
{
/** @var \MFElement $oStimulusNode */
foreach ($oStimuliNode->GetNodes('stimulus') as $oStimulusNode)
{
$sStimulusCode = $oStimulusNode->getAttribute('id');
// Removing default form is present (in case the default forms were parsed before the current one (from current or parent class))
if (isset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]))
{
unset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]);
}
// Removing default form is present (in case the default forms were parsed before the current one (from current or parent class))
if (isset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]))
{
unset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]);
}
$aFormStimuli[] = $oStimulusNode->getAttribute('id');
}
}
}
}
}
else
{
// If no mode was specified, we set it all but stimuli as it would have no sense that every transition forms
// have as many fields displayed as a regular edit form for example.
$aModes = array('view', 'edit', 'create');
}
$aFormStimuli[] = $oStimulusNode->getAttribute('id');
}
}
}
}
}
else
{
// If no mode was specified, we set it all but stimuli as it would have no sense that every transition forms
// have as many fields displayed as a regular edit form for example.
$aModes = array('view', 'edit', 'create');
}
// Parsing fields
$aFields = array(
'id' => $oFormNode->getAttribute('id'),
'type' => null,
'properties' => $aFormProperties,
'fields' => null,
'layout' => null,
);
// ... either enumerated fields ...
if ($oFormNode->GetOptionalElement('fields') !== null)
{
$aFields['type'] = 'custom_list';
$aFields['fields'] = array();
// Parsing fields
$aFields = array(
'id' => $oFormNode->getAttribute('id'),
'type' => null,
'properties' => $aFormProperties,
'fields' => null,
'layout' => null,
);
// ... either enumerated fields ...
if ($oFormNode->GetOptionalElement('fields') !== null)
{
$aFields['type'] = 'custom_list';
$aFields['fields'] = array();
/** @var \MFElement $oFieldNode */
foreach ($oFormNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode)
{
$sFieldId = $oFieldNode->getAttribute('id');
if ($sFieldId !== '')
{
$aField = array();
// Parsing field options like read_only, hidden and mandatory
if ($oFieldNode->GetOptionalElement('read_only'))
{
$aField['readonly'] = ($oFieldNode->GetOptionalElement('read_only')->GetText('true') === 'true') ? true : false;
}
if ($oFieldNode->GetOptionalElement('mandatory'))
{
$aField['mandatory'] = ($oFieldNode->GetOptionalElement('mandatory')->GetText('true') === 'true') ? true : false;
}
if ($oFieldNode->GetOptionalElement('hidden'))
{
$aField['hidden'] = ($oFieldNode->GetOptionalElement('hidden')->GetText('true') === 'true') ? true : false;
}
/** @var \MFElement $oFieldNode */
foreach ($oFormNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode)
{
$sFieldId = $oFieldNode->getAttribute('id');
if ($sFieldId !== '')
{
$aField = array();
// Parsing field options like read_only, hidden and mandatory
if ($oFieldNode->GetOptionalElement('read_only'))
{
$aField['readonly'] = ($oFieldNode->GetOptionalElement('read_only')->GetText('true') === 'true') ? true : false;
}
if ($oFieldNode->GetOptionalElement('mandatory'))
{
$aField['mandatory'] = ($oFieldNode->GetOptionalElement('mandatory')->GetText('true') === 'true') ? true : false;
}
if ($oFieldNode->GetOptionalElement('hidden'))
{
$aField['hidden'] = ($oFieldNode->GetOptionalElement('hidden')->GetText('true') === 'true') ? true : false;
}
$aFields['fields'][$sFieldId] = $aField;
}
else
{
throw new DOMFormatException('Field tag must have an id attribute', null, null,
$oFormNode);
}
}
}
// ... or the default zlist
else
{
$aFields['type'] = 'zlist';
$aFields['fields'] = 'details';
}
$aFields['fields'][$sFieldId] = $aField;
}
else
{
throw new DOMFormatException('Field tag must have an id attribute', null, null,
$oFormNode);
}
}
}
// ... or the default zlist
else
{
$aFields['type'] = 'zlist';
$aFields['fields'] = 'details';
}
// Parsing presentation
if ($oFormNode->GetOptionalElement('twig') !== null)
{
// Extracting the twig template and removing the first and last lines (twig tags)
$sXml = $this->GetModuleDesign()->saveXML($oFormNode->GetOptionalElement('twig'));
$sXml = preg_replace('/^.+\n/', '', $sXml);
$sXml = preg_replace('/\n.+$/', '', $sXml);
// Parsing presentation
if ($oFormNode->GetOptionalElement('twig') !== null)
{
// Extracting the twig template and removing the first and last lines (twig tags)
$sXml = $this->GetModuleDesign()->saveXML($oFormNode->GetOptionalElement('twig'));
$sXml = preg_replace('/^.+\n/', '', $sXml);
$sXml = preg_replace('/\n.+$/', '', $sXml);
$aFields['layout'] = array(
'type' => (preg_match('/\{\{|\{\#|\{\%/', $sXml) === 1) ? 'twig' : 'xhtml',
'content' => $sXml,
);
}
$aFields['layout'] = array(
'type' => (preg_match('/\{\{|\{\#|\{\%/', $sXml) === 1) ? 'twig' : 'xhtml',
'content' => $sXml,
);
}
// Adding form for each class / mode
foreach ($aModes as $sMode)
{
// Initializing current class if necessary
if (!isset($aForms[$sFormClass]))
{
$aForms[$sFormClass] = array();
}
// Adding form for each class / mode
foreach ($aModes as $sMode)
{
// Initializing current class if necessary
if (!isset($aForms[$sFormClass]))
{
$aForms[$sFormClass] = array();
}
if ($sMode === 'apply_stimulus')
{
// Iterating over current class and child classes to fill stimuli forms
foreach (MetaModel::EnumChildClasses($sFormClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass)
{
// Initializing child class if necessary
if (!isset($aForms[$sChildClass][$sMode]))
{
$aForms[$sChildClass][$sMode] = array();
}
if ($sMode === 'apply_stimulus')
{
// Iterating over current class and child classes to fill stimuli forms
foreach (MetaModel::EnumChildClasses($sFormClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass)
{
// Initializing child class if necessary
if (!isset($aForms[$sChildClass][$sMode]))
{
$aForms[$sChildClass][$sMode] = array();
}
// If stimuli are implicitly defined (empty tag), we define all those that have not already been by other forms.
$aChildStimuli = $aFormStimuli;
if (empty($aChildStimuli))
{
// Stimuli already declared
$aDeclaredStimuli = array();
if (array_key_exists($sChildClass, $aForms) && array_key_exists('apply_stimulus',
$aForms[$sChildClass]))
{
$aDeclaredStimuli = array_keys($aForms[$sChildClass]['apply_stimulus']);
}
// All stimuli
$aDatamodelStimuli = array_keys(MetaModel::EnumStimuli($sChildClass));
// Missing stimuli
$aChildStimuli = array_diff($aDatamodelStimuli, $aDeclaredStimuli);
}
// If stimuli are implicitly defined (empty tag), we define all those that have not already been by other forms.
$aChildStimuli = $aFormStimuli;
if (empty($aChildStimuli))
{
// Stimuli already declared
$aDeclaredStimuli = array();
if (array_key_exists($sChildClass, $aForms) && array_key_exists('apply_stimulus',
$aForms[$sChildClass]))
{
$aDeclaredStimuli = array_keys($aForms[$sChildClass]['apply_stimulus']);
}
// All stimuli
$aDatamodelStimuli = array_keys(MetaModel::EnumStimuli($sChildClass));
// Missing stimuli
$aChildStimuli = array_diff($aDatamodelStimuli, $aDeclaredStimuli);
}
foreach ($aChildStimuli as $sFormStimulus)
{
// Setting form if not defined OR if it was defined by a parent (abstract) class
if (!isset($aForms[$sChildClass][$sMode][$sFormStimulus]) || !empty($aFormStimuli))
{
$aForms[$sChildClass][$sMode][$sFormStimulus] = $aFields;
$aForms[$sChildClass][$sMode][$sFormStimulus]['id'] = 'apply_stimulus-'.$sChildClass.'-'.$sFormStimulus;
}
}
}
}
elseif (!isset($aForms[$sFormClass][$sMode]))
{
$aForms[$sFormClass][$sMode] = $aFields;
}
else
{
throw new DOMFormatException('There is already a form for the class "'.$sFormClass.'" in "'.$sMode.'"',
null, null, $oFormNode);
}
}
}
else
{
throw new DOMFormatException('Class tag must be defined', null, null, $oFormNode);
}
}
catch (DOMFormatException $e)
{
throw new Exception('Could not create from [id="'.$oFormNode->getAttribute('id').'"] from XML because of a DOM problem : '.$e->getMessage());
}
catch (Exception $e)
{
throw new Exception('Could not create from from XML : '.$oFormNode->Dump().' '.$e->getMessage());
}
}
foreach ($aChildStimuli as $sFormStimulus)
{
// Setting form if not defined OR if it was defined by a parent (abstract) class
if (!isset($aForms[$sChildClass][$sMode][$sFormStimulus]) || !empty($aFormStimuli))
{
$aForms[$sChildClass][$sMode][$sFormStimulus] = $aFields;
$aForms[$sChildClass][$sMode][$sFormStimulus]['id'] = 'apply_stimulus-'.$sChildClass.'-'.$sFormStimulus;
}
}
}
}
elseif (!isset($aForms[$sFormClass][$sMode]))
{
$aForms[$sFormClass][$sMode] = $aFields;
}
else
{
throw new DOMFormatException('There is already a form for the class "'.$sFormClass.'" in "'.$sMode.'"',
null, null, $oFormNode);
}
}
}
else
{
throw new DOMFormatException('Class tag must be defined', null, null, $oFormNode);
}
}
catch (DOMFormatException $e)
{
throw new Exception('Could not create from [id="'.$oFormNode->getAttribute('id').'"] from XML because of a DOM problem : '.$e->getMessage());
}
catch (Exception $e)
{
throw new Exception('Could not create from from XML : '.$oFormNode->Dump().' '.$e->getMessage());
}
}
$aPortalConf = $oContainer->getParameter('combodo.portal.instance.conf');
$aPortalConf['forms'] = $aForms;
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
$aPortalConf = $oContainer->getParameter('combodo.portal.instance.conf');
$aPortalConf['forms'] = $aForms;
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
}

View File

@@ -28,8 +28,8 @@ use Symfony\Component\DependencyInjection\Container;
* Class Lists
*
* @package Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class Lists extends AbstractConfiguration
{
@@ -38,75 +38,75 @@ class Lists extends AbstractConfiguration
*
* @throws \DOMFormatException
*/
public function Process(Container $oContainer)
{
$iDefaultItemRank = 0;
$aClassesLists = array();
public function Process(Container $oContainer)
{
$iDefaultItemRank = 0;
$aClassesLists = array();
// Parsing XML file
// - Each classes
/** @var \MFElement $oClassNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/classes/class') as $oClassNode)
{
$aClassLists = array();
$sClassId = $oClassNode->getAttribute('id');
if ($sClassId === null)
{
throw new DOMFormatException('Class tag must have an id attribute', null, null, $oClassNode);
}
// Parsing XML file
// - Each classes
/** @var \MFElement $oClassNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/classes/class') as $oClassNode)
{
$aClassLists = array();
$sClassId = $oClassNode->getAttribute('id');
if ($sClassId === null)
{
throw new DOMFormatException('Class tag must have an id attribute', null, null, $oClassNode);
}
// - Each lists
/** @var \MFElement $oListNode */
foreach ($oClassNode->GetNodes('./lists/list') as $oListNode)
{
$aListItems = array();
$sListId = $oListNode->getAttribute('id');
if ($sListId === null)
{
throw new DOMFormatException('List tag of "'.$sClassId.'" class must have an id attribute', null,
null, $oListNode);
}
// - Each lists
/** @var \MFElement $oListNode */
foreach ($oClassNode->GetNodes('./lists/list') as $oListNode)
{
$aListItems = array();
$sListId = $oListNode->getAttribute('id');
if ($sListId === null)
{
throw new DOMFormatException('List tag of "'.$sClassId.'" class must have an id attribute', null,
null, $oListNode);
}
// - Each items
/** @var \MFElement $oItemNode */
foreach ($oListNode->GetNodes('./items/item') as $oItemNode)
{
$sItemId = $oItemNode->getAttribute('id');
if ($sItemId === null)
{
throw new DOMFormatException('Item tag of "'.$sItemId.'" list must have an id attribute', null,
null, $oItemNode);
}
// - Each items
/** @var \MFElement $oItemNode */
foreach ($oListNode->GetNodes('./items/item') as $oItemNode)
{
$sItemId = $oItemNode->getAttribute('id');
if ($sItemId === null)
{
throw new DOMFormatException('Item tag of "'.$sItemId.'" list must have an id attribute', null,
null, $oItemNode);
}
$aItem = array(
'att_code' => $sItemId,
'rank' => $iDefaultItemRank,
);
$aItem = array(
'att_code' => $sItemId,
'rank' => $iDefaultItemRank,
);
$oRankNode = $oItemNode->GetOptionalElement('rank');
if ($oRankNode !== null)
{
$aItem['rank'] = $oRankNode->GetText($iDefaultItemRank);
}
$oRankNode = $oItemNode->GetOptionalElement('rank');
if ($oRankNode !== null)
{
$aItem['rank'] = $oRankNode->GetText($iDefaultItemRank);
}
$aListItems[] = $aItem;
}
// - Sorting list items by rank
usort($aListItems, function ($a, $b) {
return $a['rank'] > $b['rank'];
});
$aClassLists[$sListId] = $aListItems;
}
$aListItems[] = $aItem;
}
// - Sorting list items by rank
usort($aListItems, function ($a, $b) {
return $a['rank'] > $b['rank'];
});
$aClassLists[$sListId] = $aListItems;
}
// - Adding class only if it has at least one list
if (!empty($aClassLists))
{
$aClassesLists[$sClassId] = $aClassLists;
}
}
$aPortalConf = $oContainer->getParameter('combodo.portal.instance.conf');
$aPortalConf['lists'] = $aClassLists;
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
// - Adding class only if it has at least one list
if (!empty($aClassLists))
{
$aClassesLists[$sClassId] = $aClassLists;
}
}
$aPortalConf = $oContainer->getParameter('combodo.portal.instance.conf');
$aPortalConf['lists'] = $aClassLists;
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
}

View File

@@ -19,21 +19,21 @@
*
*/
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 04/03/19
* Time: 17:36
*/
namespace Combodo\iTop\Portal\EventListener;
use ApplicationContext;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
/**
* Class ApplicationContextSetUrlMakerClass
*
* @package Combodo\iTop\Portal\EventListener
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class ApplicationContextSetUrlMakerClass
{
/**
* @var array
*/
/** @var array $aCombodoPortalInstanceConf */
private $aCombodoPortalInstanceConf;
/**
@@ -44,11 +44,14 @@ class ApplicationContextSetUrlMakerClass
$this->aCombodoPortalInstanceConf = $aCombodoPortalInstanceConf;
}
/**
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $oGetResponseEvent
*/
public function onKernelRequest(GetResponseEvent $oGetResponseEvent)
{
if ($this->aCombodoPortalInstanceConf['properties']['urlmaker_class'] !== null)
{
\ApplicationContext::SetUrlMakerClass($this->aCombodoPortalInstanceConf['properties']['urlmaker_class']);
ApplicationContext::SetUrlMakerClass($this->aCombodoPortalInstanceConf['properties']['urlmaker_class']);
}
}
}

View File

@@ -25,7 +25,6 @@ use Exception;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use User;
use Dict;
use LoginWebPage;
use UserRights;
@@ -39,18 +38,18 @@ use ModuleDesign;
*/
class UserProvider implements ContainerAwareInterface
{
/** @var \ModuleDesign */
/** @var \ModuleDesign $oModuleDesign */
private $oModuleDesign;
/** @var string $sPortalId */
private $sPortalId;
/** @var \Symfony\Component\DependencyInjection\ContainerInterface */
private $container;
/** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
private $oContainer;
/**
* UserProvider constructor.
*
* @param \ModuleDesign $oModuleDesign
* @param \User $oUser
* @param string $sPortalId
*/
public function __construct(ModuleDesign $oModuleDesign, $sPortalId)
{
@@ -86,16 +85,16 @@ class UserProvider implements ContainerAwareInterface
{
throw new Exception('Could not load connected user.');
}
$this->container->set('combodo.current_user', $oUser);
$this->oContainer->set('combodo.current_user', $oUser);
}
/**
* Sets the container.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface|null $container
* @param \Symfony\Component\DependencyInjection\ContainerInterface|null $oContainer
*/
public function setContainer(ContainerInterface $container = null)
public function setContainer(ContainerInterface $oContainer = null)
{
$this->container = $container;
$this->oContainer = $oContainer;
}
}

View File

@@ -35,16 +35,17 @@ use Combodo\iTop\Form\Field\PasswordField;
* Description of PasswordFormManager
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @since 2.3.0
*/
class PasswordFormManager extends FormManager
{
/** @var string FORM_TYPE */
const FORM_TYPE = 'change_password';
/**
* @throws \Exception
*/
public function Build()
/**
* @throws \Exception
*/
public function Build()
{
// Building the form
$oForm = new Form('change_password');
@@ -75,23 +76,23 @@ class PasswordFormManager extends FormManager
$this->oRenderer->SetForm($this->oForm);
}
/**
* Validates the form and returns an array with the validation status and the messages.
* If the form is valid, creates/updates the object.
*
* eg :
* array(
* 'status' => true|false
* 'messages' => array(
* 'errors' => array()
* )
*
* @param array $aArgs
*
* @return array
*
* @throws \Exception
*/
/**
* Validates the form and returns an array with the validation status and the messages.
* If the form is valid, creates/updates the object.
*
* eg :
* array(
* 'status' => true|false
* 'messages' => array(
* 'errors' => array()
* )
*
* @param array $aArgs
*
* @return array
*
* @throws \Exception
*/
public function OnSubmit($aArgs = null)
{
$aData = array(
@@ -99,8 +100,8 @@ class PasswordFormManager extends FormManager
'messages' => array(
'success' => array(),
'warnings' => array(), // Not used as of today, just to show that the structure is ready for change like this.
'error' => array()
)
'error' => array(),
),
);
// Update object and form
@@ -117,32 +118,50 @@ class PasswordFormManager extends FormManager
$sOldPassword = $this->oForm->GetField('old_password')->GetCurrentValue();
$sNewPassword = $this->oForm->GetField('new_password')->GetCurrentValue();
$sConfirmPassword = $this->oForm->GetField('confirm_password')->GetCurrentValue();
if ($sOldPassword !== '' && $sNewPassword !== '' && $sConfirmPassword !== '')
{
if (!UserRights::CanChangePassword())
{
$aData['valid'] = false;
$aData['messages']['error'] += array('_main' => array(Dict::Format('Brick:Portal:UserProfile:Password:CantChangeContactAdministrator', ITOP_APPLICATION_SHORT)));
}
else if (!UserRights::CheckCredentials($sAuthUser, $sOldPassword))
{
$aData['valid'] = false;
$aData['messages']['error'] += array('old_password' => array(Dict::S('UI:Login:IncorrectOldPassword')));
}
else if ($sNewPassword !== $sConfirmPassword)
{
$aData['valid'] = false;
$aData['messages']['error'] += array('confirm_password' => array(Dict::S('UI:Login:RetypePwdDoesNotMatch')));
}
else if (!UserRights::ChangePassword($sOldPassword, $sNewPassword))
{
$aData['valid'] = false;
$aData['messages']['error'] += array('confirm_password' => array(Dict::Format('Brick:Portal:UserProfile:Password:CantChangeForUnknownReason', ITOP_APPLICATION_SHORT)));
$aData['messages']['error'] += array(
'_main' => array(
Dict::Format('Brick:Portal:UserProfile:Password:CantChangeContactAdministrator', ITOP_APPLICATION_SHORT),
),
);
}
else
{
$aData['messages']['success'] += array('_main' => array(Dict::S('Brick:Portal:Object:Form:Message:Saved')));
if (!UserRights::CheckCredentials($sAuthUser, $sOldPassword))
{
$aData['valid'] = false;
$aData['messages']['error'] += array('old_password' => array(Dict::S('UI:Login:IncorrectOldPassword')));
}
else
{
if ($sNewPassword !== $sConfirmPassword)
{
$aData['valid'] = false;
$aData['messages']['error'] += array('confirm_password' => array(Dict::S('UI:Login:RetypePwdDoesNotMatch')));
}
else
{
if (!UserRights::ChangePassword($sOldPassword, $sNewPassword))
{
$aData['valid'] = false;
$aData['messages']['error'] += array(
'confirm_password' => array(
Dict::Format('Brick:Portal:UserProfile:Password:CantChangeForUnknownReason',
ITOP_APPLICATION_SHORT),
),
);
}
else
{
$aData['messages']['success'] += array('_main' => array(Dict::S('Brick:Portal:Object:Form:Message:Saved')));
}
}
}
}
}
}
@@ -150,7 +169,7 @@ class PasswordFormManager extends FormManager
{
$aData['valid'] = false;
$aData['messages']['error'] += array('_main' => array($e->getMessage()));
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Exception during submit (' . $e->getMessage() . ')');
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Exception during submit ('.$e->getMessage().')');
}
}
else
@@ -159,16 +178,16 @@ class PasswordFormManager extends FormManager
$aData['valid'] = false;
$aData['messages']['error'] += $this->oForm->GetErrorMessages();
}
return $aData;
}
/**
* @param array $aArgs
*
* @throws \Exception
*/
public function OnUpdate($aArgs = null)
/**
* @param array $aArgs
*
* @throws \Exception
*/
public function OnUpdate($aArgs = null)
{
// We build the form
@@ -187,12 +206,12 @@ class PasswordFormManager extends FormManager
}
}
/**
* @param array $aArgs
*/
/**
* @param array $aArgs
*/
public function OnCancel($aArgs = null)
{
}
}

View File

@@ -36,16 +36,17 @@ use Combodo\iTop\Form\Field\SelectField;
* Description of PreferencesFormManager
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
* @since 2.3.0
*/
class PreferencesFormManager extends FormManager
{
/** @var string FORM_TYPE */
const FORM_TYPE = 'preferences';
/**
* @throws \Exception
*/
public function Build()
/**
* @throws \Exception
*/
public function Build()
{
// Building the form
$oForm = new Form('preferences');
@@ -65,7 +66,7 @@ class PreferencesFormManager extends FormManager
$aChoices = array();
foreach (Dict::GetLanguages() as $sCode => $aLanguage)
{
$aChoices[$sCode] = $aLanguage['description'] . ' (' . $aLanguage['localized_description'] . ')';
$aChoices[$sCode] = $aLanguage['description'].' ('.$aLanguage['localized_description'].')';
}
asort($aChoices);
$oField->SetChoices($aChoices);
@@ -77,25 +78,25 @@ class PreferencesFormManager extends FormManager
$this->oRenderer->SetForm($this->oForm);
}
/**
* Validates the form and returns an array with the validation status and the messages.
* If the form is valid, creates/updates the object.
*
* eg :
* array(
* 'status' => true|false
* 'messages' => array(
* 'errors' => array()
* )
*
* @param array $aArgs
*
* @return array
*
* @throws \Exception
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
/**
* Validates the form and returns an array with the validation status and the messages.
* If the form is valid, creates/updates the object.
*
* eg :
* array(
* 'status' => true|false
* 'messages' => array(
* 'errors' => array()
* )
*
* @param array $aArgs
*
* @return array
*
* @throws \Exception
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function OnSubmit($aArgs = null)
{
$aData = array(
@@ -103,8 +104,8 @@ class PreferencesFormManager extends FormManager
'messages' => array(
'success' => array(),
'warnings' => array(), // Not used as of today, just to show that the structure is ready for change like this.
'error' => array()
)
'error' => array(),
),
);
// Update object and form
@@ -130,7 +131,7 @@ class PreferencesFormManager extends FormManager
$oCurUser->Set('language', $sLanguage);
$iFieldChanged++;
}
// Updating only if preferences changed
if ($iFieldChanged > 0)
{
@@ -148,7 +149,7 @@ class PreferencesFormManager extends FormManager
CMDBSource::Query('ROLLBACK');
$aData['valid'] = false;
$aData['messages']['error'] += array('_main' => array($e->getMessage()));
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Rollback during submit (' . $e->getMessage() . ')');
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Rollback during submit ('.$e->getMessage().')');
}
}
else
@@ -157,16 +158,16 @@ class PreferencesFormManager extends FormManager
$aData['valid'] = false;
$aData['messages']['error'] += $this->oForm->GetErrorMessages();
}
return $aData;
}
/**
* @param array $aArgs
*
* @throws \Exception
*/
public function OnUpdate($aArgs = null)
/**
* @param array $aArgs
*
* @throws \Exception
*/
public function OnUpdate($aArgs = null)
{
// We build the form
@@ -185,12 +186,12 @@ class PreferencesFormManager extends FormManager
}
}
/**
* @param array $aArgs
*/
/**
* @param array $aArgs
*/
public function OnCancel($aArgs = null)
{
}
}

View File

@@ -22,52 +22,47 @@
namespace Combodo\iTop\Portal\Helper;
use ApplicationContext;
use cmdbAbstractObject;
use Combodo\iTop\Portal\Brick\AbstractBrick;
use Combodo\iTop\Portal\Brick\PortalBrick;
use DBObjectSearch;
use DBObjectSet;
use Dict;
use DOMFormatException;
use Exception;
use iPortalUIExtension;
use IssueLog;
use MetaModel;
use ModuleDesign;
use Silex\Application;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Twig_Environment;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
use UserRights;
use utils;
/**
* Contains static methods to help loading / registering classes of the application.
* Mostly used for Controllers / Routers / Entities initialization.
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class ApplicationHelper
{
/** @var string FORM_ENUM_DISPLAY_MODE_COSY */
const FORM_ENUM_DISPLAY_MODE_COSY = 'cosy';
/** @var string FORM_ENUM_DISPLAY_MODE_COMPACT */
const FORM_ENUM_DISPLAY_MODE_COMPACT = 'compact';
/** @var string FORM_DEFAULT_DISPLAY_MODE */
const FORM_DEFAULT_DISPLAY_MODE = self::FORM_ENUM_DISPLAY_MODE_COSY;
/** @var bool FORM_DEFAULT_ALWAYS_SHOW_SUBMIT */
const FORM_DEFAULT_ALWAYS_SHOW_SUBMIT = false;
/**
* Loads classes from the base portal
*
* @deprecated Since 2.7.0
*
* @param string $sScannedDir Directory to load the files from
* @param string $sScannedDir Directory to load the files from
* @param string $sFilePattern Pattern of files to load
* @param string $sType Type of files to load, used only in the Exception message, can be anything
* @param string $sType Type of files to load, used only in the Exception message, can be anything
*
* @throws \Exception
* @deprecated Since 2.7.0
*
*/
public static function LoadClasses($sScannedDir, $sFilePattern, $sType)
{
@@ -101,6 +96,8 @@ class ApplicationHelper
* Note : It is only active when $oApp['debug'] is false
*
* @param Application $oApp
*
* @todo
*/
public static function RegisterExceptionHandler(Application $oApp)
{
@@ -118,7 +115,7 @@ class ApplicationHelper
'exception' => $oException,
'code' => $iErrorCode,
'error_title' => '',
'error_message' => $oException->getMessage()
'error_message' => $oException->getMessage(),
);
switch ($iErrorCode)
@@ -264,6 +261,7 @@ class ApplicationHelper
*/
public static function GetLoadedFormFromClass($aForms, $sClass, $sMode)
{
$aForm = null;
// We try to find the form for that class
if (isset($aForms[$sClass]) && isset($aForms[$sClass][$sMode]))
@@ -364,7 +362,7 @@ class ApplicationHelper
* Form will look like the "Properties" tab of a $sClass object in the console.
*
* @param string $sClass
* @param bool $bAddLinksets
* @param bool $bAddLinksets
*
* @return array
*/
@@ -394,13 +392,13 @@ class ApplicationHelper
// Count cols (not linksets)
$iColCount = 0;
foreach($aPropertiesStruct as $sColId => $aColFieldsets)
foreach ($aPropertiesStruct as $sColId => $aColFieldsets)
{
if(substr($sColId, 0, 1) !== '_')
if (substr($sColId, 0, 1) !== '_')
{
foreach($aColFieldsets as $sFieldsetName => $aAttCodes)
foreach ($aColFieldsets as $sFieldsetName => $aAttCodes)
{
if(substr($sFieldsetName, 0, 1) !== '_')
if (substr($sFieldsetName, 0, 1) !== '_')
{
$iColCount++;
break;
@@ -409,32 +407,32 @@ class ApplicationHelper
}
}
// If no cols, return a default form with all fields one after another
if($iColCount === 0)
if ($iColCount === 0)
{
return array(
'id' => 'default',
'type' => 'zlist',
'fields' => 'details',
'layout' => null
'layout' => null,
);
}
// Warning, this might not be great when 12 modulo $iColCount is greater than 0.
$sColCSSClass = 'col-sm-'.floor(12/$iColCount);
$sColCSSClass = 'col-sm-'.floor(12 / $iColCount);
$sLinksetsHTML = "";
$sRowHTML = "<div class=\"row\">\n";
foreach($aPropertiesStruct as $sColId => $aColFieldsets)
foreach ($aPropertiesStruct as $sColId => $aColFieldsets)
{
$sColsHTML = "\t<div class=\"".$sColCSSClass."\">\n";
foreach($aColFieldsets as $sFieldsetName => $aAttCodes)
foreach ($aColFieldsets as $sFieldsetName => $aAttCodes)
{
// Add fieldset, not linkset
if(substr($sFieldsetName, 0, 1) !== '_')
if (substr($sFieldsetName, 0, 1) !== '_')
{
$sFieldsetHTML = "\t\t<fieldset>\n";
$sFieldsetHTML .= "\t\t\t<legend>".htmlentities(Dict::S($sFieldsetName), ENT_QUOTES, 'UTF-8')."</legend>\n";
foreach($aAttCodes as $sAttCode)
foreach ($aAttCodes as $sAttCode)
{
$sFieldsetHTML .= "\t\t\t<div class=\"form_field\" data-field-id=\"".$sAttCode."\"></div>\n";
}
@@ -444,9 +442,9 @@ class ApplicationHelper
// Add to col
$sColsHTML .= $sFieldsetHTML;
}
elseif($bAddLinksets)
elseif ($bAddLinksets)
{
foreach($aAttCodes as $sAttCode)
foreach ($aAttCodes as $sAttCode)
{
$sLinksetsHTML .= "<div class=\"form_field\" data-field-id=\"".$sAttCode."\"></div>\n";
}

View File

@@ -31,24 +31,26 @@ use Dict;
use MetaModel;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use UserRights;
use Combodo\iTop\Portal\Routing\UrlGenerator;
/**
* Class BrowseBrickHelper
*
* @package Combodo\iTop\Portal\Helper
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class BrowseBrickHelper
{
/** @var string LEVEL_SEPARATOR */
const LEVEL_SEPARATOR = '-';
/** @var array OPTIONAL_ATTRIBUTES */
const OPTIONAL_ATTRIBUTES = array('tooltip_att', 'description_att', 'image_att');
/**
* @var \Combodo\iTop\Portal\Helper\SecurityHelper
*/
/** @var \Combodo\iTop\Portal\Helper\SecurityHelper */
private $oSecurityHelper;
/**
* @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper
*/
/** @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper */
private $oScopeValidator;
/**
* @var \Combodo\iTop\Portal\Routing\UrlGenerator
*/
/** @var \Combodo\iTop\Portal\Routing\UrlGenerator */
private $oUrlGenerator;
/**
@@ -58,8 +60,8 @@ class BrowseBrickHelper
* @param \Combodo\iTop\Portal\Helper\ScopeValidatorHelper $oScopeValidator
* @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $oUrlGenerator
*/
public function __construct(SecurityHelper $oSecurityHelper, ScopeValidatorHelper $oScopeValidator, UrlGeneratorInterface $oUrlGenerator)
{
public function __construct(SecurityHelper $oSecurityHelper, ScopeValidatorHelper $oScopeValidator, UrlGeneratorInterface $oUrlGenerator
) {
$this->oSecurityHelper = $oSecurityHelper;
$this->oScopeValidator = $oScopeValidator;
$this->oUrlGenerator = $oUrlGenerator;
@@ -81,16 +83,18 @@ class BrowseBrickHelper
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \Exception
*/
public function TreeToFlatLevelsProperties(array $aLevels, array &$aLevelsProperties, $sLevelAliasPrefix = 'L')
{
foreach ($aLevels as $aLevel)
{
$sCurrentLevelAlias = $sLevelAliasPrefix . static::LEVEL_SEPARATOR . $aLevel['id'];
$sCurrentLevelAlias = $sLevelAliasPrefix.static::LEVEL_SEPARATOR.$aLevel['id'];
$oSearch = DBSearch::CloneWithAlias(DBSearch::FromOQL($aLevel['oql']), $sCurrentLevelAlias);
// Restricting to the allowed scope
$oScopeSearch = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $oSearch->GetClass(), UR_ACTION_READ);
$oScopeSearch = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $oSearch->GetClass(),
UR_ACTION_READ);
$oSearch = ($oScopeSearch !== null) ? $oSearch->Intersect($oScopeSearch) : null;
// - Allowing all data if necessary
if ($oScopeSearch !== null && $oScopeSearch->IsAllDataAllowed())
@@ -110,7 +114,7 @@ class BrowseBrickHelper
'image_att' => $aLevel['image_att'],
'search' => $oSearch,
'fields' => array(),
'actions' => array()
'actions' => array(),
);
// Adding current level's fields
@@ -123,24 +127,24 @@ class BrowseBrickHelper
$aLevelsProperties[$sCurrentLevelAlias]['fields'][] = array(
'code' => $sFieldAttCode,
'label' => MetaModel::GetAttributeDef($oSearch->GetClass(), $sFieldAttCode)->GetLabel(),
'hidden' => $aFieldProperties['hidden']
'hidden' => $aFieldProperties['hidden'],
);
}
}
// Flattening and adding sublevels
// Flattening and adding sub levels
if (isset($aLevel['levels']))
{
foreach ($aLevel['levels'] as $aChildLevel)
{
// Checking if the sublevel if allowed
// Checking if the sub level if allowed
$oChildSearch = DBSearch::FromOQL($aChildLevel['oql']);
if ($this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $oChildSearch->GetClass()))
{
// Adding the sublevel to this one
$aLevelsProperties[$sCurrentLevelAlias]['levels'][] = $sCurrentLevelAlias . static::LEVEL_SEPARATOR . $aChildLevel['id'];
// Adding the sub level to this one
$aLevelsProperties[$sCurrentLevelAlias]['levels'][] = $sCurrentLevelAlias.static::LEVEL_SEPARATOR.$aChildLevel['id'];
// Adding drilldown action if necessary
// Adding drill down action if necessary
foreach ($aLevel['actions'] as $sId => $aAction)
{
if ($aAction['type'] === BrowseBrick::ENUM_ACTION_DRILLDOWN)
@@ -162,11 +166,13 @@ class BrowseBrickHelper
if (!array_key_exists($sId, $aLevelsProperties[$sCurrentLevelAlias]['actions']))
{
// Adding action only if allowed
if (($aAction['type'] === BrowseBrick::ENUM_ACTION_VIEW) && !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $oSearch->GetClass()))
if (($aAction['type'] === BrowseBrick::ENUM_ACTION_VIEW) && !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ,
$oSearch->GetClass()))
{
continue;
}
elseif (($aAction['type'] === BrowseBrick::ENUM_ACTION_EDIT) && !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $oSearch->GetClass()))
elseif (($aAction['type'] === BrowseBrick::ENUM_ACTION_EDIT) && !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY,
$oSearch->GetClass()))
{
continue;
}
@@ -190,8 +196,10 @@ class BrowseBrickHelper
// We can only make translate a dictionnary entry with a class placeholder when the action has a class tag. if it has a factory method, we don't know yet what class is going to be created
if ($aAction['factory']['type'] === BrowseBrick::ENUM_FACTORY_TYPE_CLASS)
{
$aAction['title'] = Dict::Format('Brick:Portal:Browse:Action:CreateObjectFromThis', MetaModel::GetName($aAction['factory']['value']));
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create', array('sObjectClass' => $aAction['factory']['value']));
$aAction['title'] = Dict::Format('Brick:Portal:Browse:Action:CreateObjectFromThis',
MetaModel::GetName($aAction['factory']['value']));
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create',
array('sObjectClass' => $aAction['factory']['value']));
}
else
{
@@ -236,11 +244,16 @@ class BrowseBrickHelper
case BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS:
if ($aAction['factory']['type'] === BrowseBrick::ENUM_FACTORY_TYPE_CLASS)
{
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create', array('sObjectClass' => $aAction['factory']['value']));
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create',
array('sObjectClass' => $aAction['factory']['value']));
}
else
{
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create_from_factory', array('sEncodedMethodName' => base64_encode($aAction['factory']['value']), 'sObjectClass' => '-objectClass-', 'sObjectId' => '-objectId-'));
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create_from_factory', array(
'sEncodedMethodName' => base64_encode($aAction['factory']['value']),
'sObjectClass' => '-objectClass-',
'sObjectId' => '-objectId-',
));
}
break;
}
@@ -255,9 +268,9 @@ class BrowseBrickHelper
/**
* Prepares the action rules for an array of DBObject items.
*
* @param array $aItems
* @param array $aItems
* @param string $sLevelsAlias
* @param array $aLevelsProperties
* @param array $aLevelsProperties
*
* @return array
*/
@@ -298,11 +311,13 @@ class BrowseBrickHelper
*
* @throws \CoreException
* @throws \OQLException
* @throws \Exception
*/
public function AddToFlatItems(array $aCurrentRow, array &$aLevelsProperties)
{
$aRow = array();
/** @var \DBObject $value */
foreach ($aCurrentRow as $key => $value)
{
// Retrieving objects from all levels
@@ -313,18 +328,18 @@ class BrowseBrickHelper
'id' => $value->GetKey(),
'name' => $value->Get($aLevelsProperties[$key]['name_att']),
'class' => get_class($value),
'action_rules_token' => $this->PrepareActionRulesForItems($aItems, $key, $aLevelsProperties)
'action_rules_token' => $this->PrepareActionRulesForItems($aItems, $key, $aLevelsProperties),
);
// Adding optional attributes if necessary
foreach(static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
foreach (static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
{
if ($aLevelsProperties[$key][$sOptionalAttribute] !== null)
{
$sPropertyName = substr($sOptionalAttribute, 0, -4);
$oAttDef = MetaModel::GetAttributeDef(get_class($value), $aLevelsProperties[$key][$sOptionalAttribute]);
if($oAttDef instanceof AttributeImage)
if ($oAttDef instanceof AttributeImage)
{
$tmpAttValue = $value->Get($aLevelsProperties[$key][$sOptionalAttribute]);
if ($sOptionalAttribute === 'image_att')
@@ -335,7 +350,7 @@ class BrowseBrickHelper
'sObjectClass' => get_class($value),
'sObjectId' => $value->GetKey(),
'sObjectField' => $aLevelsProperties[$key][$sOptionalAttribute],
'cache' => 86400
'cache' => 86400,
));
}
else
@@ -360,7 +375,6 @@ class BrowseBrickHelper
{
$oAttDef = MetaModel::GetAttributeDef(get_class($value), $aField['code']);
$sHtmlForFieldValue = '';
switch (get_class($oAttDef))
{
case 'AttributeTagSet':
@@ -420,11 +434,12 @@ class BrowseBrickHelper
{
$aCurrentRowKeys = array_keys($aCurrentRow);
$aCurrentRowValues = array_values($aCurrentRow);
$sCurrentIndex = $aCurrentRowKeys[0] . '::' . $aCurrentRowValues[0]->GetKey();
/** @var \DBObject[] $aCurrentRowValues */
$sCurrentIndex = $aCurrentRowKeys[0].'::'.$aCurrentRowValues[0]->GetKey();
// We make sure to keep all row objects through levels by copying them when processing the first level.
// Otherwise they will be sliced through levels, one by one.
if($aCurrentRowObjects === null)
if ($aCurrentRowObjects === null)
{
$aCurrentRowObjects = $aCurrentRowValues;
}
@@ -437,25 +452,31 @@ class BrowseBrickHelper
'name' => $aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]]['name_att']),
'class' => get_class($aCurrentRowValues[0]),
'subitems' => array(),
'action_rules_token' => $this->PrepareActionRulesForItems($aCurrentRowObjects, $aCurrentRowKeys[0], $aLevelsProperties)
'action_rules_token' => $this->PrepareActionRulesForItems($aCurrentRowObjects, $aCurrentRowKeys[0], $aLevelsProperties),
);
// Adding optional attributes if necessary
foreach(static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
foreach (static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
{
if ($aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute] !== null)
{
$sPropertyName = substr($sOptionalAttribute, 0, -4);
$oAttDef = MetaModel::GetAttributeDef(get_class($aCurrentRowValues[0]), $aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute]);
$oAttDef = MetaModel::GetAttributeDef(get_class($aCurrentRowValues[0]),
$aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute]);
if($oAttDef instanceof AttributeImage)
if ($oAttDef instanceof AttributeImage)
{
$tmpAttValue = $aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute]);
if($sOptionalAttribute === 'image_att')
if ($sOptionalAttribute === 'image_att')
{
if (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty())
{
$tmpAttValue = $this->oUrlGenerator->generate('p_object_document_display', array('sObjectClass' => get_class($aCurrentRowValues[0]), 'sObjectId' => $aCurrentRowValues[0]->GetKey(), 'sObjectField' => $aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute], 'cache' => 86400));
$tmpAttValue = $this->oUrlGenerator->generate('p_object_document_display', array(
'sObjectClass' => get_class($aCurrentRowValues[0]),
'sObjectId' => $aCurrentRowValues[0]->GetKey(),
'sObjectField' => $aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute],
'cache' => 86400,
));
}
else
{

View File

@@ -36,52 +36,64 @@ use BinaryExpression;
use FieldExpression;
use ScalarExpression;
/**
* Class ContextManipulatorHelper
*
* @package Combodo\iTop\Portal\Helper
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class ContextManipulatorHelper
{
/** @var string ENUM_RULE_CALLBACK_BACK */
const ENUM_RULE_CALLBACK_BACK = 'back';
/** @var string ENUM_RULE_CALLBACK_GOTO */
const ENUM_RULE_CALLBACK_GOTO = 'goto';
/** @var string ENUM_RULE_CALLBACK_OPEN */
const ENUM_RULE_CALLBACK_OPEN = 'open';
/** @var string ENUM_RULE_CALLBACK_OPEN_VIEW */
const ENUM_RULE_CALLBACK_OPEN_VIEW = 'view';
/** @var string ENUM_RULE_CALLBACK_OPEN_EDIT */
const ENUM_RULE_CALLBACK_OPEN_EDIT = 'edit';
/** @var string DEFAULT_RULE_CALLBACK_OPEN */
const DEFAULT_RULE_CALLBACK_OPEN = self::ENUM_RULE_CALLBACK_OPEN_VIEW;
/** @var array $aRules */
protected $aRules;
/** @var \Symfony\Component\Routing\RouterInterface */
private $oRouter;
/** @var \Combodo\iTop\Portal\Brick\BrickCollection */
private $oBrickCollection;
/**
* @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper
*/
private $oScopeValidator;
/** @var \Symfony\Component\Routing\RouterInterface */
private $oRouter;
/** @var \Combodo\iTop\Portal\Brick\BrickCollection */
private $oBrickCollection;
/** @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper */
private $oScopeValidator;
/**
* ContextManipulatorHelper constructor.
*
* @param \ModuleDesign $oModuleDesign
* @param \Symfony\Component\Routing\RouterInterface $oRouter
* @param \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection
* @param \ModuleDesign $oModuleDesign
* @param \Symfony\Component\Routing\RouterInterface $oRouter
* @param \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection
* @param \Combodo\iTop\Portal\Helper\ScopeValidatorHelper $oScopeValidator
*
* @throws \DOMFormatException
*/
public function __construct(ModuleDesign $oModuleDesign, RouterInterface $oRouter, BrickCollection $oBrickCollection, ScopeValidatorHelper $oScopeValidator)
{
public function __construct(
ModuleDesign $oModuleDesign, RouterInterface $oRouter, BrickCollection $oBrickCollection, ScopeValidatorHelper $oScopeValidator
) {
$this->aRules = array();
$this->oRouter = $oRouter;
$this->oBrickCollection = $oBrickCollection;
$this->oRouter = $oRouter;
$this->oBrickCollection = $oBrickCollection;
$this->Init($oModuleDesign->GetNodes('/module_design/action_rules/action_rule'));
$this->oScopeValidator = $oScopeValidator;
}
$this->Init($oModuleDesign->GetNodes('/module_design/action_rules/action_rule'));
$this->oScopeValidator = $oScopeValidator;
}
/**
* Initializes the ScopeValidator by generating and caching the scopes compilation in the $this->sCachePath.$this->sFilename file.
*
* @param \DOMNodeList $oNodes
*
* @throws \Exception
*
* @throws \Exception
* @throws \DOMFormatException
*/
public function Init(DOMNodeList $oNodes)
@@ -89,7 +101,8 @@ class ContextManipulatorHelper
$this->aRules = array();
// Iterating over the scope nodes
foreach ($oNodes as $oRuleNode)
/** @var \Combodo\iTop\DesignElement $oRuleNode */
foreach ($oNodes as $oRuleNode)
{
// Retrieving mandatory id attribute
$sRuleId = $oRuleNode->getAttribute('id');
@@ -107,17 +120,18 @@ class ContextManipulatorHelper
'preset' => array(),
'retrofit' => array(),
'submit' => null,
'cancel' => null
'cancel' => null,
);
// Iterating over the rule's nodes
/** @var \Combodo\iTop\DesignElement $oSubNode */
foreach ($oRuleNode->childNodes as $oSubNode)
{
$sSubNodeName = $oSubNode->nodeName;
switch ($sSubNodeName)
{
case 'source_class':
$aRule['source_oql'] = 'SELECT ' . $oSubNode->GetText();
$aRule['source_oql'] = 'SELECT '.$oSubNode->GetText();
break;
case 'source_oql':
@@ -127,6 +141,7 @@ class ContextManipulatorHelper
case 'presets':
case 'retrofits':
/** @var \Combodo\iTop\DesignElement $oActionNode */
foreach ($oSubNode->childNodes as $oActionNode)
{
// Note : Caution, the index of $aRule is now $oActionNode->nodeName instead of $sSubNodeName, as we want to match iTopObjectCopier specs like told previously
@@ -150,11 +165,11 @@ class ContextManipulatorHelper
$sType = $oSubNode->getAttribute('xsi:type');
if ($sType === '')
{
throw new DOMFormatException($sSubNodeName . ' must have an xsi:type attribute.', null, null, $oSubNode);
throw new DOMFormatException($sSubNodeName.' must have an xsi:type attribute.', null, null, $oSubNode);
}
if (($sType === static::ENUM_RULE_CALLBACK_OPEN) && ($sSubNodeName === 'cancel'))
{
throw new DOMFormatException('Cancel tag cannot be of type ' . $sType . '.', null, null, $oSubNode);
throw new DOMFormatException('Cancel tag cannot be of type '.$sType.'.', null, null, $oSubNode);
}
$aRule[$sSubNodeName] = array('type' => $sType);
@@ -220,47 +235,48 @@ class ContextManipulatorHelper
return $this->aRules;
}
/**
* Return the rule identified by its ID, as a hash array
*
* @param string $sId
*
* @return array
* @throws \Exception
*/
/**
* Return the rule identified by its ID, as a hash array
*
* @param string $sId
*
* @return array
* @throws \Exception
*/
public function GetRule($sId)
{
if (!array_key_exists($sId, $this->aRules))
{
throw new Exception('Context creator : Could not find "' . $sId . '" in the rules list');
throw new Exception('Context creator : Could not find "'.$sId.'" in the rules list');
}
return $this->aRules[$sId];
}
/**
* Prepare the $oObject passed as a reference with the $aData
*
* $aData must be of the form :
* array(
* 'rules' => array(
* 'rule-id-1',
* 'rule-id-2',
* ...
* ),
* 'sources' => array(
* <DBObject1 class> => <DBObject1 id>,
* <DBObject2 class> => <DBObject2 id>,
* ...
* )
* )
*
* @param array $aData
* @param \DBObject $oObject
*
* @throws \Exception
* @throws \CoreException
* @throws \OQLException
*/
/**
* Prepare the $oObject passed as a reference with the $aData
*
* $aData must be of the form :
* array(
* 'rules' => array(
* 'rule-id-1',
* 'rule-id-2',
* ...
* ),
* 'sources' => array(
* <DBObject1 class> => <DBObject1 id>,
* <DBObject2 class> => <DBObject2 id>,
* ...
* )
* )
*
* @param array $aData
* @param \DBObject $oObject
*
* @throws \Exception
* @throws \CoreException
* @throws \OQLException
*/
public function PrepareObject(array $aData, DBObject &$oObject)
{
if (isset($aData['rules']) && isset($aData['sources']))
@@ -289,7 +305,7 @@ class ContextManipulatorHelper
{
if (is_array($sourceId))
{
throw new Exception('Context creator : ":id" parameter in rule "' . $sId . '" cannot be an array (This is a limitation of DBSearch)');
throw new Exception('Context creator : ":id" parameter in rule "'.$sId.'" cannot be an array (This is a limitation of DBSearch)');
}
$aSearchParams['id'] = $sourceId;
@@ -306,7 +322,8 @@ class ContextManipulatorHelper
for ($i = 0; $i < $iLoopMax; $i++)
{
// - Building full search expression
$oBinExpr = new BinaryExpression(new FieldExpression('id', $oSearch->GetClassAlias()), '=', new ScalarExpression($sourceId[$i]));
$oBinExpr = new BinaryExpression(new FieldExpression('id', $oSearch->GetClassAlias()), '=',
new ScalarExpression($sourceId[$i]));
if ($i === 0)
{
$oFullBinExpr = $oBinExpr;
@@ -326,7 +343,8 @@ class ContextManipulatorHelper
}
// Checking for silos
$oScopeSearch = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sSearchClass, UR_ACTION_READ);
$oScopeSearch = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sSearchClass,
UR_ACTION_READ);
if ($oScopeSearch->IsAllDataAllowed())
{
$oSearch->AllowAllData();
@@ -364,28 +382,28 @@ class ContextManipulatorHelper
}
}
/**
* Returns a hash array of urls for each type of callback
*
* eg :
* array(
* 'submit' => 'http://localhost/',
* 'cancel' => null
* );
*
* @param array $aData
* @param \DBObject $oObject
* @param boolean $bModal
*
* @return array
*
* @throws \Exception
*/
/**
* Returns a hash array of urls for each type of callback
*
* eg :
* array(
* 'submit' => 'http://localhost/',
* 'cancel' => null
* );
*
* @param array $aData
* @param \DBObject $oObject
* @param boolean $bModal
*
* @return array
*
* @throws \Exception
*/
public function GetCallbackUrls(array $aData, DBObject $oObject, $bModal = false)
{
$aResults = array(
'submit' => null,
'cancel' => null
'cancel' => null,
);
if (isset($aData['rules']))
@@ -417,7 +435,8 @@ class ContextManipulatorHelper
break;
case static::ENUM_RULE_CALLBACK_OPEN:
$sCallbackUrl = ($oObject->IsNew()) ? null : $this->oRouter->generate('p_object_' . $aRule[$sCallbackName]['mode'], array('sObjectClass' => get_class($oObject), 'sObjectId' => $oObject->GetKey()));
$sCallbackUrl = ($oObject->IsNew()) ? null : $this->oRouter->generate('p_object_'.$aRule[$sCallbackName]['mode'],
array('sObjectClass' => get_class($oObject), 'sObjectId' => $oObject->GetKey()));
break;
}
@@ -430,30 +449,31 @@ class ContextManipulatorHelper
return $aResults;
}
/**
* Prepares the rules as an array of rules and source objects so it can be tokenised
*
* @param array $aRules
* @param array $aObjects
* @return array
*/
/**
* Prepares the rules as an array of rules and source objects so it can be tokenised
*
* @param array $aRules
* @param array $aObjects
*
* @return array
*/
public static function PrepareRulesForToken($aRules, $aObjects = array())
{
// Getting necessary information from objects
$aSources = array();
foreach ($aObjects as $oObject)
{
$aSources[get_class($oObject)] = $oObject->GetKey();
}
{
// Getting necessary information from objects
$aSources = array();
foreach ($aObjects as $oObject)
{
$aSources[get_class($oObject)] = $oObject->GetKey();
}
// Preparing data
$aTokenRules = array(
'rules' => $aRules,
'sources' => $aSources
);
// Preparing data
$aTokenRules = array(
'rules' => $aRules,
'sources' => $aSources,
);
return $aTokenRules;
}
return $aTokenRules;
}
/**
* Encodes a token made out of the rules.
@@ -463,33 +483,35 @@ class ContextManipulatorHelper
* To retrieve it has
*
* @param array $aTokenRules
*
*
* @return string
*/
public static function EncodeRulesToken($aTokenRules)
{
// Returning tokenised data
// Returning tokenised data
return base64_encode(json_encode($aTokenRules));
}
/**
* @param array $aRules
* @param array $aObjects
* @return string
*/
/**
* @param array $aRules
* @param array $aObjects
*
* @return string
*/
public static function PrepareAndEncodeRulesToken($aRules, $aObjects = array())
{
// Preparing rules before making a token
$aTokenRules = static::PrepareRulesForToken($aRules, $aObjects);
{
// Preparing rules before making a token
$aTokenRules = static::PrepareRulesForToken($aRules, $aObjects);
// Returning tokenised data
return static::EncodeRulesToken($aTokenRules);
}
// Returning tokenised data
return static::EncodeRulesToken($aTokenRules);
}
/**
* Decodes a token made out of the rules
*
* @param string $sToken
*
* @return array
*/
public static function DecodeRulesToken($sToken)

View File

@@ -25,21 +25,44 @@ namespace Combodo\iTop\Portal\Helper;
use Exception;
use DOMNodeList;
use DOMFormatException;
use ModuleDesign;
use utils;
use ProfilesConfig;
use MetaModel;
/**
* Class LifecycleValidatorHelper
*
* @package Combodo\iTop\Portal\Helper
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class LifecycleValidatorHelper
{
/** @var string DEFAULT_GENERATED_CLASS */
const DEFAULT_GENERATED_CLASS = 'PortalLifecycleValues';
/** @var string|null $sCachePath */
protected $sCachePath;
/** @var string $sFilename */
protected $sFilename;
/** @var string $sInstancePrefix */
protected $sInstancePrefix;
/** @var string $sGeneratedClass */
protected $sGeneratedClass;
/** @var array $aProfilesMatrix */
protected $aProfilesMatrix;
public function __construct(\ModuleDesign $moduleDesign, $sPortalId, $sPortalCachePath = null)
/**
* LifecycleValidatorHelper constructor.
*
* @param \ModuleDesign $moduleDesign
* @param string $sPortalId
* @param string|null $sPortalCachePath
*
* @throws \DOMFormatException
*/
public function __construct(ModuleDesign $moduleDesign, $sPortalId, $sPortalCachePath = null)
{
$this->sFilename = "{$sPortalId}.lifecycle.php";
$this->sCachePath = $sPortalCachePath;
@@ -47,7 +70,7 @@ class LifecycleValidatorHelper
$this->sGeneratedClass = static::DEFAULT_GENERATED_CLASS;
$this->aProfilesMatrix = array();
$this->Init($moduleDesign->GetNodes('/module_design/classes/class'));
$this->Init($moduleDesign->GetNodes('/module_design/classes/class'));
}
/**
@@ -96,7 +119,7 @@ class LifecycleValidatorHelper
* This is used to create a unique lifecycle values class in the cache directory (/data/cache-<ENV>) as there can be several instance of the portal.
*
* @param string $sInstancePrefix
*
*
* @return \Combodo\iTop\Portal\Helper\LifecycleValidatorHelper
*/
public function SetInstancePrefix($sInstancePrefix)
@@ -106,7 +129,8 @@ class LifecycleValidatorHelper
$sInstancePrefix = str_replace(' ', '', $sInstancePrefix);
$this->sInstancePrefix = $sInstancePrefix;
$this->sGeneratedClass = $this->sInstancePrefix . static::DEFAULT_GENERATED_CLASS;
$this->sGeneratedClass = $this->sInstancePrefix.static::DEFAULT_GENERATED_CLASS;
return $this;
}
@@ -114,7 +138,7 @@ class LifecycleValidatorHelper
* Initializes the LifecycleValidator by generating and caching the lifecycles compilation in the $this->sCachePath.$this->sFilename file.
*
* @param \DOMNodeList $oNodes
*
*
* @throws \DOMFormatException
* @throws \Exception
*/
@@ -126,7 +150,7 @@ class LifecycleValidatorHelper
$this->sCachePath = utils::GetCachePath();
}
// Building full pathname for file
$sFilePath = $this->sCachePath . $this->sFilename;
$sFilePath = $this->sCachePath.$this->sFilename;
// Creating file if not existing
// Note: This is a temporary cache system, it should soon evolve to a cache provider (fs, apc, memcache, ...)
@@ -137,7 +161,8 @@ class LifecycleValidatorHelper
// This will be used to know which classes have been set, so we can set the missing ones.
$aProfileClasses = array();
// Iterating over the class nodes
foreach ($oNodes as $oClassNode)
/** @var \Combodo\iTop\DesignElement $oClassNode */
foreach ($oNodes as $oClassNode)
{
// Retrieving mandatory class id attribute
$sClass = $oClassNode->getAttribute('id');
@@ -147,78 +172,80 @@ class LifecycleValidatorHelper
}
// Retrieving lifecycle node of the class
$oLifecycleNode = $oClassNode->GetOptionalElement('lifecycle');
if($oLifecycleNode !== null)
{
// Iterating over scope nodes of the class
$oStimuliNode = $oLifecycleNode->GetOptionalElement('stimuli');
if ($oStimuliNode !== null)
{
foreach ($oStimuliNode->GetNodes('./stimulus') as $oStimulusNode)
{
// Retrieving mandatory scope id attribute
$sStimulusId = $oStimulusNode->getAttribute('id');
if ($sStimulusId === '')
{
throw new DOMFormatException('Stimulus tag must have an id attribute.', null, null, $oStimulusNode);
}
$oLifecycleNode = $oClassNode->GetOptionalElement('lifecycle');
if ($oLifecycleNode !== null)
{
// Iterating over scope nodes of the class
$oStimuliNode = $oLifecycleNode->GetOptionalElement('stimuli');
if ($oStimuliNode !== null)
{
/** @var \Combodo\iTop\DesignElement $oStimulusNode */
foreach ($oStimuliNode->GetNodes('./stimulus') as $oStimulusNode)
{
// Retrieving mandatory scope id attribute
$sStimulusId = $oStimulusNode->getAttribute('id');
if ($sStimulusId === '')
{
throw new DOMFormatException('Stimulus tag must have an id attribute.', null, null, $oStimulusNode);
}
// Retrieving profiles for the stimulus
$oProfilesNode = $oStimulusNode->GetOptionalElement('denied_profiles');
$aProfilesNames = array();
// If no profile is specified, we consider that it's for ALL the profiles
if (($oProfilesNode === null) || ($oProfilesNode->GetNodes('./denied_profile')->length === 0))
{
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue)
{
$aProfilesNames[] = $aValue['name'];
}
}
else
{
foreach ($oProfilesNode->GetNodes('./denied_profile') as $oProfileNode)
{
// Retrieving mandatory profile id attribute
$sProfileId = $oProfileNode->getAttribute('id');
if ($sProfileId === '')
{
throw new DOMFormatException('Profile tag must have an id attribute.', null, null, $oProfileNode);
}
$aProfilesNames[] = $sProfileId;
}
}
// Retrieving profiles for the stimulus
$oProfilesNode = $oStimulusNode->GetOptionalElement('denied_profiles');
$aProfilesNames = array();
// If no profile is specified, we consider that it's for ALL the profiles
if (($oProfilesNode === null) || ($oProfilesNode->GetNodes('./denied_profile')->length === 0))
{
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue)
{
$aProfilesNames[] = $aValue['name'];
}
}
else
{
/** @var \Combodo\iTop\DesignElement $oProfileNode */
foreach ($oProfilesNode->GetNodes('./denied_profile') as $oProfileNode)
{
// Retrieving mandatory profile id attribute
$sProfileId = $oProfileNode->getAttribute('id');
if ($sProfileId === '')
{
throw new DOMFormatException('Profile tag must have an id attribute.', null, null, $oProfileNode);
}
$aProfilesNames[] = $sProfileId;
}
}
//
foreach ($aProfilesNames as $sProfileName)
{
// Stimulus profile id
$iProfileId = $this->GetProfileIdFromProfileName($sProfileName);
//
foreach ($aProfilesNames as $sProfileName)
{
// Stimulus profile id
$iProfileId = $this->GetProfileIdFromProfileName($sProfileName);
// Now that we have the queries infos, we are going to build the queries for that profile / class
$sMatrixPrefix = $iProfileId . '_' . $sClass;
// - Creating profile / class entry if not already present
if(!array_key_exists($sMatrixPrefix, $aProfiles))
{
$aProfiles[$sMatrixPrefix] = array();
}
// - Adding stimulus if not already present
if(!in_array($sStimulusId, $aProfiles[$sMatrixPrefix]))
{
$aProfiles[$sMatrixPrefix][] = $sStimulusId;
}
}
}
// Now that we have the queries infos, we are going to build the queries for that profile / class
$sMatrixPrefix = $iProfileId.'_'.$sClass;
// - Creating profile / class entry if not already present
if (!array_key_exists($sMatrixPrefix, $aProfiles))
{
$aProfiles[$sMatrixPrefix] = array();
}
// - Adding stimulus if not already present
if (!in_array($sStimulusId, $aProfiles[$sMatrixPrefix]))
{
$aProfiles[$sMatrixPrefix][] = $sStimulusId;
}
}
}
$aProfileClasses[] = $sClass;
}
}
$aProfileClasses[] = $sClass;
}
}
}
// Filling the array with missing classes from MetaModel, so we can have an inheritance principle on the stimuli
// For each class explicitly given in the stimuli, we check if its child classes were also in the stimuli :
// If not, we add them
//
// Note: Classes / Stimuli not in the matrix are implicitly ALLOWED. That can happen by omitting the <lifecycle> in a <class>
//
// Note: Classes / Stimuli not in the matrix are implicitly ALLOWED. That can happen by omitting the <lifecycle> in a <class>
foreach ($aProfileClasses as $sProfileClass)
{
foreach (MetaModel::EnumChildClasses($sProfileClass) as $sChildClass)
@@ -230,11 +257,11 @@ class LifecycleValidatorHelper
{
$iProfileId = $iKey;
// If the current profile has scope for that class in that mode, we duplicate it
if (isset($aProfiles[$iProfileId . '_' . $sProfileClass]))
{
$aProfiles[$iProfileId . '_' . $sChildClass] = $aProfiles[$iProfileId . '_' . $sProfileClass];
}
// If the current profile has scope for that class in that mode, we duplicate it
if (isset($aProfiles[$iProfileId.'_'.$sProfileClass]))
{
$aProfiles[$iProfileId.'_'.$sChildClass] = $aProfiles[$iProfileId.'_'.$sProfileClass];
}
}
}
}
@@ -262,63 +289,63 @@ class LifecycleValidatorHelper
if (!class_exists($this->sGeneratedClass))
{
require_once $this->sCachePath . $this->sFilename;
require_once $this->sCachePath.$this->sFilename;
}
}
/**
* Returns an array of available stimuli for the $sProfile for the class $sClass
*
* @param string $sProfile
* @param string $sClass
*
* @return \DBSearch
*
* @throws \Exception
*/
/**
* Returns an array of available stimuli for the $sProfile for the class $sClass
*
* @param string $sProfile
* @param string $sClass
*
* @return array
*
* @throws \Exception
*/
public function GetStimuliForProfile($sProfile, $sClass)
{
return $this->GetStimuliForProfiles(array($sProfile), $sClass);
}
/**
* Returns an array of available stimuli for the $aProfiles for the class $sClass.
* Profiles are a OR condition.
*
* @param array $aProfiles
* @param string $sClass
*
* @return \DBSearch
*
* @throws \Exception
*/
/**
* Returns an array of available stimuli for the $aProfiles for the class $sClass.
* Profiles are a OR condition.
*
* @param array $aProfiles
* @param string $sClass
*
* @return array
*
* @throws \Exception
*/
public function GetStimuliForProfiles($aProfiles, $sClass)
{
$aStimuli = array();
// Preparing available stimuli
foreach(MetaModel::EnumStimuli($sClass) as $sStimulusCode => $aData)
{
$aStimuli[$sStimulusCode] = true;
}
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $aData)
{
$aStimuli[$sStimulusCode] = true;
}
// Iterating on profiles to retrieving the different OQLs parts
foreach ($aProfiles as $sProfile)
{
// Retrieving matrix informtions
// Retrieving matrix information
$iProfileId = $this->GetProfileIdFromProfileName($sProfile);
// Retrieving profile stimuli
$sLifecycleValuesClass = $this->sGeneratedClass;
$aProfileMatrix = $sLifecycleValuesClass::GetProfileStimuli($iProfileId, $sClass);
foreach($aProfileMatrix as $sStimulusCode)
{
if(array_key_exists($sStimulusCode, $aStimuli))
{
unset($aStimuli[$sStimulusCode]);
}
}
foreach ($aProfileMatrix as $sStimulusCode)
{
if (array_key_exists($sStimulusCode, $aStimuli))
{
unset($aStimuli[$sStimulusCode]);
}
}
}
return array_keys($aStimuli);
@@ -328,9 +355,9 @@ class LifecycleValidatorHelper
* Returns the profile id from a string being either a constant or its name.
*
* @param string $sProfile
*
*
* @return integer
*
*
* @throws \Exception
*/
protected function GetProfileIdFromProfileName($sProfile)
@@ -366,7 +393,7 @@ class LifecycleValidatorHelper
// If profile was not found from its name or from a constant, we throw an exception
if ($iProfileId === null)
{
throw new Exception('Lifecycle validator : Could not find "' . $sProfile . '" in the profiles list');
throw new Exception('Lifecycle validator : Could not find "'.$sProfile.'" in the profiles list');
}
return $iProfileId;
@@ -376,7 +403,7 @@ class LifecycleValidatorHelper
* Returns a string containing the generated PHP class for the compiled scopes
*
* @param array $aProfiles
*
*
* @return string
*/
protected function BuildPHPClass($aProfiles = array())
@@ -417,6 +444,7 @@ class $sClassName
}
EOF;
return $sPHP;
}

View File

@@ -46,13 +46,16 @@ use UserRights;
* Class ObjectFormHandlerHelper
*
* @package Combodo\iTop\Portal\Helper
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.7.0
*/
class ObjectFormHandlerHelper
{
/** @var string ENUM_MODE_VIEW */
const ENUM_MODE_VIEW = 'view';
/** @var string ENUM_MODE_EDIT */
const ENUM_MODE_EDIT = 'edit';
/** @var string ENUM_MODE_CREATE */
const ENUM_MODE_CREATE = 'create';
/** @var \Combodo\iTop\Portal\Helper\RequestManipulatorHelper */
@@ -145,8 +148,10 @@ class ObjectFormHandlerHelper
// Retrieve action rules information to auto-fill the form if available
// Preparing object
$this->oContextManipulator->PrepareObject($aActionRules, $oObject);
$aPrefillFormParam = array( 'user' => $_SESSION["auth_user"],
'origin' => 'portal');
$aPrefillFormParam = array(
'user' => $_SESSION["auth_user"],
'origin' => 'portal',
);
$oObject->PrefillForm('creation_from_0', $aPrefillFormParam);
}
else
@@ -170,7 +175,7 @@ class ObjectFormHandlerHelper
$aStimuli = Metamodel::EnumStimuli($sObjectClass);
foreach ($oObject->EnumTransitions() as $sStimulusCode => $aTransitionDef)
{
if($this->oSecurityHelper->IsStimulusAllowed($sStimulusCode, $sObjectClass, $oSetToCheckRights))
if ($this->oSecurityHelper->IsStimulusAllowed($sStimulusCode, $sObjectClass, $oSetToCheckRights))
{
$aFormData['buttons']['transitions'][$sStimulusCode] = $aStimuli[$sStimulusCode]->GetLabel();
}
@@ -180,15 +185,15 @@ class ObjectFormHandlerHelper
/** @var \iPopupMenuExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
{
foreach($oExtensionInstance->EnumItems(iPopupMenuExtension::PORTAL_OBJDETAILS_ACTIONS, array('portal_id' => $this->sPortalId, 'object' => $oObject, 'mode' => $sMode)) as $oMenuItem)
foreach ($oExtensionInstance->EnumItems(iPopupMenuExtension::PORTAL_OBJDETAILS_ACTIONS, array('portal_id' => $this->sPortalId, 'object' => $oObject, 'mode' => $sMode)) as $oMenuItem)
{
if (is_object($oMenuItem))
{
if($oMenuItem instanceof JSButtonItem)
if ($oMenuItem instanceof JSButtonItem)
{
$aFormData['buttons']['actions'][] = $oMenuItem->GetMenuItem() + array('js_files' => $oMenuItem->GetLinkedScripts());
}
elseif($oMenuItem instanceof URLButtonItem)
elseif ($oMenuItem instanceof URLButtonItem)
{
$aFormData['buttons']['links'][] = $oMenuItem->GetMenuItem();
}
@@ -197,11 +202,11 @@ class ObjectFormHandlerHelper
}
// Hiding submit button or changing its label if necessary
if(!empty($aFormData['buttons']['transitions']) && isset($aFormProperties['properties']) &&$aFormProperties['properties']['always_show_submit'] === false)
if (!empty($aFormData['buttons']['transitions']) && isset($aFormProperties['properties']) && $aFormProperties['properties']['always_show_submit'] === false)
{
unset($aFormData['buttons']['submit']);
}
elseif($sMode === static::ENUM_MODE_EDIT)
elseif ($sMode === static::ENUM_MODE_EDIT)
{
$aFormData['buttons']['submit']['label'] = Dict::S('Portal:Button:Apply');
}
@@ -225,7 +230,7 @@ class ObjectFormHandlerHelper
// Note : We might need to distinguish form & renderer endpoints
if (in_array($sMode, array('create', 'edit', 'view')))
{
$sFormEndpoint = $this->oUrlGenerator->generate('p_object_' . $sMode, array('sObjectClass' => $sObjectClass, 'sObjectId' => $sObjectId));
$sFormEndpoint = $this->oUrlGenerator->generate('p_object_'.$sMode, array('sObjectClass' => $sObjectClass, 'sObjectId' => $sObjectId));
}
else
{
@@ -252,9 +257,9 @@ class ObjectFormHandlerHelper
// Update / Submit / Cancel
$sFormManagerClass = $this->oRequestManipulator->ReadParam('formmanager_class', '', FILTER_UNSAFE_RAW);
$sFormManagerData = $this->oRequestManipulator->ReadParam('formmanager_data', '', FILTER_UNSAFE_RAW);
if ( empty($sFormManagerClass) || empty($sFormManagerData) )
if (empty($sFormManagerClass) || empty($sFormManagerData))
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Parameters formmanager_class and formamanager_data must be defined.');
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Parameters formmanager_class and formamanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameters formmanager_class and formmanager_data must be defined.');
}
@@ -280,7 +285,7 @@ class ObjectFormHandlerHelper
'currentValues' => $this->oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW),
'attachmentIds' => $this->oRequestManipulator->ReadParam('attachment_ids', array(), FILTER_UNSAFE_RAW),
'formProperties' => $aFormProperties,
'applyStimulus' => $this->oRequestManipulator->ReadParam('apply_stimulus', null)
'applyStimulus' => $this->oRequestManipulator->ReadParam('apply_stimulus', null),
)
);
if ($aFormData['validation']['valid'] === true)
@@ -329,7 +334,7 @@ class ObjectFormHandlerHelper
$sFormPath = $this->oRequestManipulator->ReadParam('form_path', '');
// Checking if the update was on a subform, if so we need to make the rendering for that part only
if ( !empty($sFormPath) && $sFormPath !== $oFormManager->GetForm()->GetId() )
if (!empty($sFormPath) && $sFormPath !== $oFormManager->GetForm()->GetId())
{
$oSubForm = $oFormManager->GetForm()->FindSubForm($sFormPath);
$oSubFormRenderer = new BsFormRenderer($oSubForm);
@@ -362,19 +367,32 @@ class ObjectFormHandlerHelper
return $aFormData;
}
/**
* @param $sId
* @param $sTwigString
* @param $aData
*
* @return string
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \Twig_Error_Loader
* @throws \Twig_Error_Runtime
* @throws \Twig_Error_Syntax
*/
public function RenderFormFromTwig($sId, $sTwigString, $aData)
{
// Creating sandbox twig env. to load and test the custom form template
$oTwig = new Twig_Environment(new Twig_Loader_Array( array($sId => $sTwigString) ));
$oTwig = new Twig_Environment(new Twig_Loader_Array(array($sId => $sTwigString)));
// Manually registering filters and functions as we didn't find how to do it automatically
$aFilters = $this->oAppExtension->getFilters();
foreach($aFilters as $oFilter)
foreach ($aFilters as $oFilter)
{
$oTwig->addFilter($oFilter);
}
$aFunctions = $this->oAppExtension->getFunctions();
foreach($aFunctions as $oFunction)
foreach ($aFunctions as $oFunction)
{
$oTwig->addFunction($oFunction);
}

View File

@@ -30,91 +30,91 @@ use Symfony\Component\HttpFoundation\RequestStack;
* Handle basic requests manipulation.
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.5.1
* @since 2.5.1
*/
class RequestManipulatorHelper
{
/** @var \Symfony\Component\HttpFoundation\RequestStack $oRequestStack */
protected $oRequestStack;
/** @var \Symfony\Component\HttpFoundation\RequestStack $oRequestStack */
protected $oRequestStack;
/**
* RequestManipulatorHelper constructor.
*
* @param \Symfony\Component\HttpFoundation\RequestStack $oRequestStack
*/
public function __construct(RequestStack $oRequestStack)
{
$this->oRequestStack = $oRequestStack;
}
/**
* RequestManipulatorHelper constructor.
*
* @param \Symfony\Component\HttpFoundation\RequestStack $oRequestStack
*/
public function __construct(RequestStack $oRequestStack)
{
$this->oRequestStack = $oRequestStack;
}
/**
* @return \Symfony\Component\HttpFoundation\Request
*/
public function GetCurrentRequest()
{
return $this->oRequestStack->getCurrentRequest();
}
/**
* @return \Symfony\Component\HttpFoundation\Request
*/
public function GetCurrentRequest()
{
return $this->oRequestStack->getCurrentRequest();
}
/**
* Returns if the request has a $sKey parameter.
* This looks in the GET arguments first, then PATH and finally the POST data.
*
* @param string $sKey
*
* @return bool
*/
public function HasParam($sKey)
{
if ($this->GetCurrentRequest()->query->has($sKey))
{
return true;
}
/**
* Returns if the request has a $sKey parameter.
* This looks in the GET arguments first, then PATH and finally the POST data.
*
* @param string $sKey
*
* @return bool
*/
public function HasParam($sKey)
{
if ($this->GetCurrentRequest()->query->has($sKey))
{
return true;
}
if ($this->GetCurrentRequest()->attributes->has($sKey))
{
return true;
}
if ($this->GetCurrentRequest()->attributes->has($sKey))
{
return true;
}
if ($this->GetCurrentRequest()->request->has($sKey))
{
return true;
}
if ($this->GetCurrentRequest()->request->has($sKey))
{
return true;
}
return false;
}
return false;
}
/**
* Returns the $sKey parameter from the request filtered with $iFilter.
* This looks in the GET arguments first, then the PATH and finally the POST data.
*
* Note: It is inspired by the \Symfony\Component\HttpFoundation\ParameterBag::filter() function and was necessary as we sometimes have parameters that can be either in the GET/PATH/POST arguments and need to be filtered. Silex only offer the possibility to filter parameter from a single ParameterBag, so we created this helper.
*
* @param string $sKey
* @param mixed $default
* @param int $iFilter Default is FILTER_SANITIZE_STRING
*
* @return mixed|null
*
* @since 2.5.1
*/
public function ReadParam($sKey, $default = null, $iFilter = FILTER_SANITIZE_STRING)
{
if ($this->GetCurrentRequest()->query->has($sKey))
{
return $this->GetCurrentRequest()->query->filter($sKey, $default, $iFilter);
}
/**
* Returns the $sKey parameter from the request filtered with $iFilter.
* This looks in the GET arguments first, then the PATH and finally the POST data.
*
* Note: It is inspired by the \Symfony\Component\HttpFoundation\ParameterBag::filter() function and was necessary as we sometimes have parameters that can be either in the GET/PATH/POST arguments and need to be filtered. Silex only offer the possibility to filter parameter from a single ParameterBag, so we created this helper.
*
* @param string $sKey
* @param mixed $default
* @param int $iFilter Default is FILTER_SANITIZE_STRING
*
* @return mixed|null
*
* @since 2.5.1
*/
public function ReadParam($sKey, $default = null, $iFilter = FILTER_SANITIZE_STRING)
{
if ($this->GetCurrentRequest()->query->has($sKey))
{
return $this->GetCurrentRequest()->query->filter($sKey, $default, $iFilter);
}
if ($this->GetCurrentRequest()->attributes->has($sKey))
{
return $this->GetCurrentRequest()->attributes->filter($sKey, $default, $iFilter);
}
if ($this->GetCurrentRequest()->attributes->has($sKey))
{
return $this->GetCurrentRequest()->attributes->filter($sKey, $default, $iFilter);
}
if ($this->GetCurrentRequest()->request->has($sKey))
{
return $this->GetCurrentRequest()->request->filter($sKey, $default, $iFilter);
}
if ($this->GetCurrentRequest()->request->has($sKey))
{
return $this->GetCurrentRequest()->request->filter($sKey, $default, $iFilter);
}
return $default;
}
return $default;
}
}

View File

@@ -28,6 +28,7 @@ use DOMFormatException;
use DOMNodeList;
use Exception;
use MetaModel;
use ModuleDesign;
use ProfilesConfig;
use UserRights;
use utils;
@@ -41,23 +42,44 @@ use utils;
*/
class ScopeValidatorHelper
{
/** @var string ENUM_MODE_READ */
const ENUM_MODE_READ = 'r';
/** @var string ENUM_MODE_WRITE */
const ENUM_MODE_WRITE = 'w';
/** @var string ENUM_TYPE_ALLOW */
const ENUM_TYPE_ALLOW = 'allow';
/** @var string ENUM_TYPE_RESTRICT */
const ENUM_TYPE_RESTRICT = 'restrict';
/** @var string DEFAULT_GENERATED_CLASS */
const DEFAULT_GENERATED_CLASS = '\\PortalScopesValues';
/** @var bool DEFAULT_IGNORE_SILOS */
const DEFAULT_IGNORE_SILOS = false;
/** @var string|null $sCachePath */
protected $sCachePath;
/** @var string $sFilename */
protected $sFilename;
/** @var string $sInstancePrefix */
protected $sInstancePrefix;
/** @var string $sGeneratedClass */
protected $sGeneratedClass;
/** @var array $aProfilesMatrix */
protected $aProfilesMatrix;
public function __construct(\ModuleDesign $moduleDesign, $sPortalId, $sPortalCachePath = null)
/**
* ScopeValidatorHelper constructor.
*
* @param \ModuleDesign $moduleDesign
* @param string $sPortalId
* @param string|null $sPortalCachePath
*
* @throws \DOMFormatException
*/
public function __construct(ModuleDesign $moduleDesign, $sPortalId, $sPortalCachePath = null)
{
$this->sFilename = "{$sPortalId}.scopes.php";
$this->sCachePath = $sPortalCachePath;
$this->sFilename = "{$sPortalId}.scopes.php";
$this->sCachePath = $sPortalCachePath;
$this->sInstancePrefix = "{$sPortalId}-";
$this->sGeneratedClass = static::DEFAULT_GENERATED_CLASS;
$this->aProfilesMatrix = array();
@@ -65,40 +87,41 @@ class ScopeValidatorHelper
$this->Init($moduleDesign->GetNodes('/module_design/classes/class'));
}
/**
* Initializes the ScopeValidator by generating and caching the scopes compilation in the $this->sCachePath.$this->sFilename file.
*
* @param DOMNodeList $oNodes
* @throws DOMFormatException
* @throws Exception
*/
public function Init(DOMNodeList $oNodes)
{
// Checking cache path
if ($this->sCachePath === null)
{
$this->sCachePath = utils::GetCachePath();
}
// Building full pathname for file
$sFilePath = $this->sCachePath . $this->sFilename;
/**
* Initializes the ScopeValidator by generating and caching the scopes compilation in the $this->sCachePath.$this->sFilename file.
*
* @param DOMNodeList $oNodes
*
* @throws DOMFormatException
* @throws Exception
*/
public function Init(DOMNodeList $oNodes)
{
// Checking cache path
if ($this->sCachePath === null)
{
$this->sCachePath = utils::GetCachePath();
}
// Building full pathname for file
$sFilePath = $this->sCachePath.$this->sFilename;
// Creating file if not existing
// Note : This is a temporary cache system, it should soon evolve to a cache provider (fs, apc, memcache, ...)
if (!file_exists($sFilePath))
{
$this->InitGenerateAndWriteCache($oNodes, $sFilePath);
}
// Creating file if not existing
// Note : This is a temporary cache system, it should soon evolve to a cache provider (fs, apc, memcache, ...)
if (!file_exists($sFilePath))
{
$this->InitGenerateAndWriteCache($oNodes, $sFilePath);
}
if (!class_exists($this->sGeneratedClass))
{
require_once $this->sCachePath . $this->sFilename;
}
}
if (!class_exists($this->sGeneratedClass))
{
require_once $this->sCachePath.$this->sFilename;
}
}
public static function EnumTypeValues()
{
return array(static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT);
}
public static function EnumTypeValues()
{
return array(static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT);
}
/**
* Returns the path where to cache the compiled scopes file
@@ -146,6 +169,7 @@ class ScopeValidatorHelper
* This is used to create a unique scope values class in the cache directory (/data/cache-<ENV>) as there can be several instance of the portal.
*
* @param string $sInstancePrefix
*
* @return \Combodo\iTop\Portal\Helper\ScopeValidatorHelper
*/
public function SetInstancePrefix($sInstancePrefix)
@@ -155,7 +179,7 @@ class ScopeValidatorHelper
$sInstancePrefix = str_replace(' ', '', $sInstancePrefix);
$this->sInstancePrefix = $sInstancePrefix;
$this->sGeneratedClass = $this->sInstancePrefix . static::DEFAULT_GENERATED_CLASS;
$this->sGeneratedClass = $this->sInstancePrefix.static::DEFAULT_GENERATED_CLASS;
return $this;
}
@@ -163,35 +187,35 @@ class ScopeValidatorHelper
/**
* Returns the DBSearch for the $sProfile in $iAction for the class $sClass
*
* @param string $sProfile
* @param string $sClass
* @param string $sProfile
* @param string $sClass
* @param integer $iAction
*
*
* @return \DBSearch
*
* @throws \Exception
* @throws \CoreException
* @throws \OQLException
*
* @throws \Exception
* @throws \CoreException
* @throws \OQLException
*/
public function GetScopeFilterForProfile($sProfile, $sClass, $iAction = null)
{
return $this->GetScopeFilterForProfiles(array($sProfile), $sClass, $iAction);
}
/**
* Returns the DBSearch for the $aProfiles in $iAction for the class $sClass.
* Profiles are a OR condition.
*
* @param array $aProfiles
* @param string $sClass
* @param integer $iAction
*
* @return \DBSearch
*
* @throws \Exception
* @throws \CoreException
* @throws \OQLException
*/
/**
* Returns the DBSearch for the $aProfiles in $iAction for the class $sClass.
* Profiles are a OR condition.
*
* @param array $aProfiles
* @param string $sClass
* @param integer $iAction
*
* @return \DBSearch
*
* @throws \Exception
* @throws \CoreException
* @throws \OQLException
*/
public function GetScopeFilterForProfiles($aProfiles, $sClass, $iAction = null)
{
$oSearch = null;
@@ -254,18 +278,18 @@ class ScopeValidatorHelper
return $oSearch;
}
/**
* Add the scope query (view or edit depending on $sAction) for $sClass to the $oQuery.
*
* @param \DBSearch $oQuery
* @param string $sClass
* @param int $sAction
*
* @return bool true if scope exists, false if scope is null
*
* @throws \CoreException
* @throws \OQLException
*/
/**
* Add the scope query (view or edit depending on $sAction) for $sClass to the $oQuery.
*
* @param \DBSearch $oQuery
* @param string $sClass
* @param int $sAction
*
* @return bool true if scope exists, false if scope is null
*
* @throws \CoreException
* @throws \OQLException
*/
public function AddScopeToQuery(DBSearch &$oQuery, $sClass, $sAction = UR_ACTION_READ)
{
$oScopeQuery = $this->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sClass, $sAction);
@@ -284,16 +308,16 @@ class ScopeValidatorHelper
return false;
}
/**
* Returns true if at least one of the $aProfiles has the ignore_silos flag set to true for the $sClass.
*
* @param array $aProfiles
* @param string $sClass
*
* @return boolean
*
* @throws \Exception
*/
/**
* Returns true if at least one of the $aProfiles has the ignore_silos flag set to true for the $sClass.
*
* @param array $aProfiles
* @param string $sClass
*
* @return boolean
*
* @throws \Exception
*/
public function IsAllDataAllowedForScope($aProfiles, $sClass)
{
$bIgnoreSilos = false;
@@ -301,7 +325,7 @@ class ScopeValidatorHelper
// Iterating on profiles to retrieving the different OQLs parts
foreach ($aProfiles as $sProfile)
{
// Retrieving matrix informtions
// Retrieving matrix information
$iProfileId = $this->GetProfileIdFromProfileName($sProfile);
// Retrieving profile OQLs
@@ -324,9 +348,9 @@ class ScopeValidatorHelper
* Returns the profile id from a string being either a constant or its name.
*
* @param string $sProfile
*
*
* @return integer
*
*
* @throws \Exception
*/
protected function GetProfileIdFromProfileName($sProfile)
@@ -362,7 +386,7 @@ class ScopeValidatorHelper
// If profile was not found from its name or from a constant, we throw an exception
if ($iProfileId === null)
{
throw new Exception('Scope validator : Could not find "' . $sProfile . '" in the profiles list');
throw new Exception('Scope validator : Could not find "'.$sProfile.'" in the profiles list');
}
return $iProfileId;
@@ -372,6 +396,7 @@ class ScopeValidatorHelper
* Returns a string containing the generated PHP class for the compiled scopes
*
* @param array $aProfiles
*
* @return string
*/
protected function BuildPHPClass($aProfiles = array())
@@ -415,212 +440,251 @@ EOF;
return $sPHP;
}
/**
* @param DOMNodeList $oNodes
* @param $sFilePath
*
* @throws DOMFormatException
* @throws \CoreException
* @throws \OQLException
*/
protected function InitGenerateAndWriteCache(DOMNodeList $oNodes, $sFilePath)
{
// - Build php array from xml
$aProfiles = array();
// This will be used to know which classes have been set, so we can set the missing ones.
$aProfileClasses = array();
// Iterating over the class nodes
foreach ($oNodes as $oClassNode) {
// retrieving mandatory class id attribute
$sClass = $oClassNode->getAttribute('id');
if ($sClass === '') {
throw new DOMFormatException('Class tag must have an id attribute.', null, null, $oClassNode);
}
/**
* @param DOMNodeList $oNodes
* @param string $sFilePath
*
* @throws DOMFormatException
* @throws \CoreException
* @throws \OQLException
* @throws \Exception
*/
protected function InitGenerateAndWriteCache(DOMNodeList $oNodes, $sFilePath)
{
// - Build php array from xml
$aProfiles = array();
// This will be used to know which classes have been set, so we can set the missing ones.
$aProfileClasses = array();
// Iterating over the class nodes
/** @var \Combodo\iTop\DesignElement $oClassNode */
foreach ($oNodes as $oClassNode)
{
// retrieving mandatory class id attribute
$sClass = $oClassNode->getAttribute('id');
if ($sClass === '')
{
throw new DOMFormatException('Class tag must have an id attribute.', null, null, $oClassNode);
}
// Iterating over scope nodes of the class
$oScopesNode = $oClassNode->GetOptionalElement('scopes');
if ($oScopesNode !== null) {
foreach ($oScopesNode->GetNodes('./scope') as $oScopeNode) {
// Retrieving mandatory scope id attribute
$sScopeId = $oScopeNode->getAttribute('id');
if ($sScopeId === '') {
throw new DOMFormatException('Scope tag must have an id attribute.', null, null, $oScopeNode);
}
// Iterating over scope nodes of the class
$oScopesNode = $oClassNode->GetOptionalElement('scopes');
if ($oScopesNode !== null)
{
/** @var \Combodo\iTop\DesignElement $oScopeNode */
foreach ($oScopesNode->GetNodes('./scope') as $oScopeNode)
{
// Retrieving mandatory scope id attribute
$sScopeId = $oScopeNode->getAttribute('id');
if ($sScopeId === '')
{
throw new DOMFormatException('Scope tag must have an id attribute.', null, null, $oScopeNode);
}
// Retrieving the type of query
// Note : This has been disabled as we don't want deny rules for now
// $oOqlViewTypeNode = $oClassNode->GetOptionalElement('oql_view_type');
// $sOqlViewType = ($oOqlViewTypeNode !== null && ($oOqlViewTypeNode->GetText() === static::ENUM_TYPE_RESTRICT)) ? static::ENUM_TYPE_RESTRICT : static::ENUM_TYPE_ALLOW;
$sOqlViewType = static::ENUM_TYPE_ALLOW;
// Retrieving the view query
$oOqlViewNode = $oScopeNode->GetUniqueElement('oql_view');
$sOqlView = $oOqlViewNode->GetText();
if ($sOqlView === null) {
throw new DOMFormatException(
'Scope tag in class must have a not empty oql_view tag',
null,
null,
$oScopeNode
);
}
// Retrieving the edit query
$oOqlEditNode = $oScopeNode->GetOptionalElement('oql_edit');
$sOqlEdit = (($oOqlEditNode !== null) && ($oOqlEditNode->GetText(
) !== null)) ? $oOqlEditNode->GetText() : null;
// Retrieving ignore allowed org flag
$oIgnoreSilosNode = $oScopeNode->GetOptionalElement('ignore_silos');
$bIgnoreSilos = (($oIgnoreSilosNode !== null) && ($oIgnoreSilosNode->GetText(
) === 'true')) ? true : static::DEFAULT_IGNORE_SILOS;
// Retrieving the type of query
// Note : This has been disabled as we don't want deny rules for now
// $oOqlViewTypeNode = $oClassNode->GetOptionalElement('oql_view_type');
// $sOqlViewType = ($oOqlViewTypeNode !== null && ($oOqlViewTypeNode->GetText() === static::ENUM_TYPE_RESTRICT)) ? static::ENUM_TYPE_RESTRICT : static::ENUM_TYPE_ALLOW;
$sOqlViewType = static::ENUM_TYPE_ALLOW;
// Retrieving the view query
$oOqlViewNode = $oScopeNode->GetUniqueElement('oql_view');
$sOqlView = $oOqlViewNode->GetText();
if ($sOqlView === null)
{
throw new DOMFormatException(
'Scope tag in class must have a not empty oql_view tag',
null,
null,
$oScopeNode
);
}
// Retrieving the edit query
$oOqlEditNode = $oScopeNode->GetOptionalElement('oql_edit');
$sOqlEdit = (($oOqlEditNode !== null) && ($oOqlEditNode->GetText() !== null)) ? $oOqlEditNode->GetText() : null;
// Retrieving ignore allowed org flag
$oIgnoreSilosNode = $oScopeNode->GetOptionalElement('ignore_silos');
$bIgnoreSilos = (($oIgnoreSilosNode !== null) && ($oIgnoreSilosNode->GetText() === 'true')) ? true : static::DEFAULT_IGNORE_SILOS;
// Retrieving profiles for the scope
$oProfilesNode = $oScopeNode->GetOptionalElement('allowed_profiles');
$aProfilesNames = array();
// If no profile is specified, we consider that it's for ALL the profiles
if (($oProfilesNode === null) || ($oProfilesNode->GetNodes('./allowed_profile')->length === 0)) {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
$aProfilesNames[] = $aValue['name'];
}
} else {
foreach ($oProfilesNode->GetNodes('./allowed_profile') as $oProfileNode) {
// Retrieving mandatory profile id attribute
$sProfileId = $oProfileNode->getAttribute('id');
if ($sProfileId === '') {
throw new DOMFormatException(
'Scope tag must have an id attribute.',
null,
null,
$oProfileNode
);
}
$aProfilesNames[] = $sProfileId;
}
}
// Retrieving profiles for the scope
$oProfilesNode = $oScopeNode->GetOptionalElement('allowed_profiles');
$aProfilesNames = array();
// If no profile is specified, we consider that it's for ALL the profiles
if (($oProfilesNode === null) || ($oProfilesNode->GetNodes('./allowed_profile')->length === 0))
{
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue)
{
$aProfilesNames[] = $aValue['name'];
}
}
else
{
/** @var \Combodo\iTop\DesignElement $oProfileNode */
foreach ($oProfilesNode->GetNodes('./allowed_profile') as $oProfileNode)
{
// Retrieving mandatory profile id attribute
$sProfileId = $oProfileNode->getAttribute('id');
if ($sProfileId === '')
{
throw new DOMFormatException(
'Scope tag must have an id attribute.',
null,
null,
$oProfileNode
);
}
$aProfilesNames[] = $sProfileId;
}
}
//
foreach ($aProfilesNames as $sProfileName) {
// Scope profile id
$iProfileId = $this->GetProfileIdFromProfileName($sProfileName);
//
foreach ($aProfilesNames as $sProfileName)
{
// Scope profile id
$iProfileId = $this->GetProfileIdFromProfileName($sProfileName);
// Now that we have the queries infos, we are going to build the queries for that profile / class
$sMatrixPrefix = $iProfileId.'_'.$sClass.'_';
// - View query
$oViewFilter = DBSearch::FromOQL($sOqlView);
// ... We have to union the query if this profile has another scope for that class
if (array_key_exists($sMatrixPrefix.static::ENUM_MODE_READ, $aProfiles) && array_key_exists(
$sOqlViewType,
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ]
)) {
$oExistingFilter = DBSearch::FromOQL(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ][$sOqlViewType]
);
$aFilters = array($oExistingFilter, $oViewFilter);
$oResFilter = new DBUnionSearch($aFilters);
// Now that we have the queries infos, we are going to build the queries for that profile / class
$sMatrixPrefix = $iProfileId.'_'.$sClass.'_';
// - View query
$oViewFilter = DBSearch::FromOQL($sOqlView);
// ... We have to union the query if this profile has another scope for that class
if (array_key_exists($sMatrixPrefix.static::ENUM_MODE_READ, $aProfiles) && array_key_exists(
$sOqlViewType,
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ]
))
{
$oExistingFilter = DBSearch::FromOQL(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ][$sOqlViewType]
);
$aFilters = array($oExistingFilter, $oViewFilter);
$oResFilter = new DBUnionSearch($aFilters);
// Applying ignore_silos flag on result filter if necessary (As the union will remove it if it is not on all sub-queries)
if ($aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ]['ignore_silos'] === true) {
$bIgnoreSilos = true;
}
} else {
$oResFilter = $oViewFilter;
}
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ] = array(
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos
);
// - Edit query
if ($sOqlEdit !== null) {
$oEditFilter = DBSearch::FromOQL($sOqlEdit);
// - If the queries are the same, we don't make an intersect, we just reuse the view query
if ($sOqlEdit === $sOqlView) {
// Do not intersect, edit query is identical to view query
} else {
if (($oEditFilter->GetClass() === $oViewFilter->GetClass()) && $oEditFilter->IsAny()) {
$oEditFilter = $oViewFilter;
// Do not intersect, edit query is identical to view query
} else {
// Intersect
$oEditFilter = $oViewFilter->Intersect($oEditFilter);
}
}
// Applying ignore_silos flag on result filter if necessary (As the union will remove it if it is not on all sub-queries)
if ($aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ]['ignore_silos'] === true)
{
$bIgnoreSilos = true;
}
}
else
{
$oResFilter = $oViewFilter;
}
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ] = array(
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos,
);
// - Edit query
if ($sOqlEdit !== null)
{
$oEditFilter = DBSearch::FromOQL($sOqlEdit);
// - If the queries are the same, we don't make an intersect, we just reuse the view query
if ($sOqlEdit === $sOqlView)
{
// Do not intersect, edit query is identical to view query
}
else
{
if (($oEditFilter->GetClass() === $oViewFilter->GetClass()) && $oEditFilter->IsAny())
{
$oEditFilter = $oViewFilter;
// Do not intersect, edit query is identical to view query
}
else
{
// Intersect
$oEditFilter = $oViewFilter->Intersect($oEditFilter);
}
}
// ... We have to union the query if this profile has another scope for that class
if (array_key_exists(
$sMatrixPrefix.static::ENUM_MODE_WRITE,
$aProfiles
) && array_key_exists(
$sOqlViewType,
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE]
)) {
$oExistingFilter = DBSearch::FromOQL(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE][$sOqlViewType]
);
$aFilters = array($oExistingFilter, $oEditFilter);
$oResFilter = new DBUnionSearch($aFilters);
} else {
$oResFilter = $oEditFilter;
}
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE] = array(
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos
);
}
}
}
// ... We have to union the query if this profile has another scope for that class
if (array_key_exists(
$sMatrixPrefix.static::ENUM_MODE_WRITE,
$aProfiles
) && array_key_exists(
$sOqlViewType,
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE]
))
{
$oExistingFilter = DBSearch::FromOQL(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE][$sOqlViewType]
);
$aFilters = array($oExistingFilter, $oEditFilter);
$oResFilter = new DBUnionSearch($aFilters);
}
else
{
$oResFilter = $oEditFilter;
}
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE] = array(
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos,
);
}
}
}
$aProfileClasses[] = $sClass;
}
}
$aProfileClasses[] = $sClass;
}
}
// Filling the array with missing classes from MetaModel, so we can have an inheritance principle on the scope
// For each class explicitly given in the scopes, we check if its child classes were also in the scope :
// If not, we add them with the same OQL
foreach ($aProfileClasses as $sProfileClass) {
foreach (MetaModel::EnumChildClasses($sProfileClass) as $sChildClass) {
// If the child class is not in the scope, we are going to try to add it
if (!in_array($sChildClass, $aProfileClasses)) {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
$iProfileId = $iKey;
foreach (array(static::ENUM_MODE_READ, static::ENUM_MODE_WRITE) as $sAction) {
// If the current profile has scope for that class in that mode, we duplicate it
if (isset($aProfiles[$iProfileId.'_'.$sProfileClass.'_'.$sAction])) {
$aTmpProfile = $aProfiles[$iProfileId.'_'.$sProfileClass.'_'.$sAction];
foreach ($aTmpProfile as $sType => $sOql) {
// IF condition is just to skip the 'ignore_silos' flag
if (in_array($sType, array(static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT))) {
$oTmpFilter = DBSearch::FromOQL($sOql);
$oTmpFilter->ChangeClass($sChildClass);
// Filling the array with missing classes from MetaModel, so we can have an inheritance principle on the scope
// For each class explicitly given in the scopes, we check if its child classes were also in the scope :
// If not, we add them with the same OQL
foreach ($aProfileClasses as $sProfileClass)
{
foreach (MetaModel::EnumChildClasses($sProfileClass) as $sChildClass)
{
// If the child class is not in the scope, we are going to try to add it
if (!in_array($sChildClass, $aProfileClasses))
{
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue)
{
$iProfileId = $iKey;
foreach (array(static::ENUM_MODE_READ, static::ENUM_MODE_WRITE) as $sAction)
{
// If the current profile has scope for that class in that mode, we duplicate it
if (isset($aProfiles[$iProfileId.'_'.$sProfileClass.'_'.$sAction]))
{
$aTmpProfile = $aProfiles[$iProfileId.'_'.$sProfileClass.'_'.$sAction];
foreach ($aTmpProfile as $sType => $sOql)
{
// IF condition is just to skip the 'ignore_silos' flag
if (in_array($sType, array(static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT)))
{
$oTmpFilter = DBSearch::FromOQL($sOql);
$oTmpFilter->ChangeClass($sChildClass);
$aTmpProfile[$sType] = $oTmpFilter->ToOQL();
}
}
$aTmpProfile[$sType] = $oTmpFilter->ToOQL();
}
}
$aProfiles[$iProfileId.'_'.$sChildClass.'_'.$sAction] = $aTmpProfile;
}
}
}
}
}
}
$aProfiles[$iProfileId.'_'.$sChildClass.'_'.$sAction] = $aTmpProfile;
}
}
}
}
}
}
// - Build php class
$sPHP = $this->BuildPHPClass($aProfiles);
// - Build php class
$sPHP = $this->BuildPHPClass($aProfiles);
// - Write file on disk
// - Creating dir if necessary
if (!is_dir($this->sCachePath)) {
mkdir($this->sCachePath, 0777, true);
}
// -- Then creating the file
$ret = file_put_contents($sFilePath, $sPHP);
if ($ret === false) {
$iLen = strlen($sPHP);
$fFree = @disk_free_space(dirname($sFilePath));
$aErr = error_get_last();
throw new Exception(
"Failed to write '$sFilePath'. Last error: '{$aErr['message']}', content to write: $iLen bytes, available free space on disk: $fFree."
);
}
}
// - Write file on disk
// - Creating dir if necessary
if (!is_dir($this->sCachePath))
{
mkdir($this->sCachePath, 0777, true);
}
// -- Then creating the file
$ret = file_put_contents($sFilePath, $sPHP);
if ($ret === false)
{
$iLen = strlen($sPHP);
$fFree = @disk_free_space(dirname($sFilePath));
$aErr = error_get_last();
throw new Exception(
"Failed to write '$sFilePath'. Last error: '{$aErr['message']}', content to write: $iLen bytes, available free space on disk: $fFree."
);
}
}
}

View File

@@ -19,7 +19,6 @@
namespace Combodo\iTop\Portal\Helper;
use Silex\Application;
use UserRights;
use IssueLog;
use MetaModel;
@@ -35,22 +34,21 @@ use BinaryExpression;
*
* Handle security checks through the different layers (portal scopes, iTop silos, user rights)
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Portal\Helper
* @since 2.3.0
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class SecurityHelper
{
public static $aAllowedScopeObjectsCache = array(
UR_ACTION_READ => array(),
UR_ACTION_MODIFY => array(),
);
/** @var array $aAllowedScopeObjectsCache */
public static $aAllowedScopeObjectsCache = array(
UR_ACTION_READ => array(),
UR_ACTION_MODIFY => array(),
);
/**
* @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper
*/
/** @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper $oScopeValidator */
private $oScopeValidator;
/**
* @var \Combodo\iTop\Portal\Helper\LifecycleValidatorHelper
*/
/** @var \Combodo\iTop\Portal\Helper\LifecycleValidatorHelper $oLifecycleValidator */
private $oLifecycleValidator;
/** @var bool $bDebug */
private $bDebug;
@@ -71,32 +69,36 @@ class SecurityHelper
/**
* Returns true if the current user is allowed to do the $sAction on an $sObjectClass object (with optionnal $sObjectId id)
* Checks are:
* - Has a scope query for the $sObjectClass / $sAction
* - Optionally, if $sObjectId provided: Is object within scope for $sObjectClass / $sObjectId / $sAction
* - Is allowed by datamodel for $sObjectClass / $sAction
*
* @param \Silex\Application $oApp
* @param string $sAction Must be in UR_ACTION_READ|UR_ACTION_MODIFY|UR_ACTION_CREATE
* @param string $sObjectClass
* @param string $sObjectId
*
* @return boolean
*
* @throws \CoreException
*/
* Returns true if the current user is allowed to do the $sAction on an $sObjectClass object (with optionnal $sObjectId id)
* Checks are:
* - Has a scope query for the $sObjectClass / $sAction
* - Optionally, if $sObjectId provided: Is object within scope for $sObjectClass / $sObjectId / $sAction
* - Is allowed by datamodel for $sObjectClass / $sAction
*
* @param string $sAction Must be in UR_ACTION_READ|UR_ACTION_MODIFY|UR_ACTION_CREATE
* @param string $sObjectClass
* @param string $sObjectId
*
* @return boolean
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function IsActionAllowed($sAction, $sObjectClass, $sObjectId = null)
{
$sDebugTracePrefix = __CLASS__ . ' / ' . __METHOD__ . ' : Returned false for action ' . $sAction . ' on ' . $sObjectClass . '::' . $sObjectId;
$sDebugTracePrefix = __CLASS__.' / '.__METHOD__.' : Returned false for action '.$sAction.' on '.$sObjectClass.'::'.$sObjectId;
// Checking action type
if (!in_array($sAction, array(UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_CREATE)))
{
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix . ' as the action value could not be understood (' . UR_ACTION_READ . '/' . UR_ACTION_MODIFY . '/' . UR_ACTION_CREATE . ' expected');
IssueLog::Info($sDebugTracePrefix.' as the action value could not be understood ('.UR_ACTION_READ.'/'.UR_ACTION_MODIFY.'/'.UR_ACTION_CREATE.' expected');
}
return false;
}
@@ -109,8 +111,9 @@ class SecurityHelper
{
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix . ' as there was no scope defined for action ' . $sScopeAction . ' and profiles ' . implode('/', UserRights::ListProfiles()));
IssueLog::Info($sDebugTracePrefix.' as there was no scope defined for action '.$sScopeAction.' and profiles '.implode('/', UserRights::ListProfiles()));
}
return false;
}
// - If action != create we do some additionnal checks
@@ -119,49 +122,51 @@ class SecurityHelper
// - Checking specific object if id is specified
if ($sObjectId !== null)
{
// Checking if object status is in cache (to avoid unnecessary query)
if(isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId]) )
{
if(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] === false)
{
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix . ' as it was denied in the scope objects cache');
}
return false;
}
}
else
{
// Modifying query to filter on the ID
// - Adding expression
$sObjectKeyAtt = MetaModel::DBGetKey($sObjectClass);
$oFieldExp = new FieldExpression($sObjectKeyAtt, $oScopeQuery->GetClassAlias());
$oBinExp = new BinaryExpression($oFieldExp, '=', new VariableExpression('object_id'));
$oScopeQuery->AddConditionExpression($oBinExp);
// - Setting value
$aQueryParams = $oScopeQuery->GetInternalParams();
$aQueryParams['object_id'] = $sObjectId;
$oScopeQuery->SetInternalParams($aQueryParams);
unset($aQueryParams);
// Checking if object status is in cache (to avoid unnecessary query)
if (isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId]))
{
if (static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] === false)
{
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix.' as it was denied in the scope objects cache');
}
// - Checking if query result is null (which means that the user has no right to view this specific object)
$oSet = new DBObjectSet($oScopeQuery);
if ($oSet->Count() === 0)
{
// Updating cache
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = false;
return false;
}
}
else
{
// Modifying query to filter on the ID
// - Adding expression
$sObjectKeyAtt = MetaModel::DBGetKey($sObjectClass);
$oFieldExp = new FieldExpression($sObjectKeyAtt, $oScopeQuery->GetClassAlias());
$oBinExp = new BinaryExpression($oFieldExp, '=', new VariableExpression('object_id'));
$oScopeQuery->AddConditionExpression($oBinExp);
// - Setting value
$aQueryParams = $oScopeQuery->GetInternalParams();
$aQueryParams['object_id'] = $sObjectId;
$oScopeQuery->SetInternalParams($aQueryParams);
unset($aQueryParams);
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix . ' as there was no result for the following scope query : ' . $oScopeQuery->ToOQL(true));
}
return false;
}
// - Checking if query result is null (which means that the user has no right to view this specific object)
$oSet = new DBObjectSet($oScopeQuery);
if ($oSet->Count() === 0)
{
// Updating cache
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = false;
// Updating cache
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = true;
}
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix.' as there was no result for the following scope query : '.$oScopeQuery->ToOQL(true));
}
return false;
}
// Updating cache
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = true;
}
}
}
@@ -172,32 +177,41 @@ class SecurityHelper
//throw new SecurityException('User not allowed to view this object', array('class' => $sObjectClass, 'id' => $sObjectId));
if ($this->bDebug)
{
IssueLog::Info($sDebugTracePrefix . ' as the user is not allowed to access this object according to the datamodel security (cf. Console settings)');
IssueLog::Info($sDebugTracePrefix.' as the user is not allowed to access this object according to the datamodel security (cf. Console settings)');
}
return false;
}
return true;
}
/**
* @param string $sStimulusCode
* @param string $sObjectClass
* @param \DBObjectSet|null $oInstanceSet
*
* @return bool
* @throws \Exception
*/
public function IsStimulusAllowed($sStimulusCode, $sObjectClass, $oInstanceSet = null)
{
// Checking DataModel layer
$aStimuliFromDatamodel = Metamodel::EnumStimuli($sObjectClass);
// Checking DataModel layer
$aStimuliFromDatamodel = Metamodel::EnumStimuli($sObjectClass);
$iActionAllowed = (get_class($aStimuliFromDatamodel[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sObjectClass, $sStimulusCode, $oInstanceSet) : UR_ALLOWED_NO;
if( ($iActionAllowed === false) || ($iActionAllowed === UR_ALLOWED_NO) )
{
return false;
}
if (($iActionAllowed === false) || ($iActionAllowed === UR_ALLOWED_NO))
{
return false;
}
// Checking portal security layer
$aStimuliFromPortal = $this->oLifecycleValidator->GetStimuliForProfiles(UserRights::ListProfiles(), $sObjectClass);
if(!in_array($sStimulusCode, $aStimuliFromPortal))
{
return false;
}
// Checking portal security layer
$aStimuliFromPortal = $this->oLifecycleValidator->GetStimuliForProfiles(UserRights::ListProfiles(), $sObjectClass);
if (!in_array($sStimulusCode, $aStimuliFromPortal))
{
return false;
}
return true;
return true;
}
/**
@@ -210,99 +224,101 @@ class SecurityHelper
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \OQLException
* @throws \Exception
*/
public function PreloadForCache(DBSearch $oSearch, $aExtKeysToPreload = null)
{
$sObjectClass = $oSearch->GetClass();
$aObjectIds = array();
$aExtKeysIds = array();
$aColumnsToLoad = array();
{
$sObjectClass = $oSearch->GetClass();
$aObjectIds = array();
$aExtKeysIds = array();
$aColumnsToLoad = array();
if($aExtKeysToPreload !== null)
{
foreach($aExtKeysToPreload as $sAttCode)
{
/** @var \AttributeDefinition $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
if($oAttDef->IsExternalKey())
{
$aExtKeysIds[$oAttDef->GetTargetClass()] = array();
$aColumnsToLoad[] = $sAttCode;
}
}
}
if ($aExtKeysToPreload !== null)
{
foreach ($aExtKeysToPreload as $sAttCode)
{
/** @var \AttributeDefinition $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
if ($oAttDef->IsExternalKey())
{
/** @var \AttributeExternalKey $oAttDef */
$aExtKeysIds[$oAttDef->GetTargetClass()] = array();
$aColumnsToLoad[] = $sAttCode;
}
}
}
// Retrieving IDs of all objects
// Note: We have to clone $oSet otherwise the source object will be modified
$oSet = new DBObjectSet($oSearch);
$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => $aColumnsToLoad));
while($oCurrentRow = $oSet->Fetch())
{
// Note: By presetting value to false, it is quicker to find which objects where not returned by the scope query later
$aObjectIds[$oCurrentRow->GetKey()] = false;
// Retrieving IDs of all objects
// Note: We have to clone $oSet otherwise the source object will be modified
$oSet = new DBObjectSet($oSearch);
$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => $aColumnsToLoad));
while ($oCurrentRow = $oSet->Fetch())
{
// Note: By presetting value to false, it is quicker to find which objects where not returned by the scope query later
$aObjectIds[$oCurrentRow->GetKey()] = false;
// Preparing ExtKeys to preload
foreach($aColumnsToLoad as $sAttCode)
{
$iExtKey = $oCurrentRow->Get($sAttCode);
if($iExtKey > 0)
{
/** @var \AttributeExternalKey $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
if(!in_array($iExtKey, $aExtKeysIds[$oAttDef->GetTargetClass()]))
{
$aExtKeysIds[$oAttDef->GetTargetClass()][] = $iExtKey;
}
}
}
}
// Preparing ExtKeys to preload
foreach ($aColumnsToLoad as $sAttCode)
{
$iExtKey = $oCurrentRow->Get($sAttCode);
if ($iExtKey > 0)
{
/** @var \AttributeExternalKey $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
if (!in_array($iExtKey, $aExtKeysIds[$oAttDef->GetTargetClass()]))
{
$aExtKeysIds[$oAttDef->GetTargetClass()][] = $iExtKey;
}
}
}
}
foreach(array(UR_ACTION_READ, UR_ACTION_MODIFY) as $sScopeAction)
{
// Retrieving scope query
/** @var DBSearch $oScopeQuery */
$oScopeQuery = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sObjectClass, $sScopeAction);
if($oScopeQuery !== null)
{
// Restricting scope if specified
if(!empty($aObjectIds))
{
$oScopeQuery->AddCondition('id', array_keys($aObjectIds), 'IN');
}
foreach (array(UR_ACTION_READ, UR_ACTION_MODIFY) as $sScopeAction)
{
// Retrieving scope query
/** @var DBSearch $oScopeQuery */
$oScopeQuery = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sObjectClass, $sScopeAction);
if ($oScopeQuery !== null)
{
// Restricting scope if specified
if (!empty($aObjectIds))
{
$oScopeQuery->AddCondition('id', array_keys($aObjectIds), 'IN');
}
// Preparing object set
$oScopeSet = new DBObjectSet($oScopeQuery);
$oScopeSet->OptimizeColumnLoad(array());
// Preparing object set
$oScopeSet = new DBObjectSet($oScopeQuery);
$oScopeSet->OptimizeColumnLoad(array());
// Checking objects status
$aScopeObjectIds = $aObjectIds;
while($oCurrentRow = $oScopeSet->Fetch())
{
$aScopeObjectIds[$oCurrentRow->GetKey()] = true;
}
// Checking objects status
$aScopeObjectIds = $aObjectIds;
while ($oCurrentRow = $oScopeSet->Fetch())
{
$aScopeObjectIds[$oCurrentRow->GetKey()] = true;
}
// Updating cache
if(!isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass]))
{
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = $aScopeObjectIds;
}
else
{
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = array_merge_recursive(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass], $aScopeObjectIds);
}
}
}
// Updating cache
if (!isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass]))
{
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = $aScopeObjectIds;
}
else
{
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = array_merge_recursive(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass], $aScopeObjectIds);
}
}
}
// Preloading ExtKeys
foreach($aExtKeysIds as $sTargetClass => $aTargetIds)
{
if(!empty($aTargetIds))
{
$oTargetSearch = new DBObjectSearch($sTargetClass);
$oTargetSearch->AddCondition('id', $aTargetIds, 'IN');
// Preloading ExtKeys
foreach ($aExtKeysIds as $sTargetClass => $aTargetIds)
{
if (!empty($aTargetIds))
{
$oTargetSearch = new DBObjectSearch($sTargetClass);
$oTargetSearch->AddCondition('id', $aTargetIds, 'IN');
static::PreloadForCache($oTargetSearch);
}
}
}
static::PreloadForCache($oTargetSearch);
}
}
}
}

View File

@@ -1,4 +1,23 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal;
@@ -10,27 +29,43 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
/**
* Class Kernel
*
* @package Combodo\iTop\Portal
* @since 2.7.0
*/
class Kernel extends BaseKernel
{
use MicroKernelTrait;
/** @var string CONFIG_EXTS */
const CONFIG_EXTS = '.{php,xml,yaml,yml}';
public function getCacheDir()
/**
* @return string
*/
public function getCacheDir()
{
$cacheDir = $_ENV['PORTAL_ID'] . '-' . $this->environment;
return utils::GetCachePath() . "/portals/$cacheDir";
}
public function getLogDir()
/**
* @return string
*/
public function getLogDir()
{
$logDir = $_ENV['PORTAL_ID'] . '-' . $this->environment;
return utils::GetLogPath() . "/portals/$logDir";
}
public function registerBundles()
/**
* @return \Generator|iterable|\Symfony\Component\HttpKernel\Bundle\BundleInterface[]
*/
public function registerBundles()
{
$contents = require $this->getProjectDir().'/config/bundles.php';
foreach ($contents as $class => $envs) {
@@ -40,7 +75,13 @@ class Kernel extends BaseKernel
}
}
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
/**
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
* @param \Symfony\Component\Config\Loader\LoaderInterface $loader
*
* @throws \Exception
*/
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
// Feel free to remove the "container.autowiring.strict_mode" parameter
@@ -55,7 +96,12 @@ class Kernel extends BaseKernel
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
}
protected function configureRoutes(RouteCollectionBuilder $routes)
/**
* @param \Symfony\Component\Routing\RouteCollectionBuilder $routes
*
* @throws \Symfony\Component\Config\Exception\FileLoaderLoadException
*/
protected function configureRoutes(RouteCollectionBuilder $routes)
{
$confDir = $this->getProjectDir().'/config';
@@ -63,4 +109,20 @@ class Kernel extends BaseKernel
$routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob');
}
/**
* Checks if a given class name belongs to an active bundle.
*
* @param string $class A class name
*
* @return void true if the class belongs to an active bundle, false otherwise
*
* @api
*
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
*/
public function isClassInActiveBundle($class)
{
// TODO: Implement isClassInActiveBundle() method.
}
}

View File

@@ -19,12 +19,6 @@
*
*/
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 31/01/19
* Time: 16:44
*/
namespace Combodo\iTop\Portal\Routing;
@@ -34,38 +28,45 @@ use Exception;
* Class ItopExtensionsExtraRoutes
*
* @deprecated Compatibility layer for migrating brick's routes to iTop 2.7+
* @package Combodo\iTop\Portal\Routing
* @package Combodo\iTop\Portal\Routing
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class ItopExtensionsExtraRoutes
{
static private $routes = array();
/** @var array $aRoutes */
static private $aRoutes = array();
/**
* @deprecated Since 2.7.0
*
* @param array $extraRoutes
*
* @throws Exception
*/
public static function addRoutes($extraRoutes)
{
@trigger_error(
sprintf(
'Usage of legacy route "%s" is deprecated. You should declare routes in YAML format.',
__FILE__
),
E_USER_DEPRECATED
);
/**
* @param array $extraRoutes
*
* @throws Exception
* @deprecated Since 2.7.0
*
*/
public static function AddRoutes($extraRoutes)
{
@trigger_error(
sprintf(
'Usage of legacy route "%s" is deprecated. You should declare routes in YAML format.',
__FILE__
),
E_USER_DEPRECATED
);
if (!is_array($extraRoutes)) {
throw new Exception('Only array are allowed as parameter to '.__METHOD__);
}
if (!is_array($extraRoutes))
{
throw new Exception('Only array are allowed as parameter to '.__METHOD__);
}
self::$routes = array_merge(self::$routes, $extraRoutes);
}
self::$aRoutes = array_merge(self::$aRoutes, $extraRoutes);
}
public static function getRoutes()
{
return self::$routes;
}
/**
* @return array
*/
public static function GetRoutes()
{
return self::$aRoutes;
}
}

View File

@@ -28,13 +28,16 @@ use Symfony\Component\Routing\Generator\UrlGenerator as BaseUrlGenerator;
* Class UrlGenerator
*
* @package Combodo\iTop\Portal\Routing
* @since 2.7.0
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class UrlGenerator extends BaseUrlGenerator
{
/** @noinspection PhpTooManyParametersInspection */
/**
* Overloading of the parent function to add the $_REQUEST parameters to the url parameters.
* This is used to keep additionnal parameters in the url, especially when portal is accessed from the /pages/exec.php
* This is used to keep additional parameters in the url, especially when portal is accessed from the /pages/exec.php
*
* Note: As of now, it only adds the exec_module/exec_page/portal_id/env_switch/debug parameters. Any other parameter will be ignored.
*
@@ -66,22 +69,26 @@ class UrlGenerator extends BaseUrlGenerator
{
$sExecModule = utils::ReadParam('exec_module', '', false, 'string');
$sExecPage = utils::ReadParam('exec_page', '', false, 'string');
if ($sExecModule !== '' && $sExecPage !== '') {
if ($sExecModule !== '' && $sExecPage !== '')
{
$aParameters['exec_module'] = $sExecModule;
$aParameters['exec_page'] = $sExecPage;
}
// Optional parameters
$sPortalId = utils::ReadParam('portal_id', '', false, 'string');
if ($sPortalId !== '') {
if ($sPortalId !== '')
{
$aParameters['portal_id'] = $sPortalId;
}
$sEnvSwitch = utils::ReadParam('env_switch', '', false, 'string');
if ($sEnvSwitch !== '') {
if ($sEnvSwitch !== '')
{
$aParameters['env_switch'] = $sEnvSwitch;
}
$sDebug = utils::ReadParam('debug', '', false, 'string');
if ($sDebug !== '') {
if ($sDebug !== '')
{
$aParameters['debug'] = $sDebug;
}

View File

@@ -1,9 +1,24 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 24/01/19
* Time: 15:36
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\Twig;
use Twig\Extension\AbstractExtension;
@@ -14,94 +29,106 @@ use utils;
use Dict;
use MetaModel;
/**
* Class AppExtension
*
* @package Combodo\iTop\Portal\Twig
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class AppExtension extends AbstractExtension
{
public function getFilters()
{
$filters = array();
// Filter to translate a string via the Dict::S function
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
$filters[] = new Twig_SimpleFilter('dict_s',
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
}
);
/**
* @return array|\Twig\TwigFilter[]|\Twig_SimpleFilter[]
*/
public function getFilters()
{
$filters = array();
// Filter to translate a string via the Dict::S function
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
$filters[] = new Twig_SimpleFilter('dict_s',
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
}
);
// Filter to format a string via the Dict::Format function
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
$filters[] = new Twig_SimpleFilter('dict_format',
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
}
);
// Filter to format a string via the Dict::Format function
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
$filters[] = new Twig_SimpleFilter('dict_format',
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
}
);
// Filter to enable base64 encode/decode
// Usage in twig: {{ 'String to encode'|base64_encode }}
$filters[] = new Twig_SimpleFilter('base64_encode', 'base64_encode');
$filters[] = new Twig_SimpleFilter('base64_decode', 'base64_decode');
// Filter to enable base64 encode/decode
// Usage in twig: {{ 'String to encode'|base64_encode }}
$filters[] = new Twig_SimpleFilter('base64_encode', 'base64_encode');
$filters[] = new Twig_SimpleFilter('base64_decode', 'base64_decode');
// Filter to enable json decode (encode already exists)
// Usage in twig: {{ aSomeArray|json_decode }}
$filters[] = new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
return json_decode($sJsonString, $bAssoc);
}
);
// Filter to enable json decode (encode already exists)
// Usage in twig: {{ aSomeArray|json_decode }}
$filters[] = new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
return json_decode($sJsonString, $bAssoc);
}
);
// Filter to add itopversion to an url
$filters[] = new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?itopversion=".ITOP_VERSION;
}
else
{
$sUrl = $sUrl."&itopversion=".ITOP_VERSION;
}
// Filter to add itopversion to an url
$filters[] = new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?itopversion=".ITOP_VERSION;
}
else
{
$sUrl = $sUrl."&itopversion=".ITOP_VERSION;
}
return $sUrl;
});
return $sUrl;
});
// Filter to add a module's version to an url
$filters[] = new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
// Filter to add a module's version to an url
$filters[] = new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?moduleversion=".$sModuleVersion;
}
else
{
$sUrl = $sUrl."&moduleversion=".$sModuleVersion;
}
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?moduleversion=".$sModuleVersion;
}
else
{
$sUrl = $sUrl."&moduleversion=".$sModuleVersion;
}
return $sUrl;
});
return $sUrl;
});
return $filters;
}
return $filters;
}
public function getFunctions()
{
$functions = array();
/**
* @return array|\Twig\TwigFunction[]|\Twig_SimpleFunction[]
*/
public function getFunctions()
{
$functions = array();
// Function to check our current environment
// Usage in twig: {% if is_development_environment() %}
$functions[] = new Twig_SimpleFunction('is_development_environment', function()
{
return utils::IsDevelopmentEnvironment();
});
// Function to check our current environment
// Usage in twig: {% if is_development_environment() %}
$functions[] = new Twig_SimpleFunction('is_development_environment', function () {
return utils::IsDevelopmentEnvironment();
});
// Function to get configuration parameter
// Usage in twig: {{ get_config_parameter('foo') }}
$functions[] = new Twig_SimpleFunction('get_config_parameter', function($sParamName)
{
$oConfig = MetaModel::GetConfig();
return $oConfig->Get($sParamName);
});
// Function to get configuration parameter
// Usage in twig: {{ get_config_parameter('foo') }}
$functions[] = new Twig_SimpleFunction('get_config_parameter', function ($sParamName) {
$oConfig = MetaModel::GetConfig();
return $functions;
}
return $oConfig->Get($sParamName);
});
return $functions;
}
}

View File

@@ -31,42 +31,42 @@ use utils;
/**
* AbstractPortalUrlMaker
*
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @since 2.3.0
* @since 2.3.0
*/
abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
{
/** @var string PORTAL_ID */
/** @var string PORTAL_ID */
const PORTAL_ID = '';
/** @var \Combodo\iTop\Portal\Kernel[] $aKernels */
private static $aKernels = array();
/**
* Generate an (absolute) URL to an object, either in view or edit mode.
* Returns null if the current user is not allowed to view / edit object.
*
* @param string $sClass The class of the object
* @param int $iId The identifier of the object
* @param string $sMode edit|view
*
* @return string | null
*
* @throws Exception
* @throws CoreException
*/
/**
* Generate an (absolute) URL to an object, either in view or edit mode.
* Returns null if the current user is not allowed to view / edit object.
*
* @param string $sClass The class of the object
* @param int $iId The identifier of the object
* @param string $sMode edit|view
*
* @return string | null
*
* @throws Exception
* @throws CoreException
*/
public static function PrepareObjectURL($sClass, $iId, $sMode)
{
$sPreviousPortalId = (isset($_ENV['PORTAL_ID'])) ? $_ENV['PORTAL_ID'] : '';
$_ENV['PORTAL_ID'] = static::PORTAL_ID;
require MODULESROOT . 'itop-portal-base/portal/config/bootstrap.php';
require MODULESROOT.'itop-portal-base/portal/config/bootstrap.php';
$sUrl = self::DoPrepareObjectURL($sClass, $iId, $sMode);
if(!empty($sPreviousPortalId))
if (!empty($sPreviousPortalId))
{
$_ENV['PORTAL_ID'] = $sPreviousPortalId;
}
@@ -76,7 +76,7 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
/**
* @param string $sClass
* @param int $iId
* @param int $iId
* @param string $sMode
*
* @return string|null
@@ -155,9 +155,9 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
*/
private static function GetKernelInstance()
{
if(!array_key_exists(static::PORTAL_ID, self::$aKernels))
if (!array_key_exists(static::PORTAL_ID, self::$aKernels))
{
self::$aKernels[static::PORTAL_ID] = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
self::$aKernels[static::PORTAL_ID] = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
self::$aKernels[static::PORTAL_ID]->boot();
}

View File

@@ -1,19 +1,39 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 28/02/19
* Time: 16:59
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\VariableAccessor;
/**
* Class AbstractStringVariableAccessor
*
* @package Combodo\iTop\Portal\VariableAccessor
* @since 2.7.0
*/
abstract class AbstractStringVariableAccessor extends AbstractVariableAccessor
{
public function __toString()
{
return $this->getVariable();
}
/**
* @return string
*/
public function __toString()
{
return $this->getVariable();
}
}

View File

@@ -1,30 +1,50 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 28/02/19
* Time: 16:59
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\VariableAccessor;
/**
* Class AbstractVariableAccessor
*
* @package Combodo\iTop\Portal\VariableAccessor
* @since 2.7.0
*/
abstract class AbstractVariableAccessor
{
/**
* @var string
*/
private $mStoredVariable;
/** @var string $storedVariable */
private $storedVariable;
/**
* @param string $mVariableToStore
* @param string $variableToStore
*/
public function __construct($mVariableToStore)
public function __construct($variableToStore)
{
$this->mStoredVariable = $mVariableToStore;
$this->storedVariable = $variableToStore;
}
/**
* @return string
*/
public function getVariable()
{
return $this->mStoredVariable;
return $this->storedVariable;
}
}

View File

@@ -19,12 +19,6 @@
*
*/
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 28/02/19
* Time: 16:59
*/
namespace Combodo\iTop\Portal\VariableAccessor;
@@ -33,15 +27,28 @@ use MetaModel;
use User;
use UserRights;
/**
* Class CombodoCurrentContactPhotoUrl
*
* @package Combodo\iTop\Portal\VariableAccessor
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class CombodoCurrentContactPhotoUrl
{
/**
* @var \User
*/
/** @var \User $oUser */
private $oUser;
/** @var string $sCombodoPortalInstanceAbsoluteUrl */
private $sCombodoPortalInstanceAbsoluteUrl;
/** @var string|null $sContactPhotoUrl */
private $sContactPhotoUrl;
/**
* CombodoCurrentContactPhotoUrl constructor.
*
* @param \User $oUser
* @param string $sCombodoPortalInstanceAbsoluteUrl
*/
public function __construct(User $oUser, $sCombodoPortalInstanceAbsoluteUrl)
{
$this->oUser = $oUser;
@@ -51,10 +58,11 @@ class CombodoCurrentContactPhotoUrl
/**
* @return string
* @throws \CoreException
*/
public function __toString()
{
if($this->sContactPhotoUrl === null)
if ($this->sContactPhotoUrl === null)
{
$this->sContactPhotoUrl = $this->ComputeContactPhotoUrl();
}
@@ -75,6 +83,7 @@ class CombodoCurrentContactPhotoUrl
// - Checking if we can load the contact
try
{
/** @var \cmdbAbstractObject $oContact */
$oContact = UserRights::GetContactObject();
}
catch (Exception $e)
@@ -94,6 +103,7 @@ class CombodoCurrentContactPhotoUrl
{
if (MetaModel::IsValidAttCode(get_class($oContact), 'picture'))
{
/** @var \ormDocument $oImage */
$oImage = $oContact->Get('picture');
if (is_object($oImage) && !$oImage->IsEmpty())
{

View File

@@ -1,13 +1,33 @@
<?php
/**
* Created by Bruno DA SILVA, working for Combodo
* Date: 04/03/19
* Time: 17:43
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
namespace Combodo\iTop\Portal\VariableAccessor;
/**
* Class CombodoPortalInstanceConf
*
* @package Combodo\iTop\Portal\VariableAccessor
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
*/
class CombodoPortalInstanceConf extends AbstractVariableAccessor
{

View File

@@ -1,21 +1,24 @@
<?php
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
/**
* Backward Compatibility file for default portal.
@@ -37,15 +40,15 @@
);
// Load current environment
if (file_exists(__DIR__ . '/../../approot.inc.php'))
if (file_exists(__DIR__.'/../../approot.inc.php'))
{
require_once __DIR__ . '/../../approot.inc.php'; // When in env-xxxx folder
require_once __DIR__.'/../../approot.inc.php'; // When in env-xxxx folder
}
else
{
require_once __DIR__ . '/../../../approot.inc.php'; // When in datamodels/x.x folder
require_once __DIR__.'/../../../approot.inc.php'; // When in datamodels/x.x folder
}
require_once APPROOT . 'application/startup.inc.php';
require_once APPROOT.'application/startup.inc.php';
// Protection against setup in the following configuration : ITIL Ticket with Enhanced Portal selected but neither UserRequest or Incident. Which would crash the portal.
if (!class_exists('UserRequest') && !class_exists('Incident'))
@@ -58,4 +61,4 @@ $sDir = basename(__DIR__);
define('PORTAL_ID', $sDir);
// Load frontal
require_once MODULESROOT . 'itop-portal-base/index.php';
require_once MODULESROOT.'itop-portal-base/index.php';

View File

@@ -25,14 +25,14 @@ require_once APPROOT.'/lib/composer-vendor/autoload.php';
/**
* iTopPortalEditUrlMaker
*
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @since 2.3.0
* @since 2.3.0
*/
class iTopPortalEditUrlMaker extends AbstractPortalUrlMaker
{
/** @var string PORTAL_ID */
/** @var string PORTAL_ID */
const PORTAL_ID = 'itop-portal';
}
@@ -41,7 +41,7 @@ class iTopPortalEditUrlMaker extends AbstractPortalUrlMaker
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @since 2.3.0
* @since 2.3.0
*/
class iTopPortalViewUrlMaker extends iTopPortalEditUrlMaker
{
@@ -52,7 +52,7 @@ class iTopPortalViewUrlMaker extends iTopPortalEditUrlMaker
{
return static::PrepareObjectURL($sClass, $iId, 'view');
}
}
// Default portal hyperlink (for notifications) is the edit hyperlink

View File

@@ -1,5 +1,6 @@
<?php
/** @noinspection PhpUnhandledExceptionInspection */
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-portal/2.7.0', array(