Merge branch 'support/3.2' into develop

This commit is contained in:
odain
2025-11-07 20:33:14 +01:00
1837 changed files with 33034 additions and 34549 deletions

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*

View File

@@ -58,26 +58,25 @@ $oKPI->ComputeAndReport('Load portal lists definition');
// A dedicated listener 'CssFromSassCompiler' exists to compile files again when by-passing HTTP cache.
// This is to keep developers comfort when tuning the SCSS files.
$oKPI = new ExecutionKPI();
$aImportPaths = array($_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/');
$aImportPaths = [$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/'];
$aPortalConf = $container->getParameter('combodo.portal.instance.conf');
foreach ($aPortalConf['properties']['themes'] as $sKey => $value)
{
if (!is_array($value))
{
$aPortalConf['properties']['themes'][$sKey] = utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$value,
$aImportPaths);
}
else
{
$aValues = array();
foreach ($value as $sSubValue)
{
$aValues[] = utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$sSubValue,
$aImportPaths);
foreach ($aPortalConf['properties']['themes'] as $sKey => $value) {
if (!is_array($value)) {
$aPortalConf['properties']['themes'][$sKey] = utils::GetCSSFromSASS(
'env-'.utils::GetCurrentEnvironment().'/'.$value,
$aImportPaths
);
} else {
$aValues = [];
foreach ($value as $sSubValue) {
$aValues[] = utils::GetCSSFromSASS(
'env-'.utils::GetCurrentEnvironment().'/'.$sSubValue,
$aImportPaths
);
}
$aPortalConf['properties']['themes'][$sKey] = $aValues;
}
}
$oKPI->ComputeAndReport('Generating CSS files');
$container->setParameter('combodo.portal.instance.conf', $aPortalConf);
$container->setParameter('combodo.portal.instance.conf', $aPortalConf);

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -24,8 +25,7 @@ use Symfony\Component\Routing\Route;
$oRouteCollection = new RouteCollection();
$aRoutes = ItopExtensionsExtraRoutes::GetRoutes();
foreach ($aRoutes as $aRoute)
{
foreach ($aRoutes as $aRoute) {
$aRoute['values'] = (isset($aRoute['values'])) ? $aRoute['values'] : [];
$aRoute['asserts'] = (isset($aRoute['asserts'])) ? $aRoute['asserts'] : [];
@@ -42,4 +42,4 @@ foreach ($aRoutes as $aRoute)
);
}
return $oRouteCollection;
return $oRouteCollection;

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -45,4 +46,4 @@ return static function (ContainerConfigurator $oContainer) {
->autoconfigure();
}
};
};

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -26,7 +27,6 @@ require_once MODULESROOT.'itop-portal-base/portal/config/bootstrap.php';
$oContext = new ContextTag(ContextTag::TAG_PORTAL);
$oContext2 = new ContextTag('Portal:'.$_ENV['PORTAL_ID']);
$oKPI = new ExecutionKPI();
// Note: Manually refactored ternary condition to be PHP 5.x compatible
@@ -52,10 +52,8 @@ $oResponse = $oKernel->handle($oRequest);
$oResponse->send();
$oKPI->ComputeAndReport('Page execution and rendering');
$oKPI = new ExecutionKPI();
$oKernel->terminate($oRequest, $oResponse);
$oKPI->ComputeAndReport('Symfony kernel termination');
ExecutionKPI::ReportStats();
ExecutionKPI::ReportStats();

View File

@@ -43,34 +43,34 @@ use ModuleDesign;
abstract class AbstractBrick implements TemplatesProviderInterface
{
/** @var string ENUM_DATA_LOADING_LAZY */
const ENUM_DATA_LOADING_LAZY = 'lazy';
public const ENUM_DATA_LOADING_LAZY = 'lazy';
/** @var string ENUM_DATA_LOADING_FULL */
const ENUM_DATA_LOADING_FULL = 'full';
public const ENUM_DATA_LOADING_FULL = 'full';
/** @var string ENUM_DATA_LOADING_AUTO */
const ENUM_DATA_LOADING_AUTO = 'auto';
public const ENUM_DATA_LOADING_AUTO = 'auto';
/** @var bool DEFAULT_MANDATORY */
const DEFAULT_MANDATORY = true;
public const DEFAULT_MANDATORY = true;
/** @var bool DEFAULT_ACTIVE */
const DEFAULT_ACTIVE = true;
public const DEFAULT_ACTIVE = true;
/** @var bool DEFAULT_VISIBLE */
const DEFAULT_VISIBLE = true;
public const DEFAULT_VISIBLE = true;
/** @var float DEFAULT_RANK */
const DEFAULT_RANK = 1.0;
public const DEFAULT_RANK = 1.0;
/** @var string|null DEFAULT_PAGE_TEMPLATE_PATH @deprecated since 3.2.1 */
const DEFAULT_PAGE_TEMPLATE_PATH = null;
public const DEFAULT_PAGE_TEMPLATE_PATH = null;
/** @var string DEFAULT_TITLE */
const DEFAULT_TITLE = '';
public const DEFAULT_TITLE = '';
/** @var string|null DEFAULT_DESCRIPTION */
const DEFAULT_DESCRIPTION = null;
public const DEFAULT_DESCRIPTION = null;
/** @var string DEFAULT_DATA_LOADING */
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_AUTO;
public const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_AUTO;
/** @var string DEFAULT_ALLOWED_PROFILES_OQL */
const DEFAULT_ALLOWED_PROFILES_OQL = '';
public const DEFAULT_ALLOWED_PROFILES_OQL = '';
/** @var string DEFAULT_DENIED_PROFILES_OQL */
const DEFAULT_DENIED_PROFILES_OQL = '';
public const DEFAULT_DENIED_PROFILES_OQL = '';
/** @var string TEMPLATES_BASE_PATH */
const TEMPLATES_BASE_PATH = 'itop-portal-base/portal/templates/bricks/';
public const TEMPLATES_BASE_PATH = 'itop-portal-base/portal/templates/bricks/';
/** @var string $sId */
protected $sId;
@@ -105,8 +105,9 @@ abstract class AbstractBrick implements TemplatesProviderInterface
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'layout.html.twig'),
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH.'layout.html.twig'),
);
}
@@ -135,9 +136,9 @@ abstract class AbstractBrick implements TemplatesProviderInterface
*
* @return array
*/
static function GetEnumDataLoadingValues()
public static function GetEnumDataLoadingValues()
{
return array(self::ENUM_DATA_LOADING_LAZY, self::ENUM_DATA_LOADING_FULL, self::ENUM_DATA_LOADING_AUTO);
return [self::ENUM_DATA_LOADING_LAZY, self::ENUM_DATA_LOADING_FULL, self::ENUM_DATA_LOADING_AUTO];
}
/**
@@ -155,8 +156,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
$this->sTitle = static::DEFAULT_TITLE;
$this->sDescription = static::DEFAULT_DESCRIPTION;
$this->sDataLoading = static::DEFAULT_DATA_LOADING;
$this->aAllowedProfiles = array();
$this->aDeniedProfiles = array();
$this->aAllowedProfiles = [];
$this->aDeniedProfiles = [];
$this->sAllowedProfilesOql = static::DEFAULT_ALLOWED_PROFILES_OQL;
$this->sDeniedProfilesOql = static::DEFAULT_DENIED_PROFILES_OQL;
}
@@ -297,8 +298,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the brick id
*
* @param string $sId
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetId($sId)
{
@@ -310,8 +311,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets if the brick is mandatory
*
* @param boolean $bMandatory
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetMandatory($bMandatory)
{
@@ -336,8 +337,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets if the brick is active
*
* @param boolean $bActive
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetActive($bActive)
{
@@ -349,8 +350,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the rank of the brick
*
* @param float $fRank
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetRank($fRank)
{
@@ -362,15 +363,15 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the page template path of the brick
*
* @param string $sPageTemplatePath
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @deprecated since 3.2.1 use SetTemplatePath('page') instead
*/
public function SetPageTemplatePath($sPageTemplatePath)
{
$this->sPageTemplatePath = $sPageTemplatePath;
$this->SetTemplatePath( 'page', $sPageTemplatePath);
$this->SetTemplatePath('page', $sPageTemplatePath);
return $this;
}
@@ -378,8 +379,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the title of the brick
*
* @param string $sTitle
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetTitle($sTitle)
{
@@ -391,8 +392,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the description of the brick
*
* @param string $sDescription
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetDescription($sDescription)
{
@@ -404,8 +405,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the data loading mode of the brick
*
* @param string $sDataLoading
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetDataLoading($sDataLoading)
{
@@ -444,8 +445,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the allowed profiles oql query for the brick
*
* @param string $sAllowedProfilesOql
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetAllowedProfilesOql($sAllowedProfilesOql)
{
@@ -457,8 +458,8 @@ abstract class AbstractBrick implements TemplatesProviderInterface
* Sets the denied profiles oql query for the brick
*
* @param string $sDeniedProfilesOql
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*/
public function SetDeniedProfilesOql($sDeniedProfilesOql)
{
@@ -489,8 +490,7 @@ abstract class AbstractBrick implements TemplatesProviderInterface
*/
public function RemoveAllowedProfile($sProfile)
{
if (isset($this->aAllowedProfiles[$sProfile]))
{
if (isset($this->aAllowedProfiles[$sProfile])) {
unset($this->aAllowedProfiles[$sProfile]);
}
@@ -530,8 +530,7 @@ abstract class AbstractBrick implements TemplatesProviderInterface
*/
public function RemoveDeniedProfile($sProfile)
{
if (isset($this->aDeniedProfiles[$sProfile]))
{
if (isset($this->aDeniedProfiles[$sProfile])) {
unset($this->aDeniedProfiles[$sProfile]);
}
@@ -560,7 +559,7 @@ abstract class AbstractBrick implements TemplatesProviderInterface
*/
public function IsGrantedForProfile($sProfile)
{
return $this->IsGrantedForProfiles(array($sProfile));
return $this->IsGrantedForProfiles([$sProfile]);
}
/**
@@ -577,27 +576,21 @@ abstract class AbstractBrick implements TemplatesProviderInterface
{
$bGranted = true;
if ($this->HasAllowedProfiles())
{
if ($this->HasAllowedProfiles()) {
// We set $bGranted to false as the user must explicitly have an allowed profile to be granted
$bGranted = false;
foreach ($aProfiles as $sProfile)
{
if (in_array($sProfile, $this->aAllowedProfiles))
{
foreach ($aProfiles as $sProfile) {
if (in_array($sProfile, $this->aAllowedProfiles)) {
$bGranted = true;
break;
}
}
}
if ($this->HasDeniedProfiles())
{
foreach ($aProfiles as $sProfile)
{
if (in_array($sProfile, $this->aDeniedProfiles))
{
if ($this->HasDeniedProfiles()) {
foreach ($aProfiles as $sProfile) {
if (in_array($sProfile, $this->aDeniedProfiles)) {
$bGranted = false;
break;
}
@@ -629,18 +622,15 @@ abstract class AbstractBrick implements TemplatesProviderInterface
public function LoadFromXml(DesignElement $oMDElement)
{
// Checking mandatory elements
if (!$oMDElement->hasAttribute('id'))
{
if (!$oMDElement->hasAttribute('id')) {
throw new DOMFormatException('Brick node must have both id and xsi:type attributes defined', 0, null, $oMDElement);
}
$this->SetId($oMDElement->getAttribute('id'));
// Checking others elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode) {
switch ($oBrickSubNode->nodeName) {
case 'mandatory':
$this->SetMandatory(($oBrickSubNode->GetText() === 'no') ? false : true);
break;
@@ -649,15 +639,13 @@ abstract class AbstractBrick implements TemplatesProviderInterface
break;
case 'rank':
$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
if ($oOptionalNode !== null)
{
if ($oOptionalNode !== null) {
$this->SetRank((float)$oOptionalNode->GetText(static::DEFAULT_RANK));
}
break;
case 'templates':
$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id='.ModuleDesign::XPathQuote('page').']');
if ($oTemplateNodeList->length > 0)
{
if ($oTemplateNodeList->length > 0) {
/** @var \Combodo\iTop\DesignElement $oTemplateNode */
$oTemplateNode = $oTemplateNodeList->item(0);
$this->SetTemplatePath('page', $oTemplateNode->GetText(static::DEFAULT_PAGE_TEMPLATE_PATH));
@@ -665,8 +653,7 @@ abstract class AbstractBrick implements TemplatesProviderInterface
break;
case 'title':
$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
if ($oOptionalNode !== null)
{
if ($oOptionalNode !== null) {
$this->SetTitle($oOptionalNode->GetText(static::DEFAULT_TITLE));
}
break;
@@ -678,16 +665,17 @@ abstract class AbstractBrick implements TemplatesProviderInterface
break;
case 'security':
/** @var \Combodo\iTop\DesignElement $oSecurityNode */
foreach ($oBrickSubNode->GetNodes('*') 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);
foreach ($oBrickSubNode->GetNodes('*') 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
);
}
switch ($oSecurityNode->nodeName)
{
switch ($oSecurityNode->nodeName) {
case 'denied_profiles':
$this->SetDeniedProfilesOql($oSecurityNode->GetText());
break;

View File

@@ -38,11 +38,11 @@ use DOMFormatException;
class AggregatePageBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-tachometer-alt';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-tachometer-alt fa-2x';
public const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-tachometer-alt';
public const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-tachometer-alt fa-2x';
/** @var string @deprecated since 3.2.1 */
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/aggregate-page/layout.html.twig';
public const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/aggregate-page/layout.html.twig';
// Overloaded variables
public static $sRouteName = 'p_aggregatepage_brick';
@@ -50,21 +50,22 @@ class AggregatePageBrick extends PortalBrick
/**
* @var string[] list of bricks to use, ordered by rank (key=id, value=rank)
*/
private $aAggregatePageBricks = array();
private $aAggregatePageBricks = [];
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'aggregate-page/layout.html.twig')
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH.'aggregate-page/layout.html.twig')
);
}
/**
* AggregatePageBrick constructor.
*/
function __construct()
public function __construct()
{
parent::__construct();
@@ -83,25 +84,24 @@ class AggregatePageBrick extends PortalBrick
parent::LoadFromXml($oMDElement);
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
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', 0,
null, $oAggregatePageBrickNode);
foreach ($oBrickSubNode->GetNodes('./aggregate_page_brick') as $oAggregatePageBrickNode) {
if (!$oAggregatePageBrickNode->hasAttribute('id')) {
throw new DOMFormatException(
'AggregatePageBrick : must have an id attribute',
0,
null,
$oAggregatePageBrickNode
);
}
$sBrickName = $oAggregatePageBrickNode->getAttribute('id');
$iBrickRank = static::DEFAULT_RANK;
$oOptionalNode = $oAggregatePageBrickNode->GetOptionalElement('rank');
if ($oOptionalNode !== null)
{
if ($oOptionalNode !== null) {
$iBrickRank = $oOptionalNode->GetText();
}
@@ -123,5 +123,4 @@ class AggregatePageBrick extends PortalBrick
return $this->aAggregatePageBricks;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -67,8 +68,8 @@ class BrickCollection
$this->aAllowedBricks = null;
$this->iDisplayedInHome = 0;
$this->iDisplayedInNavigationMenu = 0;
$this->aHomeOrdering = array();
$this->aNavigationMenuOrdering = array();
$this->aHomeOrdering = [];
$this->aNavigationMenuOrdering = [];
$this->Load();
}
@@ -84,8 +85,7 @@ class BrickCollection
public function __call($method, $arguments)
{
// Made for cleaner/easier access from twig (eg. app['brick_collection'].bricks)
switch ($method)
{
switch ($method) {
case 'bricks':
return $this->GetBricks();
break;
@@ -128,10 +128,8 @@ class BrickCollection
*/
public function GetBrickById($sId)
{
foreach ($this->GetBricks() as $oBrick)
{
if ($oBrick->GetId() === $sId)
{
foreach ($this->GetBricks() as $oBrick) {
if ($oBrick->GetId() === $sId) {
return $oBrick;
}
}
@@ -146,19 +144,15 @@ class BrickCollection
{
$aRawBrickList = $this->GetRawBrickList();
foreach ($aRawBrickList as $oBrick)
{
foreach ($aRawBrickList as $oBrick) {
ApplicationHelper::LoadBrickSecurity($oBrick);
if ($oBrick->GetActive() && $oBrick->IsGrantedForProfiles(UserRights::ListProfiles()))
{
if ($oBrick->GetActive() && $oBrick->IsGrantedForProfiles(UserRights::ListProfiles())) {
$this->aAllowedBricks[] = $oBrick;
if ($oBrick->GetVisibleHome())
{
if ($oBrick->GetVisibleHome()) {
$this->iDisplayedInHome++;
}
if ($oBrick->GetVisibleNavigationMenu())
{
if ($oBrick->GetVisibleNavigationMenu()) {
$this->iDisplayedInNavigationMenu++;
}
}
@@ -191,35 +185,30 @@ class BrickCollection
*/
private function GetRawBrickList()
{
$aBricks = array();
$aBricks = [];
/** @var \Combodo\iTop\DesignElement $oBrickNode */
foreach ($this->oModuleDesign->GetNodes('/module_design/bricks/brick') as $oBrickNode)
{
foreach ($this->oModuleDesign->GetNodes('/module_design/bricks/brick') as $oBrickNode) {
$sBrickClass = $oBrickNode->getAttribute('xsi:type');
try
{
if (class_exists($sBrickClass))
{
try {
if (class_exists($sBrickClass)) {
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oBrick */
$oBrick = new $sBrickClass();
// Load the brick specific properties from its XML definition
$oBrick->LoadFromXml($oBrickNode);
$aBricks[] = $oBrick;
} else {
throw new DOMFormatException(
'Unknown brick class "'.$sBrickClass.'" from xsi:type attribute',
null,
null,
$oBrickNode
);
}
else
{
throw new DOMFormatException('Unknown brick class "'.$sBrickClass.'" from xsi:type attribute', null,
null, $oBrickNode);
}
}
catch (DOMFormatException $e)
{
} catch (DOMFormatException $e) {
throw new Exception('Could not create brick ('.$sBrickClass.') from XML because of a DOM problem : '.$e->getMessage());
}
catch (Exception $e)
{
} catch (Exception $e) {
throw new Exception('Could not create brick ('.$sBrickClass.') from XML : '.$oBrickNode->Dump().' '.$e->getMessage());
}
}
@@ -227,4 +216,4 @@ class BrickCollection
return $aBricks;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -30,5 +31,4 @@ use Exception;
*/
class BrickNotFoundException extends Exception
{
}
}

View File

@@ -35,77 +35,76 @@ use DOMFormatException;
class BrowseBrick extends PortalBrick
{
/**
* @var string DEFAULT_PAGE_TEMPLATE_PATH
* @var string DEFAULT_PAGE_TEMPLATE_PATH
* @deprecated 3.2.1
*/
const DEFAULT_MODE_LIST_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig';
public const DEFAULT_MODE_LIST_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig';
/**
* @var string DEFAULT_MODE_MOSAIC_TEMPLATE_PATH
* @deprecated 3.2.1
*/
const DEFAULT_MODE_MOSAIC_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig';
public const DEFAULT_MODE_MOSAIC_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig';
/**
* @var string DEFAULT_MODE_TREE_TEMPLATE_PATH
* @deprecated 3.2.1
*/
const DEFAULT_MODE_TREE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig';
public const DEFAULT_MODE_TREE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig';
/** @var string ENUM_BROWSE_MODE_LIST */
const ENUM_BROWSE_MODE_LIST = 'list';
public const ENUM_BROWSE_MODE_LIST = 'list';
/** @var string ENUM_BROWSE_MODE_TREE */
const ENUM_BROWSE_MODE_TREE = 'tree';
public const ENUM_BROWSE_MODE_TREE = 'tree';
/** @var string ENUM_BROWSE_MODE_MOSAIC */
const ENUM_BROWSE_MODE_MOSAIC = 'mosaic';
public const ENUM_BROWSE_MODE_MOSAIC = 'mosaic';
/** @var string ENUM_ACTION_VIEW */
const ENUM_ACTION_VIEW = 'view';
public const ENUM_ACTION_VIEW = 'view';
/** @var string ENUM_ACTION_EDIT */
const ENUM_ACTION_EDIT = 'edit';
public const ENUM_ACTION_EDIT = 'edit';
/** @var string ENUM_ACTION_DRILLDOWN */
const ENUM_ACTION_DRILLDOWN = 'drilldown';
public const ENUM_ACTION_DRILLDOWN = 'drilldown';
/** @var string ENUM_ACTION_CREATE_FROM_THIS */
const ENUM_ACTION_CREATE_FROM_THIS = 'create_from_this';
public 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';
public 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';
public 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';
public 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';
public const ENUM_ACTION_ICON_CLASS_CREATE_FROM_THIS = 'glyphicon glyphicon-edit';
/** @var string ENUM_FACTORY_TYPE_METHOD */
const ENUM_FACTORY_TYPE_METHOD = 'method';
public const ENUM_FACTORY_TYPE_METHOD = 'method';
/** @var string ENUM_FACTORY_TYPE_CLASS */
const ENUM_FACTORY_TYPE_CLASS = 'class';
public const ENUM_FACTORY_TYPE_CLASS = 'class';
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-map';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-map fa-2x';
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_FULL;
public const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-map';
public const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-map fa-2x';
public const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_FULL;
/** @var string DEFAULT_LEVEL_NAME_ATT */
const DEFAULT_LEVEL_NAME_ATT = 'name';
public const DEFAULT_LEVEL_NAME_ATT = 'name';
/** @var string DEFAULT_BROWSE_MODE */
const DEFAULT_BROWSE_MODE = self::ENUM_BROWSE_MODE_LIST;
public const DEFAULT_BROWSE_MODE = self::ENUM_BROWSE_MODE_LIST;
/** @var string DEFAULT_ACTION */
const DEFAULT_ACTION = self::ENUM_ACTION_DRILLDOWN;
public const DEFAULT_ACTION = self::ENUM_ACTION_DRILLDOWN;
/** @var string DEFAULT_ACTION_OPENING_TARGET */
const DEFAULT_ACTION_OPENING_TARGET = self::ENUM_OPENING_TARGET_MODAL;
public const DEFAULT_ACTION_OPENING_TARGET = self::ENUM_OPENING_TARGET_MODAL;
/** @var int DEFAULT_LIST_LENGTH */
const DEFAULT_LIST_LENGTH = 20;
public const DEFAULT_LIST_LENGTH = 20;
// Overloaded variables
public static $sRouteName = 'p_browse_brick';
/** @var array $aBrowseModes */
public static $aBrowseModes = array(
public static $aBrowseModes = [
self::ENUM_BROWSE_MODE_LIST,
self::ENUM_BROWSE_MODE_TREE,
self::ENUM_BROWSE_MODE_MOSAIC,
);
];
/** @var array $aLevels */
protected $aLevels;
@@ -120,11 +119,12 @@ class BrowseBrick extends PortalBrick
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'browse/layout.html.twig'),
TemplateDefinitionDto::Create('page_list', static::TEMPLATES_BASE_PATH . 'browse/mode_list.html.twig'),
TemplateDefinitionDto::Create('page_tree', static::TEMPLATES_BASE_PATH . 'browse/mode_tree.html.twig'),
TemplateDefinitionDto::Create('page_mosaic', static::TEMPLATES_BASE_PATH . 'browse/mode_mosaic.html.twig'),
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH.'browse/layout.html.twig'),
TemplateDefinitionDto::Create('page_list', static::TEMPLATES_BASE_PATH.'browse/mode_list.html.twig'),
TemplateDefinitionDto::Create('page_tree', static::TEMPLATES_BASE_PATH.'browse/mode_tree.html.twig'),
TemplateDefinitionDto::Create('page_mosaic', static::TEMPLATES_BASE_PATH.'browse/mode_mosaic.html.twig'),
);
}
@@ -135,15 +135,15 @@ class BrowseBrick extends PortalBrick
{
parent::__construct();
$this->aLevels = array();
$this->aAvailablesBrowseModes = array();
$this->aLevels = [];
$this->aAvailablesBrowseModes = [];
$this->sDefaultBrowseMode = static::DEFAULT_BROWSE_MODE;
$this->iDefaultListLength = static::DEFAULT_LIST_LENGTH;
}
/**
* Compare function to sort actions by their rank attribute
*
*
* @param array $aAction1
* @param array $aAction2
*
@@ -154,13 +154,10 @@ class BrowseBrick extends PortalBrick
$bIsAction1RankSet = array_key_exists('rank', $aAction1);
$bIsAction2RankSet = array_key_exists('rank', $aAction2);
if($bIsAction1RankSet && $bIsAction2RankSet)
{
//If a1 == a2 return 0, if a1 > a2 return 1 else return -1
if ($bIsAction1RankSet && $bIsAction2RankSet) {
//If a1 == a2 return 0, if a1 > a2 return 1 else return -1
return ($aAction1['rank'] === $aAction2['rank'] ? $aAction1['default_rank'] - $aAction2['default_rank'] : $aAction1['rank'] - $aAction2['rank']);
}
else
{
} else {
//If a1 == a2 == null return 0, if a2 is null and not a1 return 1 else return -1
return ($bIsAction1RankSet === $bIsAction2RankSet ? $aAction1['default_rank'] - $aAction2['default_rank'] : ($bIsAction1RankSet ? 1 : -1));
}
@@ -255,7 +252,8 @@ class BrowseBrick extends PortalBrick
*
* @return $this
*/
public function SetDefaultListLength($iDefaultListLength) {
public function SetDefaultListLength($iDefaultListLength)
{
$this->iDefaultListLength = $iDefaultListLength;
return $this;
}
@@ -293,8 +291,7 @@ class BrowseBrick extends PortalBrick
*/
public function RemoveLevels($sLevel)
{
if (isset($this->aLevels[$sLevel]))
{
if (isset($this->aLevels[$sLevel])) {
unset($this->aLevels[$sLevel]);
}
@@ -309,7 +306,7 @@ class BrowseBrick extends PortalBrick
*
* @return \Combodo\iTop\Portal\Brick\BrowseBrick
*/
public function AddAvailableBrowseMode($sModeId, $aData = array())
public function AddAvailableBrowseMode($sModeId, $aData = [])
{
$this->aAvailablesBrowseModes[$sModeId] = $aData;
@@ -325,8 +322,7 @@ class BrowseBrick extends PortalBrick
*/
public function RemoveAvailableBrowseMode($sModeId)
{
if (isset($this->aAvailablesBrowseModes[$sModeId]))
{
if (isset($this->aAvailablesBrowseModes[$sModeId])) {
unset($this->aAvailablesBrowseModes[$sModeId]);
}
@@ -349,43 +345,38 @@ class BrowseBrick extends PortalBrick
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode) {
switch ($oBrickSubNode->nodeName) {
case 'levels':
/** @var \Combodo\iTop\DesignElement $oLevelNode */
foreach ($oBrickSubNode->GetNodes('*') as $oLevelNode)
{
if ($oLevelNode->nodeName === 'level')
{
foreach ($oBrickSubNode->GetNodes('*') as $oLevelNode) {
if ($oLevelNode->nodeName === 'level') {
$this->AddLevel($this->LoadLevelFromXml($oLevelNode));
}
}
break;
case 'browse_modes':
/** @var \Combodo\iTop\DesignElement $oBrowseModeNode */
foreach ($oBrickSubNode->GetNodes('*') as $oBrowseModeNode)
{
switch ($oBrowseModeNode->nodeName)
{
foreach ($oBrickSubNode->GetNodes('*') as $oBrowseModeNode) {
switch ($oBrowseModeNode->nodeName) {
case 'availables':
/** @var \Combodo\iTop\DesignElement $oModeNode */
foreach ($oBrowseModeNode->GetNodes('*') as $oModeNode)
{
if (!$oModeNode->hasAttribute('id'))
{
throw new DOMFormatException('BrowseBrick: Browse mode must have a unique ID attribute', 0,
null, $oModeNode);
foreach ($oBrowseModeNode->GetNodes('*') as $oModeNode) {
if (!$oModeNode->hasAttribute('id')) {
throw new DOMFormatException(
'BrowseBrick: Browse mode must have a unique ID attribute',
0,
null,
$oModeNode
);
}
$sModeId = $oModeNode->getAttribute('id');
$aModeData = array();
$aModeData = [];
// Checking if the browse mode has a specific template
$oTemplateNode = $oModeNode->GetOptionalElement('template');
if (($oTemplateNode !== null) && ($oTemplateNode->GetText() !== null))
{
if (($oTemplateNode !== null) && ($oTemplateNode->GetText() !== null)) {
$this->SetTemplatePath('page_'.$sModeId, $oTemplateNode->GetText());
}
@@ -400,12 +391,12 @@ class BrowseBrick extends PortalBrick
break;
case 'default_list_length':
$iNodeDefaultListLength = (int)$oBrickSubNode->GetText(static::DEFAULT_LIST_LENGTH);
if(!in_array($iNodeDefaultListLength, array(10, 20, 50, -1),true))
{
if (!in_array($iNodeDefaultListLength, [10, 20, 50, -1], true)) {
throw new DOMFormatException(
'BrowseBrick: Default list length must be contained in list length options. Expected -1/10/20/50, '.$iNodeDefaultListLength.' given.',
null,
null, $oBrickSubNode
null,
$oBrickSubNode
);
}
$this->SetDefaultListLength($iNodeDefaultListLength);
@@ -414,19 +405,18 @@ class BrowseBrick extends PortalBrick
}
// Checking that the brick has at least a browse mode
if (count($this->GetAvailablesBrowseModes()) === 0)
{
if (count($this->GetAvailablesBrowseModes()) === 0) {
throw new DOMFormatException('BrowseBrick : Must have at least one browse mode', 0, null, $oMDElement);
}
// 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);
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);
}
// Checking that the brick has at least a level
if (count($this->GetLevels()) === 0)
{
if (count($this->GetLevels()) === 0) {
throw new DOMFormatException('BrowseBrick : Must have at least one level', 0, null, $oMDElement);
}
@@ -444,39 +434,41 @@ class BrowseBrick extends PortalBrick
*/
protected function LoadLevelFromXml(DesignElement $oMDElement)
{
$aLevel = array(
$aLevel = [
'parent_att' => null,
'tooltip_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())),
);
'fields' => [],
'actions' => ['default' => ['type' => static::DEFAULT_ACTION, 'rules' => []]],
];
// Getting level ID
if ($oMDElement->hasAttribute('id') && $oMDElement->getAttribute('id') !== '')
{
if ($oMDElement->hasAttribute('id') && $oMDElement->getAttribute('id') !== '') {
$aLevel['id'] = $oMDElement->getAttribute('id');
}
else
{
throw new DOMFormatException('BrowseBrick : level tag without "id" attribute. It must have one and it must not be empty', null,
null, $oMDElement);
} else {
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->GetNodes('*') as $oLevelPropertyNode)
{
switch ($oLevelPropertyNode->nodeName)
{
foreach ($oMDElement->GetNodes('*') as $oLevelPropertyNode) {
switch ($oLevelPropertyNode->nodeName) {
case 'class':
$sClass = $oLevelPropertyNode->GetText();
if ($sClass === '')
{
throw new DOMFormatException('BrowseBrick : class tag is empty. Must contain Classname', null, null,
$oLevelPropertyNode);
if ($sClass === '') {
throw new DOMFormatException(
'BrowseBrick : class tag is empty. Must contain Classname',
null,
null,
$oLevelPropertyNode
);
}
$aLevel['oql'] = 'SELECT '.$sClass;
@@ -484,10 +476,13 @@ class BrowseBrick extends PortalBrick
case 'oql':
$sOql = $oLevelPropertyNode->GetText();
if ($sOql === '')
{
throw new DOMFormatException('BrowseBrick : oql tag is empty. Must contain OQL statement', null, null,
$oLevelPropertyNode);
if ($sOql === '') {
throw new DOMFormatException(
'BrowseBrick : oql tag is empty. Must contain OQL statement',
null,
null,
$oLevelPropertyNode
);
}
$aLevel['oql'] = $sOql;
@@ -508,25 +503,23 @@ class BrowseBrick extends PortalBrick
case 'fields':
$sTagName = $oLevelPropertyNode->nodeName;
if ($oLevelPropertyNode->hasChildNodes())
{
$aLevel[$sTagName] = array();
if ($oLevelPropertyNode->hasChildNodes()) {
$aLevel[$sTagName] = [];
/** @var \Combodo\iTop\DesignElement $oFieldNode */
foreach ($oLevelPropertyNode->GetNodes('*') as $oFieldNode)
{
if ($oFieldNode->hasAttribute('id') && $oFieldNode->getAttribute('id') !== '')
{
$aLevel[$sTagName][$oFieldNode->getAttribute('id')] = array('hidden' => false);
}
else
{
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/* tag must have an "id" attribute and it must not be empty',
null, null, $oFieldNode);
foreach ($oLevelPropertyNode->GetNodes('*') as $oFieldNode) {
if ($oFieldNode->hasAttribute('id') && $oFieldNode->getAttribute('id') !== '') {
$aLevel[$sTagName][$oFieldNode->getAttribute('id')] = ['hidden' => false];
} else {
throw new DOMFormatException(
'BrowseBrick : '.$sTagName.'/* tag must have an "id" attribute and it must not be empty',
null,
null,
$oFieldNode
);
}
$oFieldSubNode = $oFieldNode->GetOptionalElement('hidden');
if ($oFieldSubNode !== null)
{
if ($oFieldSubNode !== null) {
$aLevel[$sTagName][$oFieldNode->getAttribute('id')]['hidden'] = ($oFieldSubNode->GetText() === 'true') ? true : false;
}
}
@@ -536,94 +529,84 @@ class BrowseBrick extends PortalBrick
case 'actions':
$sTagName = $oLevelPropertyNode->nodeName;
if ($oLevelPropertyNode->hasChildNodes())
{
$aLevel[$sTagName] = array();
if ($oLevelPropertyNode->hasChildNodes()) {
$aLevel[$sTagName] = [];
$iActionDefaultRank = 0;
/** @var \Combodo\iTop\DesignElement $oActionNode */
foreach ($oLevelPropertyNode->GetNodes('*') as $oActionNode)
{
if ($oActionNode->hasAttribute('id') && $oActionNode->getAttribute('id') !== '')
{
$aTmpAction = array(
foreach ($oLevelPropertyNode->GetNodes('*') as $oActionNode) {
if ($oActionNode->hasAttribute('id') && $oActionNode->getAttribute('id') !== '') {
$aTmpAction = [
'type' => null,
'rules' => array(),
);
'rules' => [],
];
// Action type
$aTmpAction['type'] = ($oActionNode->hasAttribute('xsi:type') && $oActionNode->getAttribute('xsi:type') !== '') ? $oActionNode->getAttribute('xsi:type') : static::DEFAULT_ACTION;
// Action destination class
if ($aTmpAction['type'] === static::ENUM_ACTION_CREATE_FROM_THIS)
{
if ($oActionNode->GetOptionalElement('factory_method') !== null)
{
$aTmpAction['factory'] = array(
if ($aTmpAction['type'] === static::ENUM_ACTION_CREATE_FROM_THIS) {
if ($oActionNode->GetOptionalElement('factory_method') !== null) {
$aTmpAction['factory'] = [
'type' => static::ENUM_FACTORY_TYPE_METHOD,
'value' => $oActionNode->GetOptionalElement('factory_method')->GetText(),
);
}
else
{
$aTmpAction['factory'] = array(
];
} else {
$aTmpAction['factory'] = [
'type' => static::ENUM_FACTORY_TYPE_CLASS,
'value' => $oActionNode->GetUniqueElement('class')->GetText(),
);
];
}
}
// Action title
$oActionTitleNode = $oActionNode->GetOptionalElement('title');
if ($oActionTitleNode !== null)
{
if ($oActionTitleNode !== null) {
$aTmpAction['title'] = $oActionTitleNode->GetText();
}
// Action icon class
$oActionIconClassNode = $oActionNode->GetOptionalElement('icon_class');
if ($oActionIconClassNode !== null)
{
if ($oActionIconClassNode !== null) {
$aTmpAction['icon_class'] = $oActionIconClassNode->GetText();
}
// Action opening target
$oActionOpeningTargetNode = $oActionNode->GetOptionalElement('opening_target');
if ($oActionOpeningTargetNode !== null)
{
if ($oActionOpeningTargetNode !== null) {
$aTmpAction['opening_target'] = $oActionOpeningTargetNode->GetText(static::DEFAULT_ACTION_OPENING_TARGET);
}
else
{
} 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);
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);
}
$oActionRankNode = $oActionNode->GetOptionalElement('rank');
if ($oActionRankNode !== null)
{
if ($oActionRankNode !== null) {
$aTmpAction['rank'] = (int)$oActionRankNode->GetText();
}
// Action rules
/** @var \Combodo\iTop\DesignElement $oRuleNode */
foreach ($oActionNode->GetNodes('./rules/rule') as $oRuleNode)
{
if ($oRuleNode->hasAttribute('id') && $oRuleNode->getAttribute('id') !== '')
{
foreach ($oActionNode->GetNodes('./rules/rule') as $oRuleNode) {
if ($oRuleNode->hasAttribute('id') && $oRuleNode->getAttribute('id') !== '') {
$aTmpAction['rules'][] = $oRuleNode->getAttribute('id');
}
else
{
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/rules/rule tag must have an "id" attribute and it must not be empty',
null, null, $oRuleNode);
} else {
throw new DOMFormatException(
'BrowseBrick : '.$sTagName.'/rules/rule tag must have an "id" attribute and it must not be empty',
null,
null,
$oRuleNode
);
}
}
$aTmpAction['default_rank'] = $iActionDefaultRank++;
$aLevel[$sTagName][$oActionNode->getAttribute('id')] = $aTmpAction;
}
else
{
throw new DOMFormatException('BrowseBrick : '.$sTagName.'/* tag must have an "id" attribute and it must not be empty',
null, null, $oActionNode);
} else {
throw new DOMFormatException(
'BrowseBrick : '.$sTagName.'/* tag must have an "id" attribute and it must not be empty',
null,
null,
$oActionNode
);
}
}
uasort($aLevel[$sTagName], [$this, 'CompareActionsByRank']);
@@ -631,10 +614,8 @@ class BrowseBrick extends PortalBrick
break;
case 'levels':
foreach ($oLevelPropertyNode->GetNodes('*') as $oSubLevelNode)
{
if ($oSubLevelNode->nodeName === 'level')
{
foreach ($oLevelPropertyNode->GetNodes('*') as $oSubLevelNode) {
if ($oSubLevelNode->nodeName === 'level') {
$aLevel['levels'][] = $this->LoadLevelFromXml($oSubLevelNode);
}
}
@@ -644,8 +625,7 @@ class BrowseBrick extends PortalBrick
}
// Checking if level has an oql
if (!isset($aLevel['oql']) || $aLevel['oql'] === '')
{
if (!isset($aLevel['oql']) || $aLevel['oql'] === '') {
throw new DOMFormatException('BrowseBrick : must have a valid <class|oql> tag', null, null, $oMDElement);
}

View File

@@ -35,10 +35,10 @@ use DOMFormatException;
class CreateBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-plus';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-plus fa-2x';
public const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-plus';
public const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-plus fa-2x';
/** @var string DEFAULT_CLASS */
const DEFAULT_CLASS = '';
public const DEFAULT_CLASS = '';
// Overloaded variables
public static $sRouteName = 'p_create_brick';
@@ -48,14 +48,15 @@ class CreateBrick extends PortalBrick
/** @var array $aRules */
protected $aRules;
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/create/modal.html.twig';
public const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/create/modal.html.twig';
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'create/modal.html.twig')
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH.'create/modal.html.twig')
);
}
@@ -67,7 +68,7 @@ class CreateBrick extends PortalBrick
parent::__construct();
$this->sClass = static::DEFAULT_CLASS;
$this->aRules = array();
$this->aRules = [];
}
/**
@@ -134,26 +135,24 @@ class CreateBrick extends PortalBrick
// Checking specific elements
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
{
switch ($oBrickSubNode->nodeName)
{
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode) {
switch ($oBrickSubNode->nodeName) {
case 'class':
$this->SetClass($oBrickSubNode->GetText(self::DEFAULT_CLASS));
break;
case 'rules':
/** @var \Combodo\iTop\DesignElement $oRuleNode */
foreach ($oBrickSubNode->GetNodes('*') as $oRuleNode)
{
if ($oRuleNode->hasAttribute('id') && $oRuleNode->getAttribute('id') !== '')
{
foreach ($oBrickSubNode->GetNodes('*') as $oRuleNode) {
if ($oRuleNode->hasAttribute('id') && $oRuleNode->getAttribute('id') !== '') {
$this->aRules[] = $oRuleNode->getAttribute('id');
}
else
{
throw new DOMFormatException('CreateBrick: /rules/rule tag must have an "id" attribute and it must not be empty',
null, null, $oRuleNode);
} else {
throw new DOMFormatException(
'CreateBrick: /rules/rule tag must have an "id" attribute and it must not be empty',
null,
null,
$oRuleNode
);
}
}
break;

View File

@@ -35,21 +35,21 @@ use DOMFormatException;
class FilterBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
/**
* @deprecated 3.2.1
*/
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/filter/tile.html.twig';
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-search';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-search fa-2x';
/** @var string DEFAULT_TARGET_BRICK_CLASS */
const DEFAULT_TARGET_BRICK_CLASS = 'Combodo\\iTop\\Portal\\Brick\\BrowseBrick';
public const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
/**
* @deprecated 3.2.1
*/
public const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/filter/tile.html.twig';
public const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-search';
public const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-search fa-2x';
/** @var string DEFAULT_TARGET_BRICK_CLASS */
public 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';
public 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';
public const DEFAULT_SEARCH_SUBMIT_LABEL = 'Brick:Portal:Filter:SearchInput:Submit';
/** @var string DEFAULT_SEARCH_SUBMIT_CLASS */
const DEFAULT_SEARCH_SUBMIT_CLASS = '';
public const DEFAULT_SEARCH_SUBMIT_CLASS = '';
/** @var string $sTargetBrickId */
protected $sTargetBrickId;
@@ -68,8 +68,9 @@ class FilterBrick extends PortalBrick
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('tile', static::TEMPLATES_BASE_PATH . 'filter/tile.html.twig')
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('tile', static::TEMPLATES_BASE_PATH.'filter/tile.html.twig')
);
}
@@ -98,9 +99,9 @@ class FilterBrick extends PortalBrick
* @return string
*/
public function GetTargetBrickClass()
{
return $this->sTargetBrickClass;
}
{
return $this->sTargetBrickClass;
}
/**
* @return string
@@ -149,9 +150,9 @@ class FilterBrick extends PortalBrick
* @param string $sTargetBrickClass
*/
public function SetTargetBrickClass($sTargetBrickClass)
{
$this->sTargetBrickClass = $sTargetBrickClass;
}
{
$this->sTargetBrickClass = $sTargetBrickClass;
}
/**
* @param string $sTargetBrickTab
@@ -197,38 +198,34 @@ class FilterBrick extends PortalBrick
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\FilterBrick
*
* @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\FilterBrick
*
* @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)
{
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode) {
switch ($oBrickSubNode->nodeName) {
case 'target_brick':
/** @var \Combodo\iTop\DesignElement $oTargetBrickNode */
foreach ($oBrickSubNode->GetNodes('*') as $oTargetBrickNode)
{
switch ($oTargetBrickNode->nodeName)
{
case 'id':
$this->SetTargetBrickId($oTargetBrickNode->GetText());
break;
case 'type':
$this->SetTargetBrickClass($oTargetBrickNode->GetText());
break;
foreach ($oBrickSubNode->GetNodes('*') as $oTargetBrickNode) {
switch ($oTargetBrickNode->nodeName) {
case 'id':
$this->SetTargetBrickId($oTargetBrickNode->GetText());
break;
case 'type':
$this->SetTargetBrickClass($oTargetBrickNode->GetText());
break;
case 'tab':
$this->SetTargetBrickTab($oTargetBrickNode->GetText());
break;
@@ -236,12 +233,12 @@ class FilterBrick extends PortalBrick
}
break;
case 'search_placeholder_value':
// Note: We don't put the default value constant if the node is empty because we might actually want this to be empty
// Note: We don't put the default value constant if the node is empty because we might actually want this to be empty
$this->SetSearchPlaceholderValue($oBrickSubNode->GetText(''));
break;
case 'search_submit_label':
// Note: We don't put the default value constant if the node is empty because we might actually want this to be empty
$this->SetSearchSubmitLabel($oBrickSubNode->GetText(''));
// Note: We don't put the default value constant if the node is empty because we might actually want this to be empty
$this->SetSearchSubmitLabel($oBrickSubNode->GetText(''));
break;
case 'search_submit_class':
$this->SetSearchSubmitClass($oBrickSubNode->GetText(static::DEFAULT_SEARCH_SUBMIT_CLASS));
@@ -250,8 +247,7 @@ class FilterBrick extends PortalBrick
}
// Checking that the brick has at least a target brick id
if (($this->GetTargetBrickId() === null) || ($this->GetTargetBrickId() === ''))
{
if (($this->GetTargetBrickId() === null) || ($this->GetTargetBrickId() === '')) {
throw new DOMFormatException('FilterBrick : Must have a target brick id', 0, null, $oMDElement);
}

View File

@@ -31,5 +31,4 @@ use Exception;
*/
class PropertyNotFoundException extends Exception
{
}
}

View File

@@ -29,7 +29,6 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use UserRights;
/**
* Class AggregatePageBrickController
*
@@ -41,7 +40,6 @@ use UserRights;
*/
class AggregatePageBrickController extends BrickController
{
/**
* Constructor.
*
@@ -51,8 +49,7 @@ class AggregatePageBrickController extends BrickController
*/
public function __construct(
protected BrickCollection $oBrickCollection
)
{
) {
}
@@ -76,11 +73,11 @@ class AggregatePageBrickController extends BrickController
$aTilesRendering = $this->GetBricksTileRendering($oRequest, $aAggregatePageBricks);
$sLayoutTemplate = $oBrick->GetTemplatePath('page');
$aData = array(
$aData = [
'oBrick' => $oBrick,
'aggregatepage_bricks' => $aAggregatePageBricks,
'aTilesRendering' => $aTilesRendering,
);
];
$oResponse = $this->render($sLayoutTemplate, $aData);
return $oResponse;
@@ -94,15 +91,11 @@ class AggregatePageBrickController extends BrickController
*/
private function GetOrderedAggregatePageBricksObjectsById($aAggregatePageBricksConf)
{
$aAggregatePageBricks = array();
foreach ($aAggregatePageBricksConf as $sBrickId => $iBrickRank)
{
try
{
$aAggregatePageBricks = [];
foreach ($aAggregatePageBricksConf as $sBrickId => $iBrickRank) {
try {
$oPortalBrick = $this->oBrickCollection->GetBrickById($sBrickId);
}
catch (BrickNotFoundException $oException)
{
} catch (BrickNotFoundException $oException) {
IssueLog::Debug('AggregatePageBrick: Could not display brick, either wrong id or user profile not allowed', LogChannels::PORTAL, [
'brick_id' => $sBrickId,
'user_profiles' => UserRights::ListProfiles(),
@@ -124,21 +117,17 @@ class AggregatePageBrickController extends BrickController
*/
private function GetBricksTileRendering(Request $oRequest, $aBricks)
{
$aTilesRendering = array();
foreach ($aBricks as $oBrick)
{
if ($oBrick->GetTileControllerAction() !== null)
{
$aTilesRendering = [];
foreach ($aBricks as $oBrick) {
if ($oBrick->GetTileControllerAction() !== null) {
$aControllerActionParts = explode('::', $oBrick->GetTileControllerAction());
if (count($aControllerActionParts) !== 2)
{
if (count($aControllerActionParts) !== 2) {
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Tile controller action must be of form "\Namespace\ControllerClass::FunctionName" for brick "'.$oBrick->GetId().'"');
}
$aRouteParams = array();
$aRouteParams = [];
// Add sBrickId in the route params as it is necessary for each brick actions
if (is_a($aControllerActionParts[0], BrickController::class, true))
{
if (is_a($aControllerActionParts[0], BrickController::class, true)) {
$aRouteParams['sBrickId'] = $oBrick->GetId();
}
@@ -150,4 +139,4 @@ class AggregatePageBrickController extends BrickController
return $aTilesRendering;
}
}
}

View File

@@ -29,5 +29,4 @@ namespace Combodo\iTop\Portal\Controller;
*/
abstract class BrickController extends AbstractController
{
}

View File

@@ -51,7 +51,6 @@ use VariableExpression;
*/
class BrowseBrickController extends BrickController
{
/**
* Constructor.
*
@@ -67,12 +66,10 @@ class BrowseBrickController extends BrickController
protected RequestManipulatorHelper $oRequestManipulatorHelper,
protected BrickControllerHelper $oBrickControllerHelper,
protected BrickCollection $oBrickCollection
)
{
) {
}
/**
* @param \Symfony\Component\HttpFoundation\Request $oRequest
* @param string $sBrickId
@@ -103,85 +100,92 @@ class BrowseBrickController extends BrickController
// Getting current browse mode (First from router parameter, 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 : $this->oRequestManipulatorHelper->ReadParam('sDataLoading',
$oBrick->GetDataLoading());
$sDataLoading = ($sDataLoading !== null) ? $sDataLoading : $this->oRequestManipulatorHelper->ReadParam(
'sDataLoading',
$oBrick->GetDataLoading()
);
// Getting search value
$sRawSearchValue = $this->oRequestManipulatorHelper->ReadParam('sSearchValue', '');
$sSearchValue = html_entity_decode($sRawSearchValue);
if (strlen($sSearchValue) > 0)
{
if (strlen($sSearchValue) > 0) {
$sDataLoading = AbstractBrick::ENUM_DATA_LOADING_LAZY;
}
$aData = array();
$aLevelsProperties = array();
$aLevelsClasses = array();
$aData = [];
$aLevelsProperties = [];
$aLevelsClasses = [];
$this->oBrowseBrickHelper->TreeToFlatLevelsProperties($oBrick->GetLevels(), $aLevelsProperties);
// 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)));
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)
)
);
}
if (empty($aLevelsProperties))
{
if (empty($aLevelsProperties)) {
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(
if (in_array($sBrowseMode, [
BrowseBrick::ENUM_BROWSE_MODE_TREE,
BrowseBrick::ENUM_BROWSE_MODE_MOSAIC,
)) && ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY))
{
]) && ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY)) {
// Will be handled later in the pagination part
}
// .. Otherwise
else
{
else {
// We iterate (in reverse mode /!\) over the levels to build the whole query, starting from the bottom
$aLevelsPropertiesKeys = array_keys($aLevelsProperties);
$iLoopMax = count($aLevelsPropertiesKeys) - 1;
$oFullBinExpr = null;
for ($i = $iLoopMax; $i >= 0; $i--)
{
for ($i = $iLoopMax; $i >= 0; $i--) {
// Retrieving class alias for all depth
array_unshift($aLevelsClasses, $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->GetClassAlias());
// Joining queries from bottom-up
if ($i < $iLoopMax)
{
$aRealiasingMap = array();
if ($i < $iLoopMax) {
$aRealiasingMap = [];
$oParentAtt = MetaModel::GetAttributeDef($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search']->GetClass(), $aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['parent_att']);
// If we work on a n:n link
if($oParentAtt instanceof AttributeLinkedSetIndirect)
{
if ($oParentAtt instanceof AttributeLinkedSetIndirect) {
// Create a DBSearch from Link class
$oSubSearch = new DBObjectSearch($oParentAtt->GetLinkedClass());
// Join it to the bottom query
$oSubSearch = $oSubSearch->Join($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'],
DBSearch::JOIN_POINTING_TO, $oParentAtt->GetExtKeyToMe(), TREE_OPERATOR_EQUALS, $aRealiasingMap);
$oSubSearch = $oSubSearch->Join(
$aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'],
DBSearch::JOIN_POINTING_TO,
$oParentAtt->GetExtKeyToMe(),
TREE_OPERATOR_EQUALS,
$aRealiasingMap
);
// Join our Link class + bottom query to the up query
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] ->Join($oSubSearch, DBSearch::JOIN_REFERENCED_BY,
$oParentAtt->GetExtKeyToRemote(), TREE_OPERATOR_EQUALS, $aRealiasingMap);
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] ->Join(
$oSubSearch,
DBSearch::JOIN_REFERENCED_BY,
$oParentAtt->GetExtKeyToRemote(),
TREE_OPERATOR_EQUALS,
$aRealiasingMap
);
} else {
$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
);
}
else
{
$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))
{
foreach ($aLevelsPropertiesKeys as $sLevelAlias) {
if (array_key_exists($sLevelAlias, $aRealiasingMap)) {
/** @since 2.7.2 */
foreach ($aRealiasingMap[$sLevelAlias] as $sAliasToChange)
{
foreach ($aRealiasingMap[$sLevelAlias] as $sAliasToChange) {
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->RenameAlias($sAliasToChange, $sLevelAlias);
}
}
@@ -190,8 +194,7 @@ class BrowseBrickController extends BrickController
// Adding search clause
// Note : For know the search is naive and looks only for the exact match. It doesn't search for words separately
if (strlen($sSearchValue) > 0)
{
if (strlen($sSearchValue) > 0) {
// - Cleaning the search value by exploding and trimming spaces
$aExplodedSearchValues = explode(' ', $sSearchValue);
$aSearchValues = [];
@@ -202,25 +205,21 @@ class BrowseBrickController extends BrickController
}
// - Retrieving fields to search
$aSearchFields = array($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['name_att']);
if (!empty($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['fields']))
{
$aSearchFields = [$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['name_att']];
if (!empty($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['fields'])) {
$sTmpFieldClass = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->GetClass();
foreach ($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['fields'] as $aTmpField)
{
foreach ($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['fields'] as $aTmpField) {
$sTmpFieldAttCode = $aTmpField['code'];
// Skip invalid attcodes
if(!MetaModel::IsValidAttCode($sTmpFieldClass, $sTmpFieldAttCode))
{
if (!MetaModel::IsValidAttCode($sTmpFieldClass, $sTmpFieldAttCode)) {
continue;
}
// For external key, force search on the friendlyname instead of the ID.
// This should be addressed more globally with the bigger issue, see N°1970
$oTmpFieldAttDef = MetaModel::GetAttributeDef($sTmpFieldClass, $sTmpFieldAttCode);
if($oTmpFieldAttDef instanceof AttributeExternalKey)
{
if ($oTmpFieldAttDef instanceof AttributeExternalKey) {
$sTmpFieldAttCode .= '_friendlyname';
}
@@ -231,60 +230,49 @@ class BrowseBrickController extends BrickController
$oLevelBinExpr = null;
$iFieldLoopMax = count($aSearchFields) - 1;
$iSearchLoopMax = count($aSearchValues) - 1;
for ($j = 0; $j <= $iFieldLoopMax; $j++)
{
for ($j = 0; $j <= $iFieldLoopMax; $j++) {
$sTmpFieldAttCode = $aSearchFields[$j];
$oFieldBinExpr = null;
//$oFieldBinExpr = new BinaryExpression(new FieldExpression($aSearchFields[$j], $aLevelsPropertiesKeys[$i]), )
for ($k = 0; $k <= $iSearchLoopMax; $k++)
{
$oSearchBinExpr = new BinaryExpression(new FieldExpression($sTmpFieldAttCode, $aLevelsPropertiesKeys[$i]),
'LIKE', new VariableExpression('search_value_'.$k));
if ($k === 0)
{
for ($k = 0; $k <= $iSearchLoopMax; $k++) {
$oSearchBinExpr = new BinaryExpression(
new FieldExpression($sTmpFieldAttCode, $aLevelsPropertiesKeys[$i]),
'LIKE',
new VariableExpression('search_value_'.$k)
);
if ($k === 0) {
$oFieldBinExpr = $oSearchBinExpr;
}
else
{
} else {
$oFieldBinExpr = new BinaryExpression($oFieldBinExpr, 'AND', $oSearchBinExpr);
}
}
if ($j === 0)
{
if ($j === 0) {
$oLevelBinExpr = $oFieldBinExpr;
}
else
{
} else {
$oLevelBinExpr = new BinaryExpression($oLevelBinExpr, 'OR', $oFieldBinExpr);
}
}
// - Building query for the level
if ($i === $iLoopMax)
{
if ($i === $iLoopMax) {
$oFullBinExpr = $oLevelBinExpr;
}
else
{
} else {
$oFullBinExpr = new BinaryExpression($oFullBinExpr, 'OR', $oLevelBinExpr);
}
// - Adding it to the query when complete
if ($i === 0)
{
if ($i === 0) {
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->AddConditionExpression($oFullBinExpr);
}
}
// Setting selected classes and binding parameters
if ($i === 0)
{
if ($i === 0) {
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->SetSelectedClasses($aLevelsClasses);
if (strlen($sSearchValue) > 0)
{
if (strlen($sSearchValue) > 0) {
// Note : This could be way more simpler if we had a SetInternalParam($sParam, $value) verb
$aQueryParams = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->GetInternalParams();
// Note : $iSearchloopMax was initialized on the previous loop
@@ -302,23 +290,26 @@ 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($sPortalId,
'lazy_loading_threshold');
$fThreshold = (float)MetaModel::GetModuleSetting(
$sPortalId,
'lazy_loading_threshold'
);
$sDataLoading = ($oCountSet->Count() > $fThreshold) ? AbstractBrick::ENUM_DATA_LOADING_LAZY : AbstractBrick::ENUM_DATA_LOADING_FULL;
unset($oCountSet);
}
}
// Setting query pagination if needed
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY)
{
switch ($sBrowseMode)
{
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY) {
switch ($sBrowseMode) {
case BrowseBrick::ENUM_BROWSE_MODE_LIST:
// Retrieving parameters
$iPageNumber = (int)$this->oRequestManipulatorHelper->ReadParam('iPageNumber', 1, FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$this->oRequestManipulatorHelper->ReadParam('iListLength', BrowseBrick::DEFAULT_LIST_LENGTH,
FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$this->oRequestManipulatorHelper->ReadParam(
'iListLength',
BrowseBrick::DEFAULT_LIST_LENGTH,
FILTER_SANITIZE_NUMBER_INT
);
// Getting total records number
$oCountSet = new DBObjectSet($oQuery);
@@ -337,36 +328,26 @@ class BrowseBrickController extends BrickController
$sNodeId = $this->oRequestManipulatorHelper->ReadParam('sNodeId', '');
// If no values for those parameters, we might be loading page in lazy mode for the first time, therefore the URL doesn't have those information.
if (empty($sLevelAlias))
{
if (empty($sLevelAlias)) {
reset($aLevelsProperties);
$oQuery = $aLevelsProperties[key($aLevelsProperties)]['search'];
if (!empty($sNodeId))
{
if (!empty($sNodeId)) {
$oQuery->AddCondition('id', $sNodeId);
}
}
// Else we need to find the OQL for that particular level
else
{
else {
$bFoundLevel = false;
foreach ($aLevelsProperties as $aLevelProperties)
{
if ($aLevelProperties['alias'] === $sLevelAlias)
{
if (isset($aLevelProperties['levels']) && !empty($aLevelProperties['levels']) && isset($aLevelsProperties[$aLevelProperties['levels'][0]]))
{
foreach ($aLevelsProperties as $aLevelProperties) {
if ($aLevelProperties['alias'] === $sLevelAlias) {
if (isset($aLevelProperties['levels']) && !empty($aLevelProperties['levels']) && isset($aLevelsProperties[$aLevelProperties['levels'][0]])) {
$oQuery = $aLevelsProperties[$aLevelProperties['levels'][0]]['search'];
if (!empty($sNodeId))
{
if (!empty($sNodeId)) {
$sParentAttCode = $aLevelsProperties[$aLevelProperties['levels'][0]]['parent_att'];
$oParentAtt = MetaModel::GetAttributeDef($oQuery->GetClass(), $sParentAttCode);
if($oParentAtt instanceof AttributeLinkedSetIndirect)
{
if ($oParentAtt instanceof AttributeLinkedSetIndirect) {
$oQuery->AddConditionAdvanced($sParentAttCode.'->'.$oParentAtt->GetExtKeyToRemote(), $sNodeId);
}
else
{
} else {
$oQuery->AddCondition($sParentAttCode, $sNodeId);
}
}
@@ -376,10 +357,11 @@ 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.');
if (!$bFoundLevel) {
throw new HttpException(
Response::HTTP_INTERNAL_SERVER_ERROR,
'Browse brick "'.$sBrickId.'" : Level alias "'.$sLevelAlias.'" is not defined for that brick.'
);
}
}
@@ -394,34 +376,26 @@ class BrowseBrickController extends BrickController
$oSet = new DBObjectSet($oQuery);
break;
}
}
else
{
} else {
$oSet = new DBObjectSet($oQuery);
}
// Optimizing the ObjectSet to retrieve only necessary columns
$aColumnAttrs = array();
foreach ($oSet->GetFilter()->GetSelectedClasses() as $sTmpClassAlias => $sTmpClassName)
{
if (isset($aLevelsProperties[$sTmpClassAlias]))
{
$aColumnAttrs = [];
foreach ($oSet->GetFilter()->GetSelectedClasses() as $sTmpClassAlias => $sTmpClassName) {
if (isset($aLevelsProperties[$sTmpClassAlias])) {
$aTmpLevelProperties = $aLevelsProperties[$sTmpClassAlias];
// Mandatory main attribute
$aTmpColumnAttrs = array($aTmpLevelProperties['name_att']);
$aTmpColumnAttrs = [$aTmpLevelProperties['name_att']];
// Optional attributes, only if in list mode
if ($sBrowseMode === BrowseBrick::ENUM_BROWSE_MODE_LIST)
{
foreach ($aTmpLevelProperties['fields'] as $aTmpField)
{
if ($sBrowseMode === BrowseBrick::ENUM_BROWSE_MODE_LIST) {
foreach ($aTmpLevelProperties['fields'] as $aTmpField) {
$aTmpColumnAttrs[] = $aTmpField['code'];
}
}
// Optional attributes
foreach (BrowseBrickHelper::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
{
if ($aTmpLevelProperties[$sOptionalAttribute] !== null)
{
foreach (BrowseBrickHelper::OPTIONAL_ATTRIBUTES as $sOptionalAttribute) {
if ($aTmpLevelProperties[$sOptionalAttribute] !== null) {
$aTmpColumnAttrs[] = $aTmpLevelProperties[$sOptionalAttribute];
}
}
@@ -434,20 +408,15 @@ class BrowseBrickController extends BrickController
// Setting specified column sort, setting default datamodel one otherwise
$aSortedParams = $this->oBrickControllerHelper->ExtractSortParams();
if (!empty($aSortedParams))
{
if (!empty($aSortedParams)) {
$oSet->SetOrderBy($aSortedParams);
}
else
{
} else {
$oSet->SetOrderByClasses();
}
// Retrieving results and organizing them for templating
$aItems = array();
while ($aCurrentRow = $oSet->FetchAssoc())
{
switch ($sBrowseMode)
{
$aItems = [];
while ($aCurrentRow = $oSet->FetchAssoc()) {
switch ($sBrowseMode) {
case BrowseBrick::ENUM_BROWSE_MODE_TREE:
case BrowseBrick::ENUM_BROWSE_MODE_MOSAIC:
$this->oBrowseBrickHelper->AddToTreeItems($aItems, $aCurrentRow, $aLevelsProperties, null);
@@ -460,22 +429,21 @@ class BrowseBrickController extends BrickController
}
}
IssueLog::Debug('Portal BrowseBrick query', LogChannels::PORTAL, array(
IssueLog::Debug('Portal BrowseBrick query', LogChannels::PORTAL, [
'sPortalId' => $sPortalId,
'sBrickId' => $sBrickId,
'oql' => $oSet->GetFilter()->ToOQL(),
));
]);
// Preparing response
if ($oRequest->isXmlHttpRequest()) {
$aData = $aData + array(
$aData = $aData + [
'data' => $aItems,
'levelsProperties' => $aLevelsProperties,
);
];
$oResponse = new JsonResponse($aData);
} else {
$aData = $aData + array(
$aData = $aData + [
'oBrick' => $oBrick,
'sBrickId' => $sBrickId,
'sBrowseMode' => $sBrowseMode,
@@ -486,7 +454,7 @@ class BrowseBrickController extends BrickController
'iItemsCount' => count($aItems),
'aLevelsProperties' => json_encode($aLevelsProperties),
'iDefaultLengthList' => $oBrick->GetDefaultListLength(),
);
];
// Note : To extend this brick's template, depending on what you want to do :
// a) Modify the whole template :
@@ -495,13 +463,10 @@ class BrowseBrickController extends BrickController
// - Create a template for that browse mode,
// - Add the mode to those available in the brick configuration,
// - Create a router and add a route for the new browse mode
if ($oBrick->HasInstanceOverriddenTemplate('page'))
{
if ($oBrick->HasInstanceOverriddenTemplate('page')) {
$sTemplatePath = $oBrick->GetTemplatePath('page');
}
else
{
$sTemplatePath = $oBrick->GetTemplatePath('page_' .$sBrowseMode);
} else {
$sTemplatePath = $oBrick->GetTemplatePath('page_'.$sBrowseMode);
}
$oResponse = $this->render($sTemplatePath, $aData);
}

View File

@@ -33,7 +33,6 @@ use Symfony\Component\HttpFoundation\Request;
*/
class CreateBrickController extends BrickController
{
/**
* Constructor.
*
@@ -43,8 +42,7 @@ class CreateBrickController extends BrickController
*/
public function __construct(
protected BrickCollection $oBrickCollection
)
{
) {
}
/**
@@ -60,16 +58,15 @@ class CreateBrickController extends BrickController
/** @var \Combodo\iTop\Portal\Brick\CreateBrick $oBrick */
$oBrick = $this->oBrickCollection->GetBrickById($sBrickId);
$aRouteParams = array(
$aRouteParams = [
'sBrickId' => $sBrickId,
'sObjectClass' => $oBrick->GetClass(),
'ar_token' => null,
);
];
// Checking for actions rules
$aRules = $oBrick->GetRules();
if (!empty($aRules))
{
if (!empty($aRules)) {
$aRouteParams['ar_token'] = ContextManipulatorHelper::PrepareAndEncodeRulesToken($aRules);
}

View File

@@ -39,8 +39,9 @@ class DefaultController extends AbstractController
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('home', static::TEMPLATES_BASE_PATH . 'home/layout.html.twig'),
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('home', static::TEMPLATES_BASE_PATH.'home/layout.html.twig'),
);
}
@@ -53,26 +54,24 @@ class DefaultController extends AbstractController
*/
public function HomeAction(Request $oRequest, BrickCollection $oBricksCollection)
{
$aData = array();
$aData = [];
// Rendering tiles
$aData['aTilesRendering'] = array();
foreach ($oBricksCollection->GetBricks() as $oBrick)
{
$aData['aTilesRendering'] = [];
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))
{
if (($oBrick->GetVisibleHome() === true) && ($oBrick->GetTileControllerAction() !== null)) {
$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);
if (count($aControllerActionParts) !== 2) {
return new Response(
'Tile controller action must be of form "\Namespace\ControllerClass::FunctionName" for brick "'.$oBrick->GetId().'"',
500
);
}
$aRouteParams = array();
$aRouteParams = [];
// Add sBrickId in the route params as it is necessary for each brick actions
if (is_a($aControllerActionParts[0], BrickController::class, true))
{
if (is_a($aControllerActionParts[0], BrickController::class, true)) {
$aRouteParams['sBrickId'] = $oBrick->GetId();
}

View File

@@ -72,18 +72,19 @@ use utils;
*/
class ManageBrickController extends BrickController
{
/**
* @var string EXCEL_EXPORT_TEMPLATE_PATH
/**
* @var string EXCEL_EXPORT_TEMPLATE_PATH
* @deprecated since 3.2.1
*/
const EXCEL_EXPORT_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig';
public const EXCEL_EXPORT_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig';
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('modal_export_excel', static::TEMPLATES_BASE_PATH . 'bricks/manage/popup-export-excel.html.twig'),
$oTemplatesRegister->RegisterTemplates(
self::class,
TemplateDefinitionDto::Create('modal_export_excel', static::TEMPLATES_BASE_PATH.'bricks/manage/popup-export-excel.html.twig'),
);
}
@@ -104,8 +105,7 @@ class ManageBrickController extends BrickController
protected RequestManipulatorHelper $oRequestManipulatorHelper,
protected SecurityHelper $oSecurityHelper,
protected BrickControllerHelper $oBrickControllerHelper
)
{
) {
}
@@ -138,17 +138,15 @@ class ManageBrickController extends BrickController
$aData = $this->GetData($oRequest, $sBrickId, $sGroupingTab, $oBrick->IsDetailsNeeded($sDisplayMode));
$aExportFields = $oBrick->GetExportFields();
$aData = $aData + array(
$aData = $aData + [
'sDisplayMode' => $sDisplayMode,
'bCanExport' => !empty($aExportFields),
'iDefaultListLength' => $oBrick->GetDefaultListLength(),
);
];
// Preparing response
if ($oRequest->isXmlHttpRequest()) {
$oResponse = new JsonResponse($aData);
}
else
{
} else {
$sLayoutTemplate = $oBrick->GetPageTemplate($sDisplayMode);
$oResponse = $this->render($sLayoutTemplate, $aData);
}
@@ -171,14 +169,11 @@ class ManageBrickController extends BrickController
/** @var \Combodo\iTop\Portal\Brick\ManageBrick $oBrick */
$oBrick = $this->oBrickCollection->GetBrickById($sBrickId);
try
{
try {
$aData = $this->GetData($oRequest, $sBrickId, null);
}
catch (Exception $e)
{
} catch (Exception $e) {
// TODO Default values
$aData = array();
$aData = [];
}
return $this->render($oBrick->GetTileTemplate(), $aData);
@@ -210,37 +205,28 @@ class ManageBrickController extends BrickController
$sClass = $oQuery->GetClass();
$aData = $this->GetData($oRequest, $sBrickId, $sGroupingTab, true);
if (isset($aData['aQueries']) && count($aData['aQueries']) === 1)
{
if (isset($aData['aQueries']) && count($aData['aQueries']) === 1) {
$aQueries = $aData['aQueries'];
reset($aQueries);
$sKey = key($aQueries);
$oSearch = $aData['aQueries'][$sKey];
}
else
{
} else {
$this->oScopeValidatorHelper->AddScopeToQuery($oQuery, $sClass);
$aData = array();
$aData = [];
$this->ManageSearchValue($aData, $oQuery, $sClass);
// Grouping tab
if ($oBrick->HasGroupingTabs())
{
if ($oBrick->HasGroupingTabs()) {
$aGroupingTabs = $oBrick->GetGroupingTabs();
// If tabs are made of the distinct values of an attribute, we have a find them via a query
if ($oBrick->IsGroupingTabsByDistinctValues())
{
if ($oBrick->IsGroupingTabsByDistinctValues()) {
$sGroupingTabAttCode = $aGroupingTabs['attribute'];
$aGroupingTabsValues = $this->GroupByAttribute($oQuery, $sGroupingTabAttCode, $oBrick);
$oQuery = $oQuery->Intersect($aGroupingTabsValues[$sGroupingTab]['condition']);
}
else
{
foreach ($aGroupingTabs['groups'] as $aGroup)
{
if ($aGroup['id'] === $sGroupingTab)
{
} else {
foreach ($aGroupingTabs['groups'] as $aGroup) {
if ($aGroup['id'] === $sGroupingTab) {
$oConditionQuery = $oQuery->Intersect(DBSearch::FromOQL($aGroup['condition']));
$oQuery = $oQuery->Intersect($oConditionQuery);
break;
@@ -251,29 +237,27 @@ class ManageBrickController extends BrickController
// Finalclass
$oConditionQuery = DBSearch::CloneWithAlias($oQuery, 'GARE');
$oExpression = new BinaryExpression(new FieldExpression('finalclass', 'GARE'), '=',
new UnaryExpression($sGroupingArea));
$oExpression = new BinaryExpression(
new FieldExpression('finalclass', 'GARE'),
'=',
new UnaryExpression($sGroupingArea)
);
$oConditionQuery->AddConditionExpression($oExpression);
/** @var DBSearch $oSearch */
$oSearch = $oQuery->Intersect($oConditionQuery);
}
$aColumnsAttrs = $oBrick->GetExportFields();
$aFields = array();
$aFields = [];
$sTitleAttrCode = 'friendlyname';
if (!in_array($sTitleAttrCode, $aColumnsAttrs))
{
if (!in_array($sTitleAttrCode, $aColumnsAttrs)) {
$aFields[] = $sTitleAttrCode;
}
foreach ($aColumnsAttrs as $sAttCode)
{
foreach ($aColumnsAttrs as $sAttCode) {
$oAttributeDef = MetaModel::GetAttributeDef($sGroupingArea, $sAttCode);
if ($oAttributeDef->IsExternalKey(EXTKEY_ABSOLUTE))
{
if ($oAttributeDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
$aFields[] = $sAttCode.'_friendlyname';
}
else
{
} else {
$aFields[] = $sAttCode;
}
}
@@ -288,12 +272,12 @@ class ManageBrickController extends BrickController
$oExporter->SetLocalizeOutput(true);
$oExporter->SetFields($sFields);
$aData = array(
$aData = [
'oBrick' => $oBrick,
'sBrickId' => $sBrickId,
'sToken' => $oExporter->SaveState(),
'sWikiUrl' => 'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export',
);
'sWikiUrl' => 'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export',
];
return $this->render($this->GetTemplatePath('modal_export_excel'), $aData);
}
@@ -323,10 +307,10 @@ class ManageBrickController extends BrickController
/** @var \Combodo\iTop\Portal\Brick\ManageBrick $oBrick */
$oBrick = $this->oBrickCollection->GetBrickById($sBrickId);
$aData = array();
$aGroupingTabsValues = array();
$aGroupingAreasValues = array();
$aQueries = array();
$aData = [];
$aGroupingTabsValues = [];
$aGroupingAreasValues = [];
$aQueries = [];
$bHasScope = true;
// Getting current data loading mode (First from router parameter, then query parameter, then default brick value)
@@ -334,8 +318,7 @@ class ManageBrickController extends BrickController
// - Retrieving the grouping areas to display
$sGroupingArea = $this->oRequestManipulatorHelper->ReadParam('sGroupingArea', '');
if (!empty($sGroupingArea))
{
if (!empty($sGroupingArea)) {
$bNeedDetails = true;
}
@@ -343,9 +326,8 @@ class ManageBrickController extends BrickController
$aColumnsAttrs = $oBrick->GetFields();
// Adding friendlyname attribute to the list if not already in it
$sTitleAttrCode = 'friendlyname';
if (($sTitleAttrCode !== null) && !in_array($sTitleAttrCode, $aColumnsAttrs))
{
$aColumnsAttrs = array_merge(array($sTitleAttrCode), $aColumnsAttrs);
if (($sTitleAttrCode !== null) && !in_array($sTitleAttrCode, $aColumnsAttrs)) {
$aColumnsAttrs = array_merge([$sTitleAttrCode], $aColumnsAttrs);
}
// Starting to build query
@@ -356,100 +338,78 @@ class ManageBrickController extends BrickController
// Preparing tabs
// - We need to retrieve distinct values for the grouping attribute
$iCount = 0;
if ($oBrick->HasGroupingTabs())
{
if ($oBrick->HasGroupingTabs()) {
$aGroupingTabs = $oBrick->GetGroupingTabs();
// If tabs are made of the distinct values of an attribute, we have a find them via a query
if ($oBrick->IsGroupingTabsByDistinctValues())
{
if ($oBrick->IsGroupingTabsByDistinctValues()) {
$sGroupingTabAttCode = $aGroupingTabs['attribute'];
$aGroupingTabsValues = $this->GroupByAttribute($oQuery, $sGroupingTabAttCode, $oBrick);
foreach ($aGroupingTabsValues as $aResult)
{
foreach ($aGroupingTabsValues as $aResult) {
$iCount += $aResult['count'];
}
}
// Otherwise we create the tabs from the SQL expressions
else
{
$aConditionQueryGrouping = array();
foreach ($aGroupingTabs['groups'] as $aGroup)
{
else {
$aConditionQueryGrouping = [];
foreach ($aGroupingTabs['groups'] as $aGroup) {
$oDBSearch = DBSearch::FromOQL($aGroup['condition']);
$oConditionQuery = $oQuery->Intersect($oDBSearch);
// - Restricting query to scope
array_push($aConditionQueryGrouping,$oDBSearch);
array_push($aConditionQueryGrouping, $oDBSearch);
$bHasScope = $this->oScopeValidatorHelper->AddScopeToQuery($oConditionQuery, $oConditionQuery->GetClass());
if ($bHasScope)
{
if ($bHasScope) {
// - Building ObjectSet
$oConditionSet = new DBObjectSet($oConditionQuery);
$iGroupCount = $oConditionSet->Count();
}
else
{
} else {
$oConditionSet = null;
$iGroupCount = 0;
}
$aGroupingTabsValues[$aGroup['id']] = array(
$aGroupingTabsValues[$aGroup['id']] = [
'value' => $aGroup['id'],
'label' => Dict::S($aGroup['title']),
'label_html' => Dict::S($aGroup['title']),
'description' => array_key_exists('description',$aGroup) ? Dict::S($aGroup['description']) : null,
'description' => array_key_exists('description', $aGroup) ? Dict::S($aGroup['description']) : null,
'condition' => $oConditionQuery,
'count' => $iGroupCount,
);
];
}
try
{
try {
$oConditionQuery = $oQuery->Intersect(new DBUnionSearch($aConditionQueryGrouping));
$bHasScope = $this->oScopeValidatorHelper->AddScopeToQuery($oConditionQuery, $oConditionQuery->GetClass());
if ($bHasScope)
{
if ($bHasScope) {
// - Building ObjectSet
$oConditionSet = new DBObjectSet($oConditionQuery);
$iCount = $oConditionSet->Count();
}
else
{
} else {
$oConditionSet = null;
$iCount = 0;
}
}
catch (Exception $e){
} catch (Exception $e) {
$oConditionSet = null;
$iCount = -1;
}
}
}
else
{
} else {
$oConditionQuery = $this->GetScopedQuery($oBrick, $sClass);
if (!is_null($oConditionQuery))
{
if (!is_null($oConditionQuery)) {
$oSet = new DBObjectSet($oConditionQuery);
$iCount = $oSet->Count();
}
}
// - Retrieving the current grouping tab to display if necessary and altering the query to do so
if (empty($sGroupingTab))
{
if ($oBrick->HasGroupingTabs())
{
if (empty($sGroupingTab)) {
if ($oBrick->HasGroupingTabs()) {
reset($aGroupingTabsValues);
$sGroupingTab = key($aGroupingTabsValues);
if ($aGroupingTabsValues[$sGroupingTab]['condition'] !== null)
{
if ($aGroupingTabsValues[$sGroupingTab]['condition'] !== null) {
$oQuery = $aGroupingTabsValues[$sGroupingTab]['condition']->DeepClone();
}
}
}
else
{
if ($aGroupingTabsValues[$sGroupingTab]['condition'] !== null)
{
} else {
if ($aGroupingTabsValues[$sGroupingTab]['condition'] !== null) {
$oQuery = $aGroupingTabsValues[$sGroupingTab]['condition']->DeepClone();
}
}
@@ -464,60 +424,56 @@ class ManageBrickController extends BrickController
// - We need to retrieve distinct values for the grouping attribute
// Note : Will have to be changed when we consider grouping on something else than the finalclass
$sParentAlias = $oQuery->GetClassAlias();
if ($bNeedDetails)
{
if ($bNeedDetails) {
$sGroupingAreaAttCode = 'finalclass';
// For root classes
if (MetaModel::IsValidAttCode($sClass, $sGroupingAreaAttCode))
{
if (MetaModel::IsValidAttCode($sClass, $sGroupingAreaAttCode)) {
$oDistinctQuery = $this->GetScopedQuery($oBrick, $sClass);
// Adding grouping conditions
$oFieldExp = new FieldExpression($sGroupingAreaAttCode, $oDistinctQuery->GetClassAlias());
$sDistinctSql = $oDistinctQuery->MakeGroupByQuery(array(), array('grouped_by_1' => $oFieldExp), true);
$sDistinctSql = $oDistinctQuery->MakeGroupByQuery([], ['grouped_by_1' => $oFieldExp], true);
$aDistinctResults = CMDBSource::QueryToArray($sDistinctSql);
foreach ($aDistinctResults as $aDistinctResult)
{
foreach ($aDistinctResults as $aDistinctResult) {
$oConditionQuery = DBSearch::CloneWithAlias($oQuery, 'GARE');
$oExpression = new BinaryExpression(new FieldExpression($sGroupingAreaAttCode, 'GARE'), '=',
new UnaryExpression($aDistinctResult['grouped_by_1']));
$oExpression = new BinaryExpression(
new FieldExpression($sGroupingAreaAttCode, 'GARE'),
'=',
new UnaryExpression($aDistinctResult['grouped_by_1'])
);
$oConditionQuery->AddConditionExpression($oExpression);
$aGroupingAreasValues[$aDistinctResult['grouped_by_1']] = array(
$aGroupingAreasValues[$aDistinctResult['grouped_by_1']] = [
'value' => $aDistinctResult['grouped_by_1'],
'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_'],
);
];
unset($oConditionQuery);
}
unset($aDistinctResults);
}
// For leaf classes
else
{
$aGroupingAreasValues[$sClass] = array(
else {
$aGroupingAreasValues[$sClass] = [
'value' => $sClass,
'label' => MetaModel::GetName($sClass),
// Caution : This works only because we froze the grouping areas on the finalclass attribute.
'condition' => null,
'count' => 0,
);
];
}
// - If specified or lazy loading, we truncate the $aGroupingAreasValues to keep only this one
if (!empty($sGroupingArea))
{
$aGroupingAreasValues = array($sGroupingArea => $aGroupingAreasValues[$sGroupingArea]);
if (!empty($sGroupingArea)) {
$aGroupingAreasValues = [$sGroupingArea => $aGroupingAreasValues[$sGroupingArea]];
}
// - Preparing the queries
foreach ($aGroupingAreasValues as $sKey => $aGroupingAreasValue)
{
foreach ($aGroupingAreasValues as $sKey => $aGroupingAreasValue) {
$oAreaQuery = DBSearch::CloneWithAlias($oQuery, $sParentAlias);
if ($aGroupingAreasValue['condition'] !== null)
{
if ($aGroupingAreasValue['condition'] !== null) {
$oAreaQuery = $aGroupingAreasValue['condition']->DeepClone();
}
@@ -525,8 +481,7 @@ class ManageBrickController extends BrickController
// Note: Will need to moved the scope restriction on queries elsewhere when we consider grouping on something else than finalclass
// Note: We now get view scope instead of edit scope as we allowed users to view/edit objects in the brick regarding their rights
$bHasScope = $this->oScopeValidatorHelper->AddScopeToQuery($oAreaQuery, $aGroupingAreasValue['value']);
if (!$bHasScope)
{
if (!$bHasScope) {
// if no scope apply does not allow any data
$oAreaQuery = null;
}
@@ -538,71 +493,64 @@ class ManageBrickController extends BrickController
// Testing appropriate data loading mode if we are in auto
// - For all (html) tables, this doesn't care for the grouping ares (finalclass)
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_AUTO)
{
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_AUTO) {
// - Check how many records there is.
// - Update $sDataLoading with its new value regarding the number of record and the threshold
$oCountSet = new DBObjectSet($oQuery);
$oCountSet->OptimizeColumnLoad(array($oQuery->GetClassAlias() => array()));
$fThreshold = (float)MetaModel::GetModuleSetting($sPortalId,
'lazy_loading_threshold');
$oCountSet->OptimizeColumnLoad([$oQuery->GetClassAlias() => []]);
$fThreshold = (float)MetaModel::GetModuleSetting(
$sPortalId,
'lazy_loading_threshold'
);
$sDataLoading = ($oCountSet->Count() > $fThreshold) ? AbstractBrick::ENUM_DATA_LOADING_LAZY : AbstractBrick::ENUM_DATA_LOADING_FULL;
unset($oCountSet);
}
// Preparing data sets
$aSets = array();
$aSets = [];
/** @var DBSearch $oQuery */
foreach ($aQueries as $sKey => $oQuery)
{
foreach ($aQueries as $sKey => $oQuery) {
// Checking if we have a valid query
if ($oQuery !== null)
{
if ($oQuery !== null) {
// - Adding search clause if necessary
$this->ManageSearchValue($aData, $oQuery, $sKey, $aColumnsAttrs);
// Setting query pagination if needed
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY)
{
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY) {
// Retrieving parameters
$iPageNumber = (int)$this->oRequestManipulatorHelper->ReadParam('iPageNumber', 1, FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$this->oRequestManipulatorHelper->ReadParam('iListLength', ManageBrick::DEFAULT_LIST_LENGTH,
FILTER_SANITIZE_NUMBER_INT);
$iListLength = (int)$this->oRequestManipulatorHelper->ReadParam(
'iListLength',
ManageBrick::DEFAULT_LIST_LENGTH,
FILTER_SANITIZE_NUMBER_INT
);
// Getting total records number
$oCountSet = new DBObjectSet($oQuery);
$oCountSet->OptimizeColumnLoad(array($oQuery->GetClassAlias() => $aColumnsAttrs));
$oCountSet->OptimizeColumnLoad([$oQuery->GetClassAlias() => $aColumnsAttrs]);
$aData['recordsTotal'] = $oCountSet->Count();
$aData['recordsFiltered'] = $oCountSet->Count();
unset($oCountSet);
$oSet = new DBObjectSet($oQuery);
$oSet->SetLimit($iListLength, $iListLength * ($iPageNumber - 1));
}
else
{
} else {
$oSet = new DBObjectSet($oQuery);
}
// Setting specified column sort, setting default datamodel one otherwise
if (!empty($aSortedParams))
{
if (!empty($aSortedParams)) {
$oSet->SetOrderBy($aSortedParams);
}
else
{
} else {
$oSet->SetOrderByClasses();
}
// Adding always_in_tables attributes
$aColumnsToLoad = array($oQuery->GetClassAlias() => $aColumnsAttrs);
foreach ($oQuery->GetSelectedClasses() as $sAlias => $sClassSelected)
{
$aColumnsToLoad = [$oQuery->GetClassAlias() => $aColumnsAttrs];
foreach ($oQuery->GetSelectedClasses() as $sAlias => $sClassSelected) {
/** @var AttributeDefinition $oAttDef */
foreach (MetaModel::ListAttributeDefs($sClassSelected) as $sAttCode => $oAttDef)
{
if ($oAttDef->AlwaysLoadInTables())
{
foreach (MetaModel::ListAttributeDefs($sClassSelected) as $sAttCode => $oAttDef) {
if ($oAttDef->AlwaysLoadInTables()) {
$aColumnsToLoad[$sAlias][] = $sAttCode;
}
}
@@ -610,17 +558,18 @@ class ManageBrickController extends BrickController
// Note: $aColumnToLoad already contains array of aliases => attcodes
$oSet->OptimizeColumnLoad($aColumnsToLoad);
$this->oSecurityHelper->PreloadForCache($oSet->GetFilter(),
$aColumnsToLoad[$oQuery->GetClassAlias()] /* preloading only extkeys from the main class */);
$this->oSecurityHelper->PreloadForCache(
$oSet->GetFilter(),
$aColumnsToLoad[$oQuery->GetClassAlias()] /* preloading only extkeys from the main class */
);
$aSets[$sKey] = $oSet;
}
}
// Retrieving and preparing data for rendering
$aGroupingAreasData = array();
$aGroupingAreasData = [];
$bHasObjectListItemExtension = false;
foreach ($aSets as $sKey => $oSet)
{
foreach ($aSets as $sKey => $oSet) {
// Set properties
$sCurrentClass = $sKey;
@@ -628,94 +577,88 @@ class ManageBrickController extends BrickController
$sMainActionAttrCode = $aColumnsAttrs[0];
// Loading columns definition
$aColumnsDefinition = array();
foreach ($aColumnsAttrs as $sColumnAttr)
{
$aColumnsDefinition = [];
foreach ($aColumnsAttrs as $sColumnAttr) {
$oAttDef = MetaModel::GetAttributeDef($sKey, $sColumnAttr);
$aColumnsDefinition[$sColumnAttr] = array(
$aColumnsDefinition[$sColumnAttr] = [
'title' => $oAttDef->GetLabel(),
'type' => ($oAttDef instanceof AttributeDateTime) ? 'moment-'.$oAttDef->GetFormat()->ToMomentJS() : 'html',
// Special sorting for Date & Time
);
];
}
// Getting items
$aItems = array();
$aItems = [];
// ... For each item
/** @var DBObject $oCurrentRow */
while ($oCurrentRow = $oSet->Fetch())
{
while ($oCurrentRow = $oSet->Fetch()) {
$sCurrentObjectClass = get_class($oCurrentRow);
$sCurrentObjectId = $oCurrentRow->GetKey();
// ... Retrieving item's attributes values
$aItemAttrs = array();
foreach ($aColumnsAttrs as $sItemAttr)
{
$aActions = array();
$aItemAttrs = [];
foreach ($aColumnsAttrs as $sItemAttr) {
$aActions = [];
// Set the edit action to the main (first) attribute only
//if ($sItemAttr === $sTitleAttrCode)
if ($sItemAttr === $sMainActionAttrCode)
{
if ($sItemAttr === $sMainActionAttrCode) {
// Checking if we can edit the object
if (($oBrick->GetOpeningMode() === ManageBrick::ENUM_ACTION_EDIT) && $this->oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY,
$sCurrentClass, $oCurrentRow->GetKey()))
{
if (($oBrick->GetOpeningMode() === ManageBrick::ENUM_ACTION_EDIT) && $this->oSecurityHelper->IsActionAllowed(
UR_ACTION_MODIFY,
$sCurrentClass,
$oCurrentRow->GetKey()
)) {
$sActionType = ManageBrick::ENUM_ACTION_EDIT;
}
// - Otherwise, check if view is allowed
elseif ($this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sCurrentClass,
$oCurrentRow->GetKey()))
{
elseif ($this->oSecurityHelper->IsActionAllowed(
UR_ACTION_READ,
$sCurrentClass,
$oCurrentRow->GetKey()
)) {
$sActionType = ManageBrick::ENUM_ACTION_VIEW;
}
else
{
} else {
$sActionType = null;
}
// - Then set allowed action
if ($sActionType !== null)
{
$aActions[] = array(
if ($sActionType !== null) {
$aActions[] = [
'type' => $sActionType,
'class' => $sCurrentClass,
'id' => $oCurrentRow->GetKey(),
'opening_target' => $oBrick->GetOpeningTarget(),
);
];
}
}
/** @var \AttributeDefinition $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sCurrentClass, $sItemAttr);
$sAttDefClass = get_class($oAttDef);
if ($oAttDef->IsExternalKey())
{
if ($oAttDef->IsExternalKey()) {
/** @var \AttributeExternalKey $oAttDef */
$sValue = $oCurrentRow->GetAsHTML($sItemAttr.'_friendlyname');
$sSortValue = $oCurrentRow->Get($sItemAttr.'_friendlyname');
// Adding a view action on the external keys
if ($oCurrentRow->Get($sItemAttr) !== $oAttDef->GetNullValue())
{
if ($oCurrentRow->Get($sItemAttr) !== $oAttDef->GetNullValue()) {
// Checking if we can view the object
if (($this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $oAttDef->GetTargetClass(),
$oCurrentRow->Get($sItemAttr))))
{
$aActions[] = array(
if (($this->oSecurityHelper->IsActionAllowed(
UR_ACTION_READ,
$oAttDef->GetTargetClass(),
$oCurrentRow->Get($sItemAttr)
))) {
$aActions[] = [
'type' => ManageBrick::ENUM_ACTION_VIEW,
'class' => $oAttDef->GetTargetClass(),
'id' => $oCurrentRow->Get($sItemAttr),
'opening_target' => $oBrick->GetOpeningTarget(),
);
];
}
}
}
elseif ($oAttDef instanceof AttributeImage)
{
} elseif ($oAttDef instanceof AttributeImage) {
/** @var \ormDocument $oOrmDoc */
$oOrmDoc = $oCurrentRow->Get($sItemAttr);
if (is_object($oOrmDoc) && !$oOrmDoc->IsEmpty())
{
if (is_object($oOrmDoc) && !$oOrmDoc->IsEmpty()) {
$sUrl = $this->oUrlGenerator->generate('p_object_document_display', [
'sObjectClass' => get_class($oCurrentRow),
'sObjectId' => $oCurrentRow->GetKey(),
@@ -723,16 +666,12 @@ class ManageBrickController extends BrickController
'cache' => 86400,
's' => $oOrmDoc->GetSignature(),
]);
}
else
{
} else {
$sUrl = $oAttDef->Get('default_image');
}
$sValue = '<img src="'.$sUrl.'" />';
$sSortValue = null;
}
elseif ($oAttDef instanceof AttributeTagSet)
{
} elseif ($oAttDef instanceof AttributeTagSet) {
/** @var \ormTagSet $oSetValues */
$oSetValues = $oCurrentRow->Get($sItemAttr);
$aCodes = $oSetValues->GetTags();
@@ -754,17 +693,15 @@ class ManageBrickController extends BrickController
// For simple fields, we get the raw (stored) value as well
$bExcludeRawValue = false;
foreach (ApplicationHelper::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
{
if (is_a($sAttDefClass, $sAttDefClassToExclude, true))
{
foreach (ApplicationHelper::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) {
if (is_a($sAttDefClass, $sAttDefClassToExclude, true)) {
$bExcludeRawValue = true;
break;
}
}
$attValueRaw = ($bExcludeRawValue === false) ? $oCurrentRow->Get($sItemAttr) : null;
$aItemAttrs[$sItemAttr] = array(
$aItemAttrs[$sItemAttr] = [
'object_class' => $sCurrentObjectClass,
'object_id' => $sCurrentObjectId,
'attribute_code' => $sItemAttr,
@@ -773,114 +710,105 @@ class ManageBrickController extends BrickController
'value_html' => $sValue,
'sort_value' => $sSortValue,
'actions' => $aActions,
);
];
}
// ... Checking menu extensions
$aItemButtons = array();
$aItemButtons = [];
/** @var iPopupMenuExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
{
foreach ($oExtensionInstance->EnumItems(iPopupMenuExtension::PORTAL_OBJLISTITEM_ACTIONS, array(
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) {
foreach ($oExtensionInstance->EnumItems(iPopupMenuExtension::PORTAL_OBJLISTITEM_ACTIONS, [
'portal_id' => $sPortalId,
'object' => $oCurrentRow,
)) as $oMenuItem)
{
if (is_object($oMenuItem))
{
if ($oMenuItem instanceof JSButtonItem)
{
$aItemButtons[] = $oMenuItem->GetMenuItem() + array(
]) as $oMenuItem) {
if (is_object($oMenuItem)) {
if ($oMenuItem instanceof JSButtonItem) {
$aItemButtons[] = $oMenuItem->GetMenuItem() + [
'js_files' => $oMenuItem->GetLinkedScripts(),
'type' => 'button',
);
}
elseif ($oMenuItem instanceof URLButtonItem)
{
$aItemButtons[] = $oMenuItem->GetMenuItem() + array('type' => 'link');
];
} elseif ($oMenuItem instanceof URLButtonItem) {
$aItemButtons[] = $oMenuItem->GetMenuItem() + ['type' => 'link'];
}
}
}
}
// ... And item's properties
$aItems[] = array(
$aItems[] = [
'id' => $oCurrentRow->GetKey(),
'class' => $sCurrentClass,
'attributes' => $aItemAttrs,
'highlight_class' => $oCurrentRow->GetHilightClass(),
'actions' => $aItemButtons,
);
];
if (!empty($aItemButtons))
{
if (!empty($aItemButtons)) {
$bHasObjectListItemExtension = true;
}
}
// Adding an extra column for object list item extensions
if ($bHasObjectListItemExtension === true)
{
$aColumnsDefinition['_ui_extensions'] = array(
if ($bHasObjectListItemExtension === true) {
$aColumnsDefinition['_ui_extensions'] = [
'title' => Dict::S('Brick:Portal:Manage:Table:ItemActions'),
'type' => 'html',
);
];
}
$aGroupingAreasData[$sKey] = array(
$aGroupingAreasData[$sKey] = [
'sId' => $sKey,
'sTitle' => $aGroupingAreasValues[$sKey]['label'],
'aItems' => $aItems,
'iItemsCount' => $oSet->Count(),
'aColumnsDefinition' => $aColumnsDefinition,
);
];
IssueLog::Debug('Portal ManageBrick query', LogChannels::PORTAL, array(
IssueLog::Debug('Portal ManageBrick query', LogChannels::PORTAL, [
'sPortalId' => $sPortalId,
'sBrickId' => $sBrickId,
'sGroupingTab' => $sGroupingTab,
'oql' => $oSet->GetFilter()->ToOQL(),
'aGroupingTabs' => $aGroupingTabs,
));
]);
}
} else {
$aGroupingAreasData = array();
$aGroupingAreasData = [];
$sGroupingArea = null;
}
// Preparing response
if ($oRequest->isXmlHttpRequest()) {
$aData = $aData + array(
$aData = $aData + [
'data' => $aGroupingAreasData[$sGroupingArea]['aItems'],
);
];
} else {
$aDisplayValues = array();
$aUrls = array();
$aColumns = array();
$aNames = array();
$aDisplayValues = [];
$aUrls = [];
$aColumns = [];
$aNames = [];
if ($bHasScope) {
foreach ($aGroupingTabsValues as $aValues) {
$aDisplayValues[] = array(
$aDisplayValues[] = [
'value' => $aValues['count'],
'label' => $aValues['label'],
'label_html' => $aValues['label_html'],
);
$aUrls[] = $this->oUrlGenerator->generate('p_manage_brick_display_as', array(
];
$aUrls[] = $this->oUrlGenerator->generate('p_manage_brick_display_as', [
'sBrickId' => $sBrickId,
'sDisplayMode' => 'list',
'sGroupingTab' => $aValues['value'],
));
]);
}
foreach ($aDisplayValues as $idx => $aValue)
{
$aColumns[] = array('series_'.$idx, (int)$aValue['value']);
foreach ($aDisplayValues as $idx => $aValue) {
$aColumns[] = ['series_'.$idx, (int)$aValue['value']];
$aNames['series_'.$idx] = $aValue['label'];
}
}
// Preparing data to pass to the templating service
$aData = $aData + array(
$aData = $aData + [
'sFct' => 'count',
'sIconURL' => $sIconURL,
'aColumns' => $aColumns,
@@ -896,7 +824,7 @@ class ManageBrickController extends BrickController
'sDateFormat' => AttributeDate::GetFormat()->ToMomentJS(),
'sDateTimeFormat' => AttributeDateTime::GetFormat()->ToMomentJS(),
'iCount' => $iCount,
);
];
}
return $aData;
@@ -911,7 +839,7 @@ class ManageBrickController extends BrickController
* @throws \CoreException
* @throws \Exception
*/
protected function ManageSearchValue(&$aData, DBSearch &$oQuery, $sClass, $aColumnsAttrs = array())
protected function ManageSearchValue(&$aData, DBSearch &$oQuery, $sClass, $aColumnsAttrs = [])
{
// Getting search value
$sRawSearchValue = trim($this->oRequestManipulatorHelper->ReadParam('sSearchValue', ''));
@@ -975,24 +903,22 @@ class ManageBrickController extends BrickController
* @throws \OQLException
* @throws \Exception
*/
protected function GroupByAttribute(DBSearch $oQuery, $sGroupingTabAttCode, ManageBrick $oBrick) {
protected function GroupByAttribute(DBSearch $oQuery, $sGroupingTabAttCode, ManageBrick $oBrick)
{
$aGroupingTabsValues = array();
$aDistinctResults = array();
$aGroupingTabsValues = [];
$aDistinctResults = [];
$oDistinctQuery = DBSearch::FromOQL($oBrick->GetOql());
$bHasScope = $this->oScopeValidatorHelper->AddScopeToQuery($oDistinctQuery, $oDistinctQuery->GetClass());
if ($bHasScope)
{
if ($bHasScope) {
// - Adding field condition
$oFieldExp = new FieldExpression($sGroupingTabAttCode, $oDistinctQuery->GetClassAlias());
$sDistinctSql = $oDistinctQuery->MakeGroupByQuery(array(), array('grouped_by_1' => $oFieldExp), true);
$sDistinctSql = $oDistinctQuery->MakeGroupByQuery([], ['grouped_by_1' => $oFieldExp], true);
$aDistinctResults = CMDBSource::QueryToArray($sDistinctSql);
if (!empty($aDistinctResults))
{
if (!empty($aDistinctResults)) {
$iLimit = $oBrick->GetGroupLimit();
$aOthers = array();
if ($iLimit > 0)
{
$aOthers = [];
if ($iLimit > 0) {
uasort($aDistinctResults, function ($a, $b) {
$v1 = $a['_itop_count_'];
$v2 = $b['_itop_count_'];
@@ -1000,77 +926,72 @@ class ManageBrickController extends BrickController
return ($v1 == $v2) ? 0 : (($v1 > $v2) ? -1 : 1);
});
if (count($aDistinctResults) > $iLimit)
{
if ($oBrick->ShowGroupOthers())
{
if (count($aDistinctResults) > $iLimit) {
if ($oBrick->ShowGroupOthers()) {
$aOthers = array_slice($aDistinctResults, $iLimit);
}
$aDistinctResults = array_slice($aDistinctResults, 0, $iLimit);
}
}
foreach ($aDistinctResults as $aDistinctResult)
{
foreach ($aDistinctResults as $aDistinctResult) {
$oConditionQuery = DBSearch::CloneWithAlias($oQuery, 'GTAB');
$oExpression = new BinaryExpression(new FieldExpression($sGroupingTabAttCode,
$oConditionQuery->GetClassAlias()), '=', new UnaryExpression($aDistinctResult['grouped_by_1']));
$oExpression = new BinaryExpression(new FieldExpression(
$sGroupingTabAttCode,
$oConditionQuery->GetClassAlias()
), '=', new UnaryExpression($aDistinctResult['grouped_by_1']));
$oConditionQuery->AddConditionExpression($oExpression);
$sHtmlLabel = $oFieldExp->MakeValueLabel($oDistinctQuery, $aDistinctResult['grouped_by_1'], '');
$aGroupingTabsValues[$aDistinctResult['grouped_by_1']] = array(
$aGroupingTabsValues[$aDistinctResult['grouped_by_1']] = [
'value' => $aDistinctResult['grouped_by_1'],
'label_html' => $sHtmlLabel,
'label' => strip_tags(html_entity_decode($sHtmlLabel, ENT_QUOTES, 'UTF-8')),
'condition' => $oConditionQuery,
'count' => $aDistinctResult['_itop_count_'],
);
];
unset($oConditionQuery);
}
if (!empty($aOthers))
{
if (!empty($aOthers)) {
// Aggregate others
$oConditionQuery = DBSearch::CloneWithAlias($oQuery, 'GTAB');
$oExpression = null;
$iOtherCount = 0;
foreach ($aOthers as $aResult)
{
foreach ($aOthers as $aResult) {
$iOtherCount += $aResult['_itop_count_'];
$oExpr = new BinaryExpression(new FieldExpression($sGroupingTabAttCode,
$oConditionQuery->GetClassAlias()), '=', new UnaryExpression($aResult['grouped_by_1']));
if (is_null($oExpression))
{
$oExpr = new BinaryExpression(new FieldExpression(
$sGroupingTabAttCode,
$oConditionQuery->GetClassAlias()
), '=', new UnaryExpression($aResult['grouped_by_1']));
if (is_null($oExpression)) {
$oExpression = $oExpr;
}
else
{
} else {
$oExpression = new BinaryExpression($oExpression, 'OR', $oExpr);
}
}
$oConditionQuery->AddConditionExpression($oExpression);
$sLabel = Dict::S('Brick:Portal:Manage:Others');
$aGroupingTabsValues['Others'] = array(
$aGroupingTabsValues['Others'] = [
'value' => 'Others',
'label_html' => $sLabel,
'label' => $sLabel,
'condition' => $oConditionQuery,
'count' => $iOtherCount,
);
];
unset($oConditionQuery);
}
}
}
if (empty($aDistinctResults))
{
if (empty($aDistinctResults)) {
$sLabel = Dict::S('Brick:Portal:Manage:All');
$aGroupingTabsValues['undefined'] = array(
$aGroupingTabsValues['undefined'] = [
'value' => 'All',
'label_html' => $sLabel,
'label' => $sLabel,
'condition' => null,
'count' => 0,
);
];
}
return $aGroupingTabsValues;

View File

@@ -36,7 +36,6 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
*/
class SessionMessageController extends AbstractController
{
/**
* @param \Combodo\iTop\Portal\Helper\RequestManipulatorHelper $oRequestManipulatorHelper
* @param \Combodo\iTop\Portal\Helper\SessionMessageHelper $oSessionMessageHelper
@@ -46,8 +45,7 @@ class SessionMessageController extends AbstractController
public function __construct(
protected RequestManipulatorHelper $oRequestManipulatorHelper,
protected SessionMessageHelper $oSessionMessageHelper
)
{
) {
}
/**
@@ -57,15 +55,14 @@ class SessionMessageController extends AbstractController
*/
public function AddMessageAction(Request $oRequest)
{
$aData = array();
$aData = [];
// Retrieve parameters
$sMessageSeverity = $this->oRequestManipulatorHelper->ReadParam('sSeverity');
$sMessageContent = $this->oRequestManipulatorHelper->ReadParam('sContent');
// Check parameters consistency
if (empty($sMessageSeverity) || empty($sMessageContent))
{
if (empty($sMessageSeverity) || empty($sMessageContent)) {
throw new HttpException(Response::HTTP_BAD_REQUEST, 'Message must have a severity and a content, make sure both sSeverity & sContent parameters are sent.');
}

View File

@@ -16,7 +16,6 @@ use Throwable;
*/
class PortalCollector extends AbstractDataCollector
{
/**
* Constructor.
*
@@ -100,13 +99,13 @@ class PortalCollector extends AbstractDataCollector
$iOverridesCount = 0;
$aExtensions = [];
foreach($aTemplatesDefinitions as $templates){
foreach ($aTemplatesDefinitions as $templates) {
foreach ($templates as $template) {
$aMatches = [];
preg_match('#([\w-]+)/#', $template->GetPath(), $aMatches);
if(!in_array($aMatches[1], $aExtensions)){
if (!in_array($aMatches[1], $aExtensions)) {
$aExtensions[] = $aMatches[1];
}
@@ -134,4 +133,4 @@ class PortalCollector extends AbstractDataCollector
return 'portal';
}
}
}

View File

@@ -52,4 +52,4 @@ class AbstractConfiguration
return $this->oModuleDesign;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -42,23 +43,19 @@ class Forms extends AbstractConfiguration
*/
public function Process(Container $oContainer)
{
$aForms = array();
$aForms = [];
/** @var \MFElement $oFormNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/forms/form') as $oFormNode)
{
try
{
foreach ($this->GetModuleDesign()->GetNodes('/module_design/forms/form') as $oFormNode) {
try {
// Parsing form id
$sFormId = $oFormNode->getAttribute('id');
if ($oFormNode->getAttribute('id') === '')
{
if ($oFormNode->getAttribute('id') === '') {
throw new DOMFormatException('form tag must have an id attribute', 0, null, $oFormNode);
}
// Parsing form object class
if ($oFormNode->GetUniqueElement('class')->GetText() === null)
{
if ($oFormNode->GetUniqueElement('class')->GetText() === null) {
throw new DOMFormatException('Class tag must be defined', 0, null, $oFormNode);
}
@@ -66,29 +63,26 @@ class Forms extends AbstractConfiguration
$sFormClass = $oFormNode->GetUniqueElement('class')->GetText();
// Parsing properties
$aFormProperties = array(
$aFormProperties = [
'display_mode' => ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE,
'always_show_submit' => ApplicationHelper::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT,
'navigation_rules' => array(
'submit' => array(
'navigation_rules' => [
'submit' => [
NavigationRuleHelper::ENUM_ORIGIN_PAGE => null,
NavigationRuleHelper::ENUM_ORIGIN_MODAL => null,
),
'cancel' => array(
],
'cancel' => [
NavigationRuleHelper::ENUM_ORIGIN_PAGE => null,
NavigationRuleHelper::ENUM_ORIGIN_MODAL => null,
),
),
);
],
],
];
$aAllowedNavRulesButtonCodes = array_keys($aFormProperties['navigation_rules']);
if ($oFormNode->GetOptionalElement('properties') !== null)
{
if ($oFormNode->GetOptionalElement('properties') !== null) {
/** @var \MFElement $oPropertyNode */
foreach ($oFormNode->GetOptionalElement('properties')->GetNodes('*') as $oPropertyNode)
{
switch ($oPropertyNode->nodeName)
{
foreach ($oFormNode->GetOptionalElement('properties')->GetNodes('*') as $oPropertyNode) {
switch ($oPropertyNode->nodeName) {
case 'display_mode':
$aFormProperties['display_mode'] = $oPropertyNode->GetText(ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE);
break;
@@ -99,28 +93,23 @@ class Forms extends AbstractConfiguration
case 'navigation_rules':
/** @var \MFElement $oNavRuleButtonNode */
foreach($oPropertyNode->GetNodes('*') as $oNavRuleButtonNode)
{
foreach ($oPropertyNode->GetNodes('*') as $oNavRuleButtonNode) {
$sNavRuleButtonCode = $oNavRuleButtonNode->nodeName;
if(!in_array($sNavRuleButtonCode, $aAllowedNavRulesButtonCodes))
{
if (!in_array($sNavRuleButtonCode, $aAllowedNavRulesButtonCodes)) {
throw new DOMFormatException('navigation_rules tag must only contain '.implode('|', $aAllowedNavRulesButtonCodes).' tags, "'.$sNavRuleButtonCode.'" given.', null, null, $oPropertyNode);
}
/** @var \MFElement $oNavRuleOriginNode */
foreach($oNavRuleButtonNode->GetNodes('*') as $oNavRuleOriginNode)
{
foreach ($oNavRuleButtonNode->GetNodes('*') as $oNavRuleOriginNode) {
$sNavRuleOrigin = $oNavRuleOriginNode->nodeName;
if(!in_array($sNavRuleOrigin, NavigationRuleHelper::GetAllowedOrigins()))
{
throw new DOMFormatException($sNavRuleButtonCode. ' tag must only contain '.implode('|', NavigationRuleHelper::GetAllowedOrigins()).' tags, "'.$sNavRuleOrigin.'" given.', null, null, $oPropertyNode);
if (!in_array($sNavRuleOrigin, NavigationRuleHelper::GetAllowedOrigins())) {
throw new DOMFormatException($sNavRuleButtonCode.' tag must only contain '.implode('|', NavigationRuleHelper::GetAllowedOrigins()).' tags, "'.$sNavRuleOrigin.'" given.', null, null, $oPropertyNode);
}
$sNavRuleId = $oNavRuleOriginNode->GetText();
// Note: We don't check is rule exists as it would introduce a dependency to the NavigationRuleHelper service.
// Maybe we will consider it later.
if(empty($sNavRuleId))
{
if (empty($sNavRuleId)) {
throw new DOMFormatException($sNavRuleButtonCode.' tag cannot be empty.', null, null, $oPropertyNode);
}
@@ -129,8 +118,7 @@ class Forms extends AbstractConfiguration
// Set modal rule as the same as default is not present.
// We preset it so we don't have to make checks elsewhere in the code when using it.
if(empty($aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_MODAL]))
{
if (empty($aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_MODAL])) {
$aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_MODAL] = $aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_PAGE];
}
}
@@ -139,36 +127,33 @@ class Forms extends AbstractConfiguration
}
// 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();
$aFormStimuli = [];
if (($oFormNode->GetOptionalElement('modes') !== null) && ($oFormNode->GetOptionalElement('modes')->GetNodes('mode')->length > 0)) {
$aModes = [];
/** @var \MFElement $oModeNode */
foreach ($oFormNode->GetOptionalElement('modes')->GetNodes('mode') as $oModeNode)
{
foreach ($oFormNode->GetOptionalElement('modes')->GetNodes('mode') as $oModeNode) {
$sModeId = $oModeNode->getAttribute('id');
if ($sModeId === '')
{
throw new DOMFormatException('mode tag must have an id attribute', 0, null,
$oFormNode);
if ($sModeId === '') {
throw new DOMFormatException(
'mode tag must have an id attribute',
0,
null,
$oFormNode
);
}
$aModes[] = $sModeId;
// If apply_stimulus mode, checking if stimuli are defined
if ($sModeId === 'apply_stimulus')
{
if ($sModeId === '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)
{
if ($oStimuliNode !== null) {
/** @var \MFElement $oStimulusNode */
foreach ($oStimuliNode->GetNodes('stimulus') as $oStimulusNode)
{
foreach ($oStimuliNode->GetNodes('stimulus') as $oStimulusNode) {
$sStimulusCode = $oStimulusNode->getAttribute('id');
// Removing default form if present (in case the default forms were parsed before the current one (from current or parent class))
if (isset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]))
{
if (isset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode])) {
unset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]);
}
@@ -177,111 +162,95 @@ class Forms extends AbstractConfiguration
}
}
}
}
else
{
} 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');
$aModes = ['view', 'edit', 'create'];
}
// Parsing fields
$aFields = array(
$aFields = [
'_brought_by' => $sFormClass,
'id' => $sFormId,
'type' => null,
'properties' => $aFormProperties,
'fields' => null,
'layout' => null,
);
];
// ... either enumerated fields ...
if ($oFormNode->GetOptionalElement('fields') !== null)
{
if ($oFormNode->GetOptionalElement('fields') !== null) {
$aFields['type'] = 'custom_list';
$aFields['fields'] = array();
$aFields['fields'] = [];
/** @var \MFElement $oFieldNode */
foreach ($oFormNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode)
{
foreach ($oFormNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode) {
$sFieldId = $oFieldNode->getAttribute('id');
if ($sFieldId !== '')
{
$aField = array();
if ($sFieldId !== '') {
$aField = [];
// Parsing field options like read_only, hidden and mandatory
if ($oFieldNode->GetOptionalElement('read_only'))
{
if ($oFieldNode->GetOptionalElement('read_only')) {
$aField['readonly'] = ($oFieldNode->GetOptionalElement('read_only')->GetText('true') === 'true') ? true : false;
}
if ($oFieldNode->GetOptionalElement('mandatory'))
{
if ($oFieldNode->GetOptionalElement('mandatory')) {
$aField['mandatory'] = ($oFieldNode->GetOptionalElement('mandatory')->GetText('true') === 'true') ? true : false;
}
if ($oFieldNode->GetOptionalElement('hidden'))
{
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', 0, null,
$oFormNode);
} else {
throw new DOMFormatException(
'Field tag must have an id attribute',
0,
null,
$oFormNode
);
}
}
}
// ... or the default zlist
else
{
else {
$aFields['type'] = 'zlist';
$aFields['fields'] = 'details';
}
// Parsing presentation
if ($oFormNode->GetOptionalElement('twig') !== null)
{
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(
$aFields['layout'] = [
'type' => (preg_match('/{{|{#|{%/', $sXml) === 1) ? 'twig' : 'xhtml',
'content' => $sXml,
);
];
}
// Adding form for each class / mode
foreach ($aModes as $sMode)
{
foreach ($aModes as $sMode) {
// Initializing current class if necessary
if (!isset($aForms[$sFormClass]))
{
$aForms[$sFormClass] = array();
if (!isset($aForms[$sFormClass])) {
$aForms[$sFormClass] = [];
}
// For stimuli we need to fill the matrix as only some stimuli might have been given
if ($sMode === 'apply_stimulus')
{
if ($sMode === 'apply_stimulus') {
// Iterating over current class and child classes
foreach (MetaModel::EnumChildClasses($sFormClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass)
{
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 (!isset($aForms[$sChildClass][$sMode])) {
$aForms[$sChildClass][$sMode] = [];
}
// If no explicit stimulus defined in this form, than it's the generic stimulus form
// we need to find which stimulus are missing
if(empty($aFormStimuli))
{
$aExistingStimuli = array();
if (empty($aFormStimuli)) {
$aExistingStimuli = [];
// Keep only stimuli brought by the class itself
foreach($aForms[$sChildClass][$sMode] as $sExistingStimulus => $aExistingForm)
{
if(!in_array($aExistingForm['_brought_by'], MetaModel::EnumParentClasses($sFormClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)))
{
foreach ($aForms[$sChildClass][$sMode] as $sExistingStimulus => $aExistingForm) {
if (!in_array($aExistingForm['_brought_by'], MetaModel::EnumParentClasses($sFormClass, ENUM_PARENT_CLASSES_EXCLUDELEAF))) {
//continue;
$aExistingStimuli[] = $sExistingStimulus;
}
@@ -290,51 +259,43 @@ class Forms extends AbstractConfiguration
$aMissingStimulusForms = array_diff($aDatamodelStimuli, $aExistingStimuli);
}
// Otherwise, we process only the ones for this form
else
{
else {
$aMissingStimulusForms = $aFormStimuli;
}
// Retrieve missing stimuli of the child class to fill the matrix
foreach ($aMissingStimulusForms as $sDatamodelStimulus)
{
foreach ($aMissingStimulusForms as $sDatamodelStimulus) {
// Check some facts about the target form
$bFormExists = isset($aForms[$sChildClass][$sMode][$sDatamodelStimulus]);
$bWasFormBroughtByParent = $bFormExists && in_array($aForms[$sChildClass][$sMode][$sDatamodelStimulus]['_brought_by'], MetaModel::EnumParentClasses($sFormClass, ENUM_PARENT_CLASSES_EXCLUDELEAF));
// Check if we need to overwrite (form created by parent)
$bOverwriteNecessary = false;
if($bWasFormBroughtByParent || in_array($sDatamodelStimulus, $aFormStimuli))
{
if ($bWasFormBroughtByParent || in_array($sDatamodelStimulus, $aFormStimuli)) {
$bOverwriteNecessary = true;
}
// Setting form if not defined OR if it was defined by a parent (abstract) class
if (!$bFormExists || $bOverwriteNecessary)
{
if (!$bFormExists || $bOverwriteNecessary) {
$aForms[$sChildClass][$sMode][$sDatamodelStimulus] = $aFields;
$aForms[$sChildClass][$sMode][$sDatamodelStimulus]['id'] = 'apply_stimulus-'.$sChildClass.'-'.$sDatamodelStimulus;
}
}
}
}
elseif (!isset($aForms[$sFormClass][$sMode]))
{
} 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(
'There is already a form for the class "'.$sFormClass.'" in "'.$sMode.'"',
null,
null,
$oFormNode
);
}
}
}
catch (DOMFormatException $e)
{
} 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)
{
} catch (Exception $e) {
throw new Exception('Could not create from from XML : '.$oFormNode->Dump().' '.$e->getMessage());
}
}
@@ -343,4 +304,4 @@ class Forms extends AbstractConfiguration
$aPortalConf['forms'] = $aForms;
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -39,51 +40,52 @@ class Lists extends AbstractConfiguration
public function Process(Container $oContainer)
{
$iDefaultItemRank = 0;
$aClassesLists = array();
$aClassesLists = [];
// Parsing XML file
// - Each classes
/** @var \MFElement $oClassNode */
foreach ($this->GetModuleDesign()->GetNodes('/module_design/classes/class') as $oClassNode)
{
$aClassLists = array();
foreach ($this->GetModuleDesign()->GetNodes('/module_design/classes/class') as $oClassNode) {
$aClassLists = [];
$sClassId = $oClassNode->getAttribute('id');
if ($sClassId === null)
{
if ($sClassId === null) {
throw new DOMFormatException('Class tag must have an id attribute', 0, null, $oClassNode);
}
// - Each lists
/** @var \MFElement $oListNode */
foreach ($oClassNode->GetNodes('./lists/list') as $oListNode)
{
$aListItems = array();
foreach ($oClassNode->GetNodes('./lists/list') as $oListNode) {
$aListItems = [];
$sListId = $oListNode->getAttribute('id');
if ($sListId === null)
{
throw new DOMFormatException('List tag of "'.$sClassId.'" class must have an id attribute', null,
null, $oListNode);
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)
{
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);
if ($sItemId === null) {
throw new DOMFormatException(
'Item tag of "'.$sItemId.'" list must have an id attribute',
null,
null,
$oItemNode
);
}
$aItem = array(
$aItem = [
'att_code' => $sItemId,
'rank' => $iDefaultItemRank,
);
];
$oRankNode = $oItemNode->GetOptionalElement('rank');
if ($oRankNode !== null)
{
if ($oRankNode !== null) {
$aItem['rank'] = $oRankNode->GetText($iDefaultItemRank);
}
@@ -100,8 +102,7 @@ class Lists extends AbstractConfiguration
}
// - Adding class only if it has at least one list
if (!empty($aClassLists))
{
if (!empty($aClassLists)) {
$aClassesLists[$sClassId] = $aClassLists;
}
}
@@ -110,4 +111,4 @@ class Lists extends AbstractConfiguration
$oContainer->setParameter('combodo.portal.instance.conf', $aPortalConf);
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -46,4 +47,4 @@ class ApplicationContextSetPluginPropertyClass
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', UserRights::GetUserLanguage());
}
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -31,16 +32,16 @@ use Symfony\Component\HttpKernel\Event\RequestEvent;
*/
class ApplicationContextSetUrlMakerClass
{
/** @var array $aCombodoPortalInstanceConf */
private $aCombodoPortalInstanceConf;
/** @var array $aCombodoPortalInstanceConf */
private $aCombodoPortalInstanceConf;
/**
* @param array $aCombodoPortalInstanceConf
*/
public function __construct($aCombodoPortalInstanceConf)
{
$this->aCombodoPortalInstanceConf = $aCombodoPortalInstanceConf;
}
/**
* @param array $aCombodoPortalInstanceConf
*/
public function __construct($aCombodoPortalInstanceConf)
{
$this->aCombodoPortalInstanceConf = $aCombodoPortalInstanceConf;
}
/**
* @param RequestEvent $oRequestEvent
@@ -51,4 +52,4 @@ class ApplicationContextSetUrlMakerClass
ApplicationContext::SetUrlMakerClass($this->aCombodoPortalInstanceConf['properties']['urlmaker_class']);
}
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -56,19 +57,15 @@ class CssFromSassCompiler
return;
}
$aImportPaths = array($_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/');
$aImportPaths = [$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/'];
foreach ($this->aCombodoPortalInstanceConf['properties']['themes'] as $sKey => $value) {
if (!is_array($value))
{
if (!is_array($value)) {
utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$value, $aImportPaths);
}
else
{
foreach ($value as $sSubValue)
{
} else {
foreach ($value as $sSubValue) {
utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$sSubValue, $aImportPaths);
}
}
}
}
}
}

View File

@@ -18,10 +18,8 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Portal\EventListener;
use Dict;
use ExceptionLog;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
@@ -40,7 +38,6 @@ use Twig\Environment;
*/
class ExceptionListener
{
/**
* Constructor.
*
@@ -48,8 +45,7 @@ class ExceptionListener
*/
public function __construct(
protected Environment $oTwig
)
{
) {
}
/**
@@ -59,7 +55,7 @@ class ExceptionListener
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function onKernelException(ExceptionEvent $oEvent) : void
public function onKernelException(ExceptionEvent $oEvent): void
{
// Get the exception object from the received event
$oException = $oEvent->getThrowable();
@@ -87,13 +83,11 @@ class ExceptionListener
// Prepare flatten exception
$oFlattenException = ($_SERVER['APP_DEBUG'] == 1) ? FlattenException::createFromThrowable($oException) : null;
// Remove APPROOT from file paths if in production (SF context)
if (!is_null($oFlattenException) && ($_SERVER['APP_ENV'] === 'prod'))
{
if (!is_null($oFlattenException) && ($_SERVER['APP_ENV'] === 'prod')) {
$oFlattenException->setFile($this->removeAppRootFromPath($oFlattenException->getFile()));
$aTrace = $oFlattenException->getTrace();
foreach ($aTrace as $iIdx => $aEntry)
{
foreach ($aTrace as $iIdx => $aEntry) {
$aTrace[$iIdx]['file'] = $this->removeAppRootFromPath($aEntry['file']);
}
$oFlattenException->setTrace($aTrace, $oFlattenException->getFile(), $oFlattenException->getLine());
@@ -105,20 +99,17 @@ class ExceptionListener
]);
// Prepare data for template
$aData = array(
$aData = [
'exception' => $oFlattenException,
'code' => $iStatusCode,
'error_title' => $sErrorTitle,
'error_message' => $sErrorMessage,
);
];
// Generate the response
if ($oEvent->getRequest()->isXmlHttpRequest())
{
if ($oEvent->getRequest()->isXmlHttpRequest()) {
$oResponse = new JsonResponse($aData);
}
else
{
} else {
$oResponse = new Response();
$oResponse->setContent($this->oTwig->render('itop-portal-base/portal/templates/errors/layout.html.twig', $aData));
}
@@ -164,5 +155,4 @@ class ExceptionListener
return str_replace($sNormalizedAppRoot, '', $sNormalizedInputPath);
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -78,7 +79,7 @@ class UserProvider
// - Checking user rights and prompt if needed (401 HTTP code returned if XHR request)
$iExitMethod = ($oRequestEvent->getRequest()->isXmlHttpRequest()) ? LoginWebPage::EXIT_RETURN : LoginWebPage::EXIT_PROMPT;
$iLogonRes = LoginWebPage::DoLoginEx($this->sPortalId, false, $iExitMethod);
if( ($iExitMethod === LoginWebPage::EXIT_RETURN) && ($iLogonRes != 0) ) {
if (($iExitMethod === LoginWebPage::EXIT_RETURN) && ($iLogonRes != 0)) {
die(Dict::S('Portal:ErrorUserLoggedOut'));
}
// - User must be associated with a Contact
@@ -92,8 +93,8 @@ class UserProvider
throw new Exception('Could not load connected user.');
}
// User allowed to log off or not
$this->bUserCanLogOff = utils::CanLogOff();
// User allowed to log off or not
$this->bUserCanLogOff = utils::CanLogOff();
// Allowed portals
$aAllowedPortals = UserRights::GetAllowedPortals();
@@ -146,5 +147,4 @@ class UserProvider
return $this->aAllowedPortals;
}
}
}

View File

@@ -51,6 +51,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use UserRights;
use utils;
use const UR_ACTION_READ;
/**
@@ -62,13 +63,13 @@ use const UR_ACTION_READ;
class ObjectFormManager extends FormManager
{
/** @var string ENUM_MODE_VIEW */
const ENUM_MODE_VIEW = 'view';
public const ENUM_MODE_VIEW = 'view';
/** @var string ENUM_MODE_EDIT */
const ENUM_MODE_EDIT = 'edit';
public const ENUM_MODE_EDIT = 'edit';
/** @var string ENUM_MODE_CREATE */
const ENUM_MODE_CREATE = 'create';
public const ENUM_MODE_CREATE = 'create';
/** @var string ENUM_MODE_APPLY_STIMULUS */
const ENUM_MODE_APPLY_STIMULUS = 'apply_stimulus';
public const ENUM_MODE_APPLY_STIMULUS = 'apply_stimulus';
/** @var \cmdbAbstractObject $oObject */
protected $oObject;
@@ -79,14 +80,14 @@ class ObjectFormManager extends FormManager
/** @var array $aFormProperties */
protected $aFormProperties;
/** @var array $aCallbackUrls */
protected $aCallbackUrls = array();
protected $aCallbackUrls = [];
/**
* List of hidden fields, used for form update (eg. remove them from the form regarding they dependencies)
*
* @var array $aHiddenFieldsId
* @since 2.7.5
*/
protected $aHiddenFieldsId = array();
protected $aHiddenFieldsId = [];
/**
* @var ObjectFormHandlerHelper $oFormHandlerHelper
@@ -95,7 +96,7 @@ class ObjectFormManager extends FormManager
private $oFormHandlerHelper;
/** @var array $aPlugins plugins data */
private array $aPlugins = array();
private array $aPlugins = [];
private array $aFieldsAtts = [];
private array $aExtraData = [];
private DOMDocument $oHtmlDocument;
@@ -143,27 +144,22 @@ class ObjectFormManager extends FormManager
}
$sObjectClass = $aJson['formobject_class'];
if (!isset($aJson['formobject_id']))
{
if (!isset($aJson['formobject_id'])) {
$oObject = MetaModel::NewObject($sObjectClass);
}
else
{
} else {
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oObject = MetaModel::GetObject($sObjectClass, $aJson['formobject_id'], true, true);
}
$oFormManager->SetObject($oObject);
// Retrieving form mode
if (!isset($aJson['formmode']))
{
if (!isset($aJson['formmode'])) {
throw new Exception('Form mode must be defined in order to generate the form');
}
$oFormManager->SetMode($aJson['formmode']);
// Retrieving actions rules
if (isset($aJson['formactionrulestoken']))
{
if (isset($aJson['formactionrulestoken'])) {
$oFormManager->SetActionRulesToken($aJson['formactionrulestoken']);
}
@@ -316,8 +312,7 @@ class ObjectFormManager extends FormManager
{
$aJson = parent::ToJSON();
$aJson['formobject_class'] = get_class($this->oObject);
if ($this->oObject->GetKey() > 0)
{
if ($this->oObject->GetKey() > 0) {
$aJson['formobject_id'] = $this->oObject->GetKey();
}
$aJson['formmode'] = $this->sMode;
@@ -338,11 +333,9 @@ class ObjectFormManager extends FormManager
// Building form from its properties
// - Consistency checks for stimulus form
if (isset($this->aFormProperties['stimulus_code']))
{
if (isset($this->aFormProperties['stimulus_code'])) {
$aTransitions = MetaModel::EnumTransitions($sObjectClass, $this->oObject->GetState());
if (!isset($aTransitions[$this->aFormProperties['stimulus_code']]))
{
if (!isset($aTransitions[$this->aFormProperties['stimulus_code']])) {
$aStimuli = Metamodel::EnumStimuli($sObjectClass);
$sStimulusLabel = $aStimuli[$this->aFormProperties['stimulus_code']]->GetLabel();
@@ -351,24 +344,22 @@ class ObjectFormManager extends FormManager
}
}
// Adding rendered template to the form renderer as the base layout
$this->oRenderer->SetBaseLayout($this->oHtmlDocument->saveHTML());
// Building the form
foreach ($this->aFieldsAtts as $sAttCode => $iFieldFlags)
{
foreach ($this->aFieldsAtts as $sAttCode => $iFieldFlags) {
// handle plugins fields
if($this->sMode !== 'apply_stimulus'
if ($this->sMode !== 'apply_stimulus'
&& array_key_exists($sAttCode, $this->aExtraData)
&& array_key_exists('plugin', $this->aExtraData[$sAttCode])){
&& array_key_exists('plugin', $this->aExtraData[$sAttCode])) {
$sPluginName = $this->aExtraData[$sAttCode]['plugin'];
switch($sPluginName){
switch ($sPluginName) {
case AttachmentPlugIn::class:
$this->AddAttachmentField($this->oForm, $sAttCode, $this->aExtraData);
break;
default:
throw new Exception('Unknown plugin ' . $sPluginName);
throw new Exception('Unknown plugin '.$sPluginName);
}
continue;
}
@@ -377,57 +368,44 @@ class ObjectFormManager extends FormManager
/** @var Field $oField */
$oField = null;
if (is_callable([$oAttDef, 'MakeFormField']))
{
if (is_callable([$oAttDef, 'MakeFormField'])) {
$oField = $oAttDef->MakeFormField($this->oObject);
}
// Failsafe for AttributeType that would not have MakeFormField and therefore could not be used in a form
if ($oField !== null)
{
if ($this->sMode !== static::ENUM_MODE_VIEW)
{
if ($oField !== null) {
if ($this->sMode !== static::ENUM_MODE_VIEW) {
// Field dependencies
$aFieldDependencies = $oAttDef->GetPrerequisiteAttributes();
if (!empty($aFieldDependencies))
{
if (!empty($aFieldDependencies)) {
$this->oForm->AddFieldDependencies($oField->GetId(), $aFieldDependencies);
}
// Setting the field flags
// - If it's locked because slave, we force it as read only
if (($iFieldFlags & OPT_ATT_SLAVE) === OPT_ATT_SLAVE)
{
if (($iFieldFlags & OPT_ATT_SLAVE) === OPT_ATT_SLAVE) {
$oField->SetReadOnly(true);
}
// - Else if it's must change (transition), we force it as mustchange, not readonly and not hidden
elseif (($iFieldFlags & OPT_ATT_MUSTCHANGE) === OPT_ATT_MUSTCHANGE && $this->IsTransitionForm())
{
elseif (($iFieldFlags & OPT_ATT_MUSTCHANGE) === OPT_ATT_MUSTCHANGE && $this->IsTransitionForm()) {
$oField->SetMustChange(true);
$oField->SetReadOnly(false);
$oField->SetHidden(false);
}
// - Else if it's must prompt (transition), we force it as not readonly and not hidden
elseif (($iFieldFlags & OPT_ATT_MUSTPROMPT) === OPT_ATT_MUSTPROMPT && $this->IsTransitionForm())
{
elseif (($iFieldFlags & OPT_ATT_MUSTPROMPT) === OPT_ATT_MUSTPROMPT && $this->IsTransitionForm()) {
$oField->SetReadOnly(false);
$oField->SetHidden(false);
}
// - Else if it wasn't mandatory or already had a value, and it's hidden, we force it as hidden
elseif (($iFieldFlags & OPT_ATT_HIDDEN) === OPT_ATT_HIDDEN)
{
elseif (($iFieldFlags & OPT_ATT_HIDDEN) === OPT_ATT_HIDDEN) {
$oField->SetHidden(true);
}
elseif (($iFieldFlags & OPT_ATT_READONLY) === OPT_ATT_READONLY)
{
} elseif (($iFieldFlags & OPT_ATT_READONLY) === OPT_ATT_READONLY) {
$oField->SetReadOnly(true);
}
else
{
} else {
// Normal field, use "flags" set by AttDef::MakeFormField()
// Except if we are in a transition be cause $oAttDef doesn't know if the form is for a transition
if ($this->IsTransitionForm())
{
if ($this->IsTransitionForm()) {
$oField->SetReadOnly(false);
$oField->SetHidden(false);
$oField->SetMandatory(false);
@@ -435,114 +413,110 @@ class ObjectFormManager extends FormManager
}
// Finally, if it's mandatory ...
if (($iFieldFlags & OPT_ATT_MANDATORY) === OPT_ATT_MANDATORY)
{
if (($iFieldFlags & OPT_ATT_MANDATORY) === OPT_ATT_MANDATORY) {
// ... and when in a transition, we force it as mandatory
if ($this->IsTransitionForm() && $oAttDef->IsNull($this->oObject->Get($sAttCode)))
{
if ($this->IsTransitionForm() && $oAttDef->IsNull($this->oObject->Get($sAttCode))) {
$oField->SetMandatory(true);
}
// .. and has no value, we force it as mandatory
elseif ($oAttDef->IsNull($this->oObject->Get($sAttCode)))
{
elseif ($oAttDef->IsNull($this->oObject->Get($sAttCode))) {
$oField->SetMandatory(true);
}
}
// Specific operation on field
// - Field that require a transaction id
if (in_array(get_class($oField),
array('Combodo\\iTop\\Form\\Field\\TextAreaField', 'Combodo\\iTop\\Form\\Field\\CaseLogField')))
{
if (in_array(
get_class($oField),
['Combodo\\iTop\\Form\\Field\\TextAreaField', 'Combodo\\iTop\\Form\\Field\\CaseLogField']
)) {
/** @var \Combodo\iTop\Form\Field\TextAreaField|\Combodo\iTop\Form\Field\CaseLogField $oField */
$oField->SetTransactionId($this->oForm->GetTransactionId());
}
// - Field that require a search endpoint
if (in_array(get_class($oField),
array('Combodo\\iTop\\Form\\Field\\SelectObjectField', 'Combodo\\iTop\\Form\\Field\\LinkedSetField'))) {
if (in_array(
get_class($oField),
['Combodo\\iTop\\Form\\Field\\SelectObjectField', 'Combodo\\iTop\\Form\\Field\\LinkedSetField']
)) {
/** @var \Combodo\iTop\Form\Field\SelectObjectField|\Combodo\iTop\Form\Field\LinkedSetField $oField */
if ($this->oFormHandlerHelper !== null) {
$sSearchEndpoint = $this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_search_generic', array(
$sSearchEndpoint = $this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_search_generic', [
'sTargetAttCode' => $oAttDef->GetCode(),
'sHostObjectClass' => get_class($this->oObject),
'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey(),
'ar_token' => $this->GetActionRulesToken(),
));
]);
$oField->SetSearchEndpoint($sSearchEndpoint);
}
}
// - Field that require an information endpoint
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\LinkedSetField'))) {
if (in_array(get_class($oField), ['Combodo\\iTop\\Form\\Field\\LinkedSetField'])) {
/** @var \Combodo\iTop\Form\Field\LinkedSetField $oField */
if ($this->oFormHandlerHelper !== null) {
$oField->SetInformationEndpoint($this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_get_information_for_linked_set_json'));
}
}
// - Field that require to apply scope on its DM OQL
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\SelectObjectField')))
{
if (in_array(get_class($oField), ['Combodo\\iTop\\Form\\Field\\SelectObjectField'])) {
/** @var \Combodo\iTop\Form\Field\SelectObjectField $oField */
if ($this->oFormHandlerHelper !== null) {
$oScopeOriginal = ($oField->GetSearch() !== null) ? $oField->GetSearch() : DBSearch::FromOQL($oAttDef->GetValuesDef()->GetFilterExpression());
/** @var \DBSearch $oScopeSearch */
$oScopeSearch = $this->oFormHandlerHelper->GetScopeValidator()->GetScopeFilterForProfiles(UserRights::ListProfiles(),
$oScopeOriginal->GetClass(), UR_ACTION_READ);
$oScopeSearch = $this->oFormHandlerHelper->GetScopeValidator()->GetScopeFilterForProfiles(
UserRights::ListProfiles(),
$oScopeOriginal->GetClass(),
UR_ACTION_READ
);
if ($oScopeSearch === null) {
IssueLog::Info(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' has no scope query for '.$oScopeOriginal->GetClass().' class.');
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
}
$oScopeOriginal = $oScopeOriginal->Intersect($oScopeSearch);
// Note : This is to skip the silo restriction on the final query
if ($oScopeSearch->IsAllDataAllowed())
{
if ($oScopeSearch->IsAllDataAllowed()) {
$oScopeOriginal->AllowAllData();
}
$oScopeOriginal->SetInternalParams(array('this' => $this->oObject));
$oScopeOriginal->SetInternalParams(['this' => $this->oObject]);
$oField->SetSearch($oScopeOriginal);
}
}
// - Field that require to check if the current value is among allowed ones
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\SelectObjectField')))
{
if (in_array(get_class($oField), ['Combodo\\iTop\\Form\\Field\\SelectObjectField'])) {
// Note: We can't do this in AttributeExternalKey::MakeFormField() in the Field::SetOnFinalizeCallback() because at this point we have no information about the portal scope and ignore_silos flag, hence it always applies silos.
// As a workaround we have to manually check if the field's current value is among the scope
$oField->ResetCurrentValueIfNotAmongAllowedValues();
}
// - Field that require processing on their subfields
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\SubFormField')))
{
if (in_array(get_class($oField), ['Combodo\\iTop\\Form\\Field\\SubFormField'])) {
/** @var \Combodo\iTop\Form\Field\SubFormField $oField */
$oSubForm = $oField->GetForm();
if ($oAttDef->GetEditClass() === 'CustomFields')
{
if ($oAttDef->GetEditClass() === 'CustomFields') {
// Retrieving only user data fields (not the metadata fields of the template)
if ($oSubForm->HasField('user_data'))
{
if ($oSubForm->HasField('user_data')) {
/** @var \Combodo\iTop\Form\Field\SubFormField $oUserDataField */
$oUserDataField = $oSubForm->GetField('user_data');
$oUserDataForm = $oUserDataField->GetForm();
foreach ($oUserDataForm->GetFields() as $oCustomField)
{
foreach ($oUserDataForm->GetFields() as $oCustomField) {
// - Field that require a search endpoint (OQL based dropdown list fields)
if (in_array(get_class($oCustomField), array('Combodo\\iTop\\Form\\Field\\SelectObjectField')))
{
if (in_array(get_class($oCustomField), ['Combodo\\iTop\\Form\\Field\\SelectObjectField'])) {
/** @var \Combodo\iTop\Form\Field\SelectObjectField $oCustomField */
if ($this->oFormHandlerHelper->GetUrlGenerator() !== null) {
$sSearchEndpoint = $this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_search_generic',
array(
$sSearchEndpoint = $this->oFormHandlerHelper->GetUrlGenerator()->generate(
'p_object_search_generic',
[
'sTargetAttCode' => $oAttDef->GetCode(),
'sHostObjectClass' => get_class($this->oObject),
'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey(),
'ar_token' => $this->GetActionRulesToken(),
));
]
);
$oCustomField->SetSearchEndpoint($sSearchEndpoint);
}
}
// - Field that require to check if the current value is among allowed ones
if (in_array(get_class($oCustomField), array('Combodo\\iTop\\Form\\Field\\SelectObjectField')))
{
if (in_array(get_class($oCustomField), ['Combodo\\iTop\\Form\\Field\\SelectObjectField'])) {
/** @var \Combodo\iTop\Form\Field\SelectObjectField $oCustomField */
$oCustomField->ResetCurrentValueIfNotAmongAllowedValues();
}
@@ -550,37 +524,34 @@ class ObjectFormManager extends FormManager
}
}
}
}
else
{
if (($iFieldFlags & OPT_ATT_HIDDEN) === OPT_ATT_HIDDEN)
{
} else {
if (($iFieldFlags & OPT_ATT_HIDDEN) === OPT_ATT_HIDDEN) {
$oField->SetHidden(true);
}
else
{
} else {
$oField->SetReadOnly(true);
}
}
// Specific operation on field
// - LinkedSet
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\LinkedSetField')))
{
if (in_array(get_class($oField), ['Combodo\\iTop\\Form\\Field\\LinkedSetField'])) {
/** @var \Combodo\iTop\Form\Field\LinkedSetField $oField */
/** @var \AttributeLinkedSetIndirect $oAttDef */
// - Overriding attributes to display
if ($this->oFormHandlerHelper !== null) {
// Note : This snippet is inspired from AttributeLinkedSet::MakeFormField()
$aAttCodesToDisplay = ApplicationHelper::GetLoadedListFromClass($this->oFormHandlerHelper->getCombodoPortalConf()['lists'],
$oField->GetTargetClass(), 'list');
$aAttCodesToDisplay = ApplicationHelper::GetLoadedListFromClass(
$this->oFormHandlerHelper->getCombodoPortalConf()['lists'],
$oField->GetTargetClass(),
'list'
);
// - Adding friendlyname attribute to the list is not already in it
$sTitleAttCode = 'friendlyname';
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
$aAttCodesToDisplay = array_merge([$sTitleAttCode], $aAttCodesToDisplay);
}
// - Adding attribute labels
$aAttributesToDisplay = array();
$aAttributesToDisplay = [];
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
$oAttDefToDisplay = MetaModel::GetAttributeDef($oField->GetTargetClass(), $sAttCodeToDisplay);
$aAttributesToDisplay[$sAttCodeToDisplay] = [
@@ -598,7 +569,7 @@ class ObjectFormManager extends FormManager
}
// - Filtering links regarding scopes
if ($this->oFormHandlerHelper !== null) {
$aLimitedAccessItemIDs = array();
$aLimitedAccessItemIDs = [];
/** @var \ormLinkSet $oFieldOriginalSet */
$oFieldOriginalSet = $oField->GetCurrentValue();
@@ -617,19 +588,16 @@ class ObjectFormManager extends FormManager
$oField->SetLimitedAccessItemIDs($aLimitedAccessItemIDs);
}
// - Displaying as opened
if (array_key_exists($sAttCode, $this->aExtraData) && array_key_exists('opened', $this->aExtraData[$sAttCode]))
{
if (array_key_exists($sAttCode, $this->aExtraData) && array_key_exists('opened', $this->aExtraData[$sAttCode])) {
$oField->SetDisplayOpened(true);
}
// - Displaying out of scopes items
if (array_key_exists($sAttCode, $this->aExtraData) && array_key_exists('ignore_scopes', $this->aExtraData[$sAttCode]))
{
if (array_key_exists($sAttCode, $this->aExtraData) && array_key_exists('ignore_scopes', $this->aExtraData[$sAttCode])) {
$oField->SetDisplayLimitedAccessItems(true);
}
}
// - BlobField
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\BlobField', 'Combodo\\iTop\\Form\\Field\\ImageField')))
{
if (in_array(get_class($oField), ['Combodo\\iTop\\Form\\Field\\BlobField', 'Combodo\\iTop\\Form\\Field\\ImageField'])) {
// - Overriding attributes to display
if ($this->oFormHandlerHelper !== null) {
// Override hardcoded URLs in ormDocument pointing to back office console
@@ -654,9 +622,7 @@ class ObjectFormManager extends FormManager
}
}
}
else
{
} else {
$oField = new LabelField($sAttCode);
$oField->SetReadOnly(true)
->SetHidden(false)
@@ -665,8 +631,7 @@ class ObjectFormManager extends FormManager
}
// Setting field display mode
if (array_key_exists($sAttCode, $this->aExtraData) && array_key_exists('display_mode', $this->aExtraData[$sAttCode]))
{
if (array_key_exists($sAttCode, $this->aExtraData) && array_key_exists('display_mode', $this->aExtraData[$sAttCode])) {
$oField->SetDisplayMode($this->aExtraData[$sAttCode]['display_mode']);
}
@@ -678,32 +643,25 @@ class ObjectFormManager extends FormManager
// Do not add hidden fields as they are of no use, if one is necessary because another depends on it, it will be automatically added.
// Note: We do this at the end because during the process an hidden field could have become writable if mandatory and empty for example.
if($oField->GetHidden() === false)
{
if ($oField->GetHidden() === false) {
$this->oForm->AddField($oField);
} else {
$this->aHiddenFieldsId[]=$oField->GetId();
$this->aHiddenFieldsId[] = $oField->GetId();
}
}
// Checking dependencies to ensure that all needed fields are in the form
// (This is kind of a garbage collector for dependencies)
foreach ($this->oForm->GetDependencies() as $sImpactedFieldId => $aDependencies)
{
foreach ($aDependencies as $sDependencyFieldId)
{
if (!$this->oForm->HasField($sDependencyFieldId))
{
try
{
foreach ($this->oForm->GetDependencies() as $sImpactedFieldId => $aDependencies) {
foreach ($aDependencies as $sDependencyFieldId) {
if (!$this->oForm->HasField($sDependencyFieldId)) {
try {
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oObject), $sDependencyFieldId);
$oField = $oAttDef->MakeFormField($this->oObject);
$oField->SetHidden(true);
$this->oForm->AddField($oField);
}
catch (Exception $e)
{
} catch (Exception $e) {
// Avoid blocking a form if a RequestTemplate reference a bad attribute (e.g. :this->id)
IssueLog::Error('May be a bad OQL (referencing :this->id) in a RequestTemplate causes the following error');
IssueLog::Error($e);
@@ -717,7 +675,7 @@ class ObjectFormManager extends FormManager
if ($this->sMode !== 'apply_stimulus'
&& class_exists('Attachment') && class_exists('AttachmentPlugIn')
&& !$this->IsPluginInitialized(AttachmentPlugIn::class)
&& AttachmentPlugIn::IsAttachmentAllowedForObject($this->oObject)){
&& AttachmentPlugIn::IsAttachmentAllowedForObject($this->oObject)) {
$this->AddAttachmentField($this->oForm, 'attachments_plugin', $this->aExtraData);
}
@@ -732,7 +690,7 @@ class ObjectFormManager extends FormManager
*
* @return bool
*/
private function IsPluginInitialized(string $sPluginName) : bool
private function IsPluginInitialized(string $sPluginName): bool
{
return array_key_exists($sPluginName, $this->aPlugins);
}
@@ -746,48 +704,54 @@ class ObjectFormManager extends FormManager
*
* @throws \Exception
*/
private function AddAttachmentField($oForm, $sId, $aFieldsExtraData) : void
private function AddAttachmentField($oForm, $sId, $aFieldsExtraData): void
{
// only one instance allowed
if($this->IsPluginInitialized(AttachmentPlugIn::class)){
throw new Exception("Unable to process field `$sId`, AttachmentPlugIn has already been initialized with field `" . $this->aPlugins[AttachmentPlugIn::class]['field']->GetId() . '`');
if ($this->IsPluginInitialized(AttachmentPlugIn::class)) {
throw new Exception("Unable to process field `$sId`, AttachmentPlugIn has already been initialized with field `".$this->aPlugins[AttachmentPlugIn::class]['field']->GetId().'`');
}
// not allowed for object class
if(!AttachmentPlugIn::IsAttachmentAllowedForObject($this->oObject)){
throw new Exception("Unable to process field `$sId`, AttachmentPlugIn is not allowed for class `" . $this->oObject::class . '`');
if (!AttachmentPlugIn::IsAttachmentAllowedForObject($this->oObject)) {
throw new Exception("Unable to process field `$sId`, AttachmentPlugIn is not allowed for class `".$this->oObject::class.'`');
}
// set id to a unique key - avoid collisions with another attribute that could exist with the name 'attachments'
$oField = new FileUploadField($sId);
$oField->SetLabel(Dict::S('Portal:Attachments'))
->SetUploadEndpoint($this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_attachment_add'))
->SetDownloadEndpoint($this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_attachment_download',
array('sAttachmentId' => '-sAttachmentId-')))
->SetDisplayEndpoint($this->oFormHandlerHelper->GetUrlGenerator()->generate('p_object_attachment_display',
array('sAttachmentId' => '-sAttachmentId-')))
->SetDownloadEndpoint($this->oFormHandlerHelper->GetUrlGenerator()->generate(
'p_object_attachment_download',
['sAttachmentId' => '-sAttachmentId-']
))
->SetDisplayEndpoint($this->oFormHandlerHelper->GetUrlGenerator()->generate(
'p_object_attachment_display',
['sAttachmentId' => '-sAttachmentId-']
))
->SetTransactionId($oForm->GetTransactionId())
->SetAllowDelete($this->oFormHandlerHelper->getCombodoPortalConf()['properties']['attachments']['allow_delete'])
->SetObject($this->oObject);
// Checking if we can edit attachments in the current state
$oObjectFormManager = $this;
$oField->SetOnFinalizeCallback(function() use ($oObjectFormManager, $oForm, $oField){
$oField->SetOnFinalizeCallback(function () use ($oObjectFormManager, $oForm, $oField) {
if (($oObjectFormManager->sMode === static::ENUM_MODE_VIEW)
|| AttachmentPlugIn::IsReadonlyState($oObjectFormManager->oObject, $oObjectFormManager->oObject->GetState(),
AttachmentPlugIn::ENUM_GUI_PORTALS) === true
|| $oForm->GetEditableFieldCount(true) === 0)
{
|| AttachmentPlugIn::IsReadonlyState(
$oObjectFormManager->oObject,
$oObjectFormManager->oObject->GetState(),
AttachmentPlugIn::ENUM_GUI_PORTALS
) === true
|| $oForm->GetEditableFieldCount(true) === 0) {
$oField->SetReadOnly(true);
}
});
if (array_key_exists($sId, $aFieldsExtraData) && array_key_exists('opened', $aFieldsExtraData[$sId])){
if (array_key_exists($sId, $aFieldsExtraData) && array_key_exists('opened', $aFieldsExtraData[$sId])) {
$oField->SetDisplayOpened(true);
}
// Adding attachments field in transition only if it is editable
if (!$this->IsTransitionForm() || !$oField->GetReadOnly()){
if (!$this->IsTransitionForm() || !$oField->GetReadOnly()) {
$oForm->AddField($oField);
}
@@ -810,8 +774,7 @@ class ObjectFormManager extends FormManager
{
// Ask to each field to clean itself
/** @var \Combodo\iTop\Form\Field\Field $oField */
foreach ($this->oForm->GetFields() as $oField)
{
foreach ($this->oForm->GetFields() as $oField) {
$oField->OnCancel();
}
// Then clean inline images from rich text editor such as TextareaField
@@ -837,7 +800,7 @@ class ObjectFormManager extends FormManager
}
$aData['messages']['error'] += [
'_main' => [$sError]
'_main' => [$sError],
];
$aData['valid'] = false;
}
@@ -875,8 +838,7 @@ class ObjectFormManager extends FormManager
$this->OnUpdate($aArgs);
// Check if form valid
if (! $this->oForm->Validate())
{
if (! $this->oForm->Validate()) {
// Handle errors
$aData['valid'] = false;
$aData['messages']['error'] += $this->oForm->GetErrorMessages();
@@ -901,8 +863,7 @@ class ObjectFormManager extends FormManager
}
// Writing object to DB
try
{
try {
$this->oObject->DBWrite();
} catch (CoreCannotSaveObjectException $e) {
throw new Exception($e->getTextMessage());
@@ -929,34 +890,29 @@ class ObjectFormManager extends FormManager
InlineImage::FinalizeInlineImages($this->oObject);
// Finalizing attachments link to object
// TODO : This has to be refactored when the function from itop-attachments has been migrated into the core
if (isset($aArgs['attachmentIds']))
{
if (isset($aArgs['attachmentIds'])) {
$this->FinalizeAttachments($aArgs['attachmentIds']);
}
// Checking if we have to apply a stimulus
if (isset($aArgs['applyStimulus']))
{
if (isset($aArgs['applyStimulus'])) {
$this->oObject->ApplyStimulus($aArgs['applyStimulus']['code']);
}
// Activating triggers only on update
if ($bActivateTriggers)
{
if ($bActivateTriggers) {
$sTriggersQuery = $this->oFormHandlerHelper->getCombodoPortalConf()['properties']['triggers_query'];
if ($sTriggersQuery !== null)
{
if ($sTriggersQuery !== null) {
$aParentClasses = MetaModel::EnumParentClasses($sObjectClass, ENUM_PARENT_CLASSES_ALL);
$oTriggerSet = new DBObjectSet(DBObjectSearch::FromOQL($sTriggersQuery), array(),
array('parent_classes' => $aParentClasses));
$oTriggerSet = new DBObjectSet(
DBObjectSearch::FromOQL($sTriggersQuery),
[],
['parent_classes' => $aParentClasses]
);
/** @var \Trigger $oTrigger */
while ($oTrigger = $oTriggerSet->Fetch())
{
try
{
while ($oTrigger = $oTriggerSet->Fetch()) {
try {
$oTrigger->DoActivate($this->oObject->ToArgs('this'));
}
catch(Exception $e)
{
} catch (Exception $e) {
utils::EnrichRaisedException($oTrigger, $e);
}
}
@@ -966,30 +922,24 @@ class ObjectFormManager extends FormManager
// Resetting caselog fields value, otherwise the value will stay in it after submit.
$this->oForm->ResetCaseLogFields();
if ($bWasModified)
{
if ($bWasModified) {
//=if (isNew) because $bActivateTriggers = (!$this->oObject->IsNew() && $this->oObject->IsModified())
if(!$bActivateTriggers)
{
$aData['messages']['success'] += array( '_main' => array(Dict::Format('UI:Title:Object_Of_Class_Created', $this->oObject->GetName(),MetaModel::GetName(get_class($this->oObject)))));
}
else
{
$aData['messages']['success'] += array('_main' => array(Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($this->oObject)), $this->oObject->GetName())));
if (!$bActivateTriggers) {
$aData['messages']['success'] += [ '_main' => [Dict::Format('UI:Title:Object_Of_Class_Created', $this->oObject->GetName(), MetaModel::GetName(get_class($this->oObject)))]];
} else {
$aData['messages']['success'] += ['_main' => [Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($this->oObject)), $this->oObject->GetName())]];
}
}
}
catch (CoreCannotSaveObjectException $e) {
} catch (CoreCannotSaveObjectException $e) {
$aData['valid'] = false;
$aData['messages']['error'] += array('_main' => array($e->getTextMessage()));
$aData['messages']['error'] += ['_main' => [$e->getTextMessage()]];
if (false === $bExceptionLogged) {
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : '.$e->getMessage());
}
}
catch (Exception $e) {
} catch (Exception $e) {
$aData['valid'] = false;
$aData['messages']['error'] += [
'_main' => [ ($e instanceof CoreCannotSaveObjectException) ? $e->getTextMessage() : $e->getMessage()]
'_main' => [ ($e instanceof CoreCannotSaveObjectException) ? $e->getTextMessage() : $e->getMessage()],
];
if (false === $bExceptionLogged) {
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : '.$e->getMessage());
@@ -1016,11 +966,9 @@ class ObjectFormManager extends FormManager
{
$aFormProperties = [];
if (is_array($aArgs))
{
if (is_array($aArgs)) {
// Then we retrieve properties of the form to build
if (isset($aArgs['formProperties']))
{
if (isset($aArgs['formProperties'])) {
$aFormProperties = $aArgs['formProperties'];
}
}
@@ -1054,20 +1002,17 @@ class ObjectFormManager extends FormManager
*/
protected function FinalizeAttachments($aAttachmentIds)
{
$aRemovedAttachmentsIds = (isset($aAttachmentIds['removed_attachments_ids'])) ? $aAttachmentIds['removed_attachments_ids'] : array();
$aRemovedAttachmentsIds = (isset($aAttachmentIds['removed_attachments_ids'])) ? $aAttachmentIds['removed_attachments_ids'] : [];
// Not used for now. //$aActualAttachmentsIds = (isset($aAttachmentIds['actual_attachments_ids'])) ? $aAttachmentIds['actual_attachments_ids'] : array();
$aActions = array();
$aActions = [];
// Removing attachments from currents
if (!empty($aRemovedAttachmentsIds))
{
if (!empty($aRemovedAttachmentsIds)) {
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id");
$oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($this->oObject), 'item_id' => $this->oObject->GetKey()));
while ($oAttachment = $oSet->Fetch())
{
$oSet = new DBObjectSet($oSearch, [], ['class' => get_class($this->oObject), 'item_id' => $this->oObject->GetKey()]);
while ($oAttachment = $oSet->Fetch()) {
// Remove attachments that are no longer attached to the current object
if (in_array($oAttachment->GetKey(), $aRemovedAttachmentsIds))
{
if (in_array($oAttachment->GetKey(), $aRemovedAttachmentsIds)) {
$aData = ['attachment' => $oAttachment];
$this->oObject->FireEvent(EVENT_REMOVE_ATTACHMENT_FROM_OBJECT, $aData);
$oAttachment->DBDelete();
@@ -1080,16 +1025,12 @@ class ObjectFormManager extends FormManager
$sTempId = utils::GetUploadTempId($this->oForm->GetTransactionId());
$sOQL = 'SELECT Attachment WHERE temp_id = :temp_id';
$oSearch = DBObjectSearch::FromOQL($sOQL);
$oSet = new DBObjectSet($oSearch, array(), array('temp_id' => $sTempId));
while ($oAttachment = $oSet->Fetch())
{
$oSet = new DBObjectSet($oSearch, [], ['temp_id' => $sTempId]);
while ($oAttachment = $oSet->Fetch()) {
// Temp attachment removed
if (in_array($oAttachment->GetKey(), $aRemovedAttachmentsIds))
{
if (in_array($oAttachment->GetKey(), $aRemovedAttachmentsIds)) {
$oAttachment->DBDelete();
}
else
{
} else {
$oAttachment->SetItem($this->oObject);
$oAttachment->Set('temp_id', '');
$oAttachment->DBUpdate();
@@ -1101,8 +1042,7 @@ class ObjectFormManager extends FormManager
// Save changes to current object history
// inspired from itop-attachments/main.attachments.php / RecordHistory
foreach ($aActions as $oChangeOp)
{
foreach ($aActions as $oChangeOp) {
$oChangeOp->Set("objclass", get_class($this->oObject));
$oChangeOp->Set("objkey", $this->oObject->GetKey());
$oChangeOp->DBInsertNoReload();
@@ -1125,9 +1065,8 @@ class ObjectFormManager extends FormManager
$sTempId = utils::GetUploadTempId($this->oForm->GetTransactionId());
$sOQL = 'SELECT Attachment WHERE temp_id = :temp_id';
$oSearch = DBObjectSearch::FromOQL($sOQL);
$oSet = new DBObjectSet($oSearch, array(), array('temp_id' => $sTempId));
while ($oAttachment = $oSet->Fetch())
{
$oSet = new DBObjectSet($oSearch, [], ['temp_id' => $sTempId]);
while ($oAttachment = $oSet->Fetch()) {
$oAttachment->DBDelete();
}
}
@@ -1147,14 +1086,11 @@ class ObjectFormManager extends FormManager
{
$oBlob = $oAttachment->Get('contents');
$sFileName = $oBlob->GetFileName();
if ($bCreate)
{
if ($bCreate) {
$oChangeOp = new CMDBChangeOpAttachmentAdded();
$oChangeOp->Set('attachment_id', $oAttachment->GetKey());
$oChangeOp->Set('filename', $sFileName);
}
else
{
} else {
$oChangeOp = new CMDBChangeOpAttachmentRemoved();
$oChangeOp->Set('filename', $sFileName);
}
@@ -1238,8 +1174,7 @@ class ObjectFormManager extends FormManager
{
$sObjectClass = get_class($this->oObject);
foreach ($aCurrentValues as $sAttCode => $value)
{
foreach ($aCurrentValues as $sAttCode => $value) {
if (count($this->aFieldsAtts) !== 0) {
if (!array_key_exists($sAttCode, $this->aFieldsAtts)) {
continue;
@@ -1342,8 +1277,7 @@ class ObjectFormManager extends FormManager
}
$oOrmSet->ApplyDelta(json_decode($value, true));
$this->oObject->Set($sAttCode, $oOrmSet);
} elseif ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
{
} elseif ($oAttDef instanceof AttributeDateTime) { // AttributeDate is derived from AttributeDateTime
if ($value != null) {
$value = $oAttDef->GetFormat()->Parse($value);
if (is_object($value)) {
@@ -1351,11 +1285,9 @@ class ObjectFormManager extends FormManager
}
}
$this->oObject->Set($sAttCode, $value);
}
elseif ($oAttDef->IsScalar() && is_array($value)) {
} elseif ($oAttDef->IsScalar() && is_array($value)) {
$this->oObject->Set($sAttCode, current($value));
}
elseif ($oAttDef->GetEditClass() === 'CustomFields') {
} elseif ($oAttDef->GetEditClass() === 'CustomFields') {
// We don't update attribute as ormCustomField comparaison is not working as excepted.
// When several templates available, "template_id" is not sent by the portal has it is a read-only select input
// therefore, the TemplateFieldsHandler::CompareValues() doesn't work.
@@ -1377,8 +1309,7 @@ class ObjectFormManager extends FormManager
$this->oObject->Set($sAttCode, $value);
}
// Else don't update! Otherwise we might loose current value
}
else {
} else {
$this->oObject->Set($sAttCode, $value);
}
}
@@ -1400,9 +1331,9 @@ class ObjectFormManager extends FormManager
public function PrepareFields(): void
{
$sObjectClass = get_class($this->oObject);
$this->aFieldsAtts = array();
$this->aExtraData = array();
$aFieldsDMOnlyAttCodes = array();
$this->aFieldsAtts = [];
$this->aExtraData = [];
$aFieldsDMOnlyAttCodes = [];
if (array_key_exists('type', $this->aFormProperties)) {
switch ($this->aFormProperties['type']) {
case 'custom_list':
@@ -1518,8 +1449,7 @@ class ObjectFormManager extends FormManager
if (array_key_exists('type', $this->aFormProperties) && $this->aFormProperties['type'] !== 'static') {
if ($this->IsTransitionForm()) {
$aDatamodelAttCodes = $this->oObject->GetTransitionAttributes($this->aFormProperties['stimulus_code']);
}
else {
} else {
$aDatamodelAttCodes = MetaModel::ListAttributeDefs($sObjectClass);
}
@@ -1536,12 +1466,10 @@ class ObjectFormManager extends FormManager
// Retrieving only mandatory flag from DM when on a transition
$iFieldFlags = $value & OPT_ATT_MANDATORY;
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oObject), $sAttCode);
}
elseif ($this->oObject->IsNew()) {
} elseif ($this->oObject->IsNew()) {
$iFieldFlags = $this->oObject->GetInitialStateAttributeFlags($sAttCode);
$oAttDef = $value;
}
else {
} else {
$iFieldFlags = $this->oObject->GetAttributeFlags($sAttCode);
$oAttDef = $value;
}
@@ -1581,11 +1509,9 @@ class ObjectFormManager extends FormManager
if ($this->IsTransitionForm()) {
$aTransitionAtts = $this->oObject->GetTransitionAttributes($this->aFormProperties['stimulus_code']);
$iFieldFlags = $aTransitionAtts[$sAttCode];
}
elseif ($this->oObject->IsNew()) {
} elseif ($this->oObject->IsNew()) {
$iFieldFlags = $this->oObject->GetInitialStateAttributeFlags($sAttCode);
}
else {
} else {
$iFieldFlags = $this->oObject->GetAttributeFlags($sAttCode);
}
@@ -1629,7 +1555,7 @@ class ObjectFormManager extends FormManager
$sRendered = $this->oFormHandlerHelper->RenderFormFromTwig(
999, // doesn't matter here
$this->aFormProperties['layout']['content'],
array('oRenderer' => $this->oRenderer, 'oObject' => $this->oObject)
['oRenderer' => $this->oRenderer, 'oObject' => $this->oObject]
);
} else {
$sRendered = 'Form not rendered because of missing container';

View File

@@ -39,7 +39,7 @@ use UserRights;
class PasswordFormManager extends FormManager
{
/** @var string FORM_TYPE */
const FORM_TYPE = 'change_password';
public const FORM_TYPE = 'change_password';
/**
* @throws \Exception
@@ -106,87 +106,66 @@ class PasswordFormManager extends FormManager
$this->OnUpdate($aArgs);
// Check if form valid
if ($this->oForm->Validate())
{
if ($this->oForm->Validate()) {
// The try catch is essentially to start a MySQL transaction
try
{
try {
// Updating password
$sAuthUser = Session::Get('auth_user');
$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())
{
if ($sOldPassword !== '' && $sNewPassword !== '' && $sConfirmPassword !== '') {
if (!UserRights::CanChangePassword()) {
$aData['valid'] = false;
$aData['messages']['error'] += array(
'_main' => array(
$aData['messages']['error'] += [
'_main' => [
Dict::Format('Brick:Portal:UserProfile:Password:CantChangeContactAdministrator', ITOP_APPLICATION_SHORT),
),
);
}
else
{
if (!UserRights::CheckCredentials($sAuthUser, $sOldPassword))
{
],
];
} 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['messages']['error'] += ['old_password' => [Dict::S('UI:Login:IncorrectOldPassword')]];
} else {
if ($sNewPassword !== $sConfirmPassword) {
$aData['valid'] = false;
$aData['messages']['error'] += array('confirm_password' => array(Dict::S('UI:Login:RetypePwdDoesNotMatch')));
}
elseif ($sNewPassword === $sOldPassword)
{
$aData['messages']['error'] += ['confirm_password' => [Dict::S('UI:Login:RetypePwdDoesNotMatch')]];
} elseif ($sNewPassword === $sOldPassword) {
$aData['valid'] = false;
$aData['messages']['error'] += array('new_password' => array(Dict::S('UI:Login:PasswordNotChanged')));
}
else
{
$aData['messages']['error'] += ['new_password' => [Dict::S('UI:Login:PasswordNotChanged')]];
} else {
try {
if (!UserRights::ChangePassword($sOldPassword, $sNewPassword))
{
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'] += [
'confirm_password' => [
Dict::Format(
'Brick:Portal:UserProfile:Password:CantChangeForUnknownReason',
ITOP_APPLICATION_SHORT
),
],
];
} else {
$aData['messages']['success'] += ['_main' => [Dict::S('Brick:Portal:Object:Form:Message:Saved')]];
}
else
{
$aData['messages']['success'] += array('_main' => array(Dict::S('Brick:Portal:Object:Form:Message:Saved')));
}
}
catch (\CoreCannotSaveObjectException $e)
{
} catch (\CoreCannotSaveObjectException $e) {
$aData['valid'] = false;
$aData['messages']['error'] += array(
$aData['messages']['error'] += [
'new_password' => $e->getIssues(),
'confirm_password' => array(),
);
'confirm_password' => [],
];
}
}
}
}
}
}
catch (Exception $e)
{
} catch (Exception $e) {
$aData['valid'] = false;
$aData['messages']['error'] += array('_main' => array($e->getMessage()));
$aData['messages']['error'] += ['_main' => [$e->getMessage()]];
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Exception during submit ('.$e->getMessage().')');
}
}
else
{
} else {
// Handle errors
$aData['valid'] = false;
$aData['messages']['error'] += $this->oForm->GetErrorMessages();
@@ -207,12 +186,9 @@ class PasswordFormManager extends FormManager
$this->Build();
// Then we update it with new values
if (is_array($aArgs))
{
if (isset($aArgs['currentValues']))
{
foreach ($aArgs['currentValues'] as $sPreferenceName => $value)
{
if (is_array($aArgs)) {
if (isset($aArgs['currentValues'])) {
foreach ($aArgs['currentValues'] as $sPreferenceName => $value) {
$this->oForm->GetField($sPreferenceName)->SetCurrentValue($value);
}
}

View File

@@ -39,7 +39,7 @@ use UserRights;
class PreferencesFormManager extends FormManager
{
/** @var string FORM_TYPE */
const FORM_TYPE = 'preferences';
public const FORM_TYPE = 'preferences';
/**
* @throws \Exception
@@ -63,9 +63,8 @@ class PreferencesFormManager extends FormManager
->SetCurrentValue(Dict::GetUserLanguage())
->SetStartsWithNullChoice(false);
// - Preparing choices
$aChoices = array();
foreach (Dict::GetLanguages() as $sCode => $aLanguage)
{
$aChoices = [];
foreach (Dict::GetLanguages() as $sCode => $aLanguage) {
$aChoices[$sCode] = $aLanguage['description'].' ('.$aLanguage['localized_description'].')';
}
asort($aChoices);
@@ -109,11 +108,9 @@ class PreferencesFormManager extends FormManager
$this->OnUpdate($aArgs);
// Check if form valid
if ($this->oForm->Validate())
{
if ($this->oForm->Validate()) {
// The try catch is essentially to start a MySQL transaction
try
{
try {
// Starting transaction
CMDBSource::Query('START TRANSACTION');
$iFieldChanged = 0;
@@ -123,34 +120,28 @@ class PreferencesFormManager extends FormManager
$oCurUser = UserRights::GetUserObject();
// - Language
$sLanguage = $this->oForm->GetField('language')->GetCurrentValue();
if (($sLanguage !== null) && ($oCurUser->Get('language') !== $sLanguage))
{
if (($sLanguage !== null) && ($oCurUser->Get('language') !== $sLanguage)) {
$oCurUser->Set('language', $sLanguage);
$iFieldChanged++;
}
// Updating only if preferences changed
if ($iFieldChanged > 0)
{
if ($iFieldChanged > 0) {
$oCurUser->AllowWrite(true);
$oCurUser->DBUpdate();
$aData['messages']['success'] += array('_main' => array(Dict::S('Brick:Portal:Object:Form:Message:Saved')));
$aData['messages']['success'] += ['_main' => [Dict::S('Brick:Portal:Object:Form:Message:Saved')]];
}
// Ending transaction with a commit as everything was fine
CMDBSource::Query('COMMIT');
}
catch (Exception $e)
{
} catch (Exception $e) {
// End transaction with a rollback as something failed
CMDBSource::Query('ROLLBACK');
$aData['valid'] = false;
$aData['messages']['error'] += array('_main' => array($e->getMessage()));
$aData['messages']['error'] += ['_main' => [$e->getMessage()]];
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Rollback during submit ('.$e->getMessage().')');
}
}
else
{
} else {
// Handle errors
$aData['valid'] = false;
$aData['messages']['error'] += $this->oForm->GetErrorMessages();
@@ -171,12 +162,9 @@ class PreferencesFormManager extends FormManager
$this->Build();
// Then we update it with new values
if (is_array($aArgs))
{
if (isset($aArgs['currentValues']))
{
foreach ($aArgs['currentValues'] as $sPreferenceName => $value)
{
if (is_array($aArgs)) {
if (isset($aArgs['currentValues'])) {
foreach ($aArgs['currentValues'] as $sPreferenceName => $value) {
$this->oForm->GetField($sPreferenceName)->SetCurrentValue($value);
}
}

View File

@@ -18,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Portal\Helper;
/**
@@ -53,14 +52,13 @@ class BrickControllerHelper
public function ExtractSortParams()
{
// Getting sort params
$aSortParams = $this->oRequestManipulator->ReadParam('aSortParams', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
$aSortParams = $this->oRequestManipulator->ReadParam('aSortParams', [], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
// Converting sort direction to proper format for DBObjectSet as it only accept real booleans
foreach ($aSortParams as $sAttributeAlias => $sDirection)
{
foreach ($aSortParams as $sAttributeAlias => $sDirection) {
$aSortParams[$sAttributeAlias] = ($sDirection === 'true');
}
return $aSortParams;
}
}
}

View File

@@ -18,10 +18,8 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Portal\Helper;
use AttributeImage;
use AttributeSet;
use AttributeTagSet;
@@ -44,9 +42,9 @@ use utils;
class BrowseBrickHelper
{
/** @var string LEVEL_SEPARATOR */
const LEVEL_SEPARATOR = '-';
public const LEVEL_SEPARATOR = '-';
/** @var array OPTIONAL_ATTRIBUTES */
const OPTIONAL_ATTRIBUTES = array('tooltip_att', 'description_att', 'image_att');
public const OPTIONAL_ATTRIBUTES = ['tooltip_att', 'description_att', 'image_att'];
/** @var \Combodo\iTop\Portal\Helper\SecurityHelper */
private $oSecurityHelper;
@@ -62,7 +60,10 @@ 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;
@@ -89,24 +90,24 @@ class BrowseBrickHelper
*/
public function TreeToFlatLevelsProperties(array $aLevels, array &$aLevelsProperties, $sLevelAliasPrefix = 'L')
{
foreach ($aLevels as $aLevel)
{
foreach ($aLevels as $aLevel) {
$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())
{
if ($oScopeSearch !== null && $oScopeSearch->IsAllDataAllowed()) {
$oSearch->AllowAllData();
}
if ($oSearch !== null)
{
$aLevelsProperties[$sCurrentLevelAlias] = array(
if ($oSearch !== null) {
$aLevelsProperties[$sCurrentLevelAlias] = [
'alias' => $sCurrentLevelAlias,
'title' => ($aLevel['title'] !== null) ? Dict::S($aLevel['title']) : MetaModel::GetName($oSearch->GetClass()),
'parent_att' => $aLevel['parent_att'],
@@ -115,42 +116,35 @@ class BrowseBrickHelper
'description_att' => $aLevel['description_att'],
'image_att' => $aLevel['image_att'],
'search' => $oSearch,
'fields' => array(),
'actions' => array(),
);
'fields' => [],
'actions' => [],
];
// Adding current level's fields
if (isset($aLevel['fields']))
{
$aLevelsProperties[$sCurrentLevelAlias]['fields'] = array();
if (isset($aLevel['fields'])) {
$aLevelsProperties[$sCurrentLevelAlias]['fields'] = [];
foreach ($aLevel['fields'] as $sFieldAttCode => $aFieldProperties)
{
$aLevelsProperties[$sCurrentLevelAlias]['fields'][] = array(
foreach ($aLevel['fields'] as $sFieldAttCode => $aFieldProperties) {
$aLevelsProperties[$sCurrentLevelAlias]['fields'][] = [
'code' => $sFieldAttCode,
'label' => MetaModel::GetAttributeDef($oSearch->GetClass(), $sFieldAttCode)->GetLabel(),
'hidden' => $aFieldProperties['hidden'],
);
];
}
}
// Flattening and adding sub levels
if (isset($aLevel['levels']))
{
foreach ($aLevel['levels'] as $aChildLevel)
{
if (isset($aLevel['levels'])) {
foreach ($aLevel['levels'] as $aChildLevel) {
// Checking if the sub level if allowed
$oChildSearch = DBSearch::FromOQL($aChildLevel['oql']);
if ($this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $oChildSearch->GetClass()))
{
if ($this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $oChildSearch->GetClass())) {
// Adding the sub level to this one
$aLevelsProperties[$sCurrentLevelAlias]['levels'][] = $sCurrentLevelAlias.static::LEVEL_SEPARATOR.$aChildLevel['id'];
// Adding drill down action if necessary
foreach ($aLevel['actions'] as $sId => $aAction)
{
if ($aAction['type'] === BrowseBrick::ENUM_ACTION_DRILLDOWN)
{
foreach ($aLevel['actions'] as $sId => $aAction) {
if ($aAction['type'] === BrowseBrick::ENUM_ACTION_DRILLDOWN) {
$aLevelsProperties[$sCurrentLevelAlias]['actions'][$sId] = $aAction;
break;
}
@@ -162,49 +156,43 @@ class BrowseBrickHelper
}
// Adding actions to the level
foreach ($aLevel['actions'] as $sId => $aAction)
{
foreach ($aLevel['actions'] as $sId => $aAction) {
// ... Only if it's not already there (eg. the drilldown added with the sublevels)
if (!array_key_exists($sId, $aLevelsProperties[$sCurrentLevelAlias]['actions']))
{
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;
}
elseif ($aAction['type'] === BrowseBrick::ENUM_ACTION_DRILLDOWN)
{
} elseif ($aAction['type'] === BrowseBrick::ENUM_ACTION_DRILLDOWN) {
continue;
}
// Setting action title
if (isset($aAction['title']))
{
if (isset($aAction['title'])) {
// Note : There could be an enhancement here, by checking if the string code has the '%1' needle and use Dict::S or Dict::Format accordingly.
// But it would require to benchmark a potential performance drop as it will be done for all items
$aAction['title'] = Dict::S($aAction['title']);
}
else
{
switch ($aAction['type'])
{
} else {
switch ($aAction['type']) {
case BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS:
// We can only make translate a dictionary 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']));
}
else
{
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',
['sObjectClass' => $aAction['factory']['value']]
);
} else {
$aAction['title'] = Dict::S('Brick:Portal:Browse:Action:Create');
}
break;
@@ -221,10 +209,8 @@ class BrowseBrickHelper
}
// Setting action icon class
if (!isset($aAction['icon_class']))
{
switch ($aAction['type'])
{
if (!isset($aAction['icon_class'])) {
switch ($aAction['type']) {
case BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS:
$aAction['icon_class'] = BrowseBrick::ENUM_ACTION_ICON_CLASS_CREATE_FROM_THIS;
break;
@@ -241,21 +227,19 @@ class BrowseBrickHelper
}
// Setting action url
switch ($aAction['type'])
{
switch ($aAction['type']) {
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']));
}
else
{
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create_from_factory', array(
if ($aAction['factory']['type'] === BrowseBrick::ENUM_FACTORY_TYPE_CLASS) {
$aAction['url'] = $this->oUrlGenerator->generate(
'p_object_create',
['sObjectClass' => $aAction['factory']['value']]
);
} else {
$aAction['url'] = $this->oUrlGenerator->generate('p_object_create_from_factory', [
'sEncodedMethodName' => base64_encode($aAction['factory']['value']),
'sObjectClass' => '-objectClass-',
'sObjectId' => '-objectId-',
));
]);
}
break;
}
@@ -278,10 +262,9 @@ class BrowseBrickHelper
*/
public function PrepareActionRulesForItems(array $aItems, $sLevelsAlias, array &$aLevelsProperties)
{
$aActionRules = array();
$aActionRules = [];
foreach ($aLevelsProperties[$sLevelsAlias]['actions'] as $sId => $aAction)
{
foreach ($aLevelsProperties[$sLevelsAlias]['actions'] as $sId => $aAction) {
$aActionRules[$sId] = ContextManipulatorHelper::PrepareAndEncodeRulesToken($aAction['rules'], $aItems);
}
@@ -317,11 +300,10 @@ class BrowseBrickHelper
*/
public function AddToFlatItems(array $aCurrentRow, array &$aLevelsProperties)
{
$aRow = array();
$aRow = [];
/** @var \DBObject $value */
foreach ($aCurrentRow as $key => $value)
{
foreach ($aCurrentRow as $key => $value) {
// Retrieving objects from all levels
$aItems = array_values($aCurrentRow);
@@ -332,36 +314,31 @@ class BrowseBrickHelper
$sNameAttDef = MetaModel::GetAttributeDef($sCurrentObjectClass, $sNameAttCode);
$sNameAttDefClass = get_class($sNameAttDef);
$aRow[$key] = array(
$aRow[$key] = [
'level_alias' => $key,
'id' => $sCurrentObjectId,
'name' => utils::EscapeHtml($value->Get($sNameAttCode)),
'class' => $sCurrentObjectClass,
'action_rules_token' => $this->PrepareActionRulesForItems($aItems, $key, $aLevelsProperties),
'metadata' => array(
'metadata' => [
'object_class' => $sCurrentObjectClass,
'object_id' => $sCurrentObjectId,
'attribute_code' => $sNameAttCode,
'attribute_type' => $sNameAttDefClass,
'value_raw' => $value->Get($sNameAttCode),
),
);
],
];
// Adding optional attributes if necessary
foreach (static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
{
if ($aLevelsProperties[$key][$sOptionalAttribute] !== null)
{
foreach (static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute) {
if ($aLevelsProperties[$key][$sOptionalAttribute] !== null) {
$sPropertyName = substr($sOptionalAttribute, 0, -4);
$oAttDef = MetaModel::GetAttributeDef($sCurrentObjectClass, $aLevelsProperties[$key][$sOptionalAttribute]);
if ($oAttDef instanceof AttributeImage)
{
if ($oAttDef instanceof AttributeImage) {
$tmpAttValue = $value->Get($aLevelsProperties[$key][$sOptionalAttribute]);
if ($sOptionalAttribute === 'image_att')
{
if (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty())
{
if ($sOptionalAttribute === 'image_att') {
if (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty()) {
$oOrmDoc = $tmpAttValue;
$tmpAttValue = $this->oUrlGenerator->generate('p_object_document_display', [
'sObjectClass' => $sCurrentObjectClass,
@@ -370,15 +347,11 @@ class BrowseBrickHelper
'cache' => 86400,
's' => $oOrmDoc->GetSignature(),
]);
}
else
{
} else {
$tmpAttValue = $oAttDef->Get('default_image');
}
}
}
else
{
} else {
$tmpAttValue = $value->GetAsHTML($aLevelsProperties[$key][$sOptionalAttribute]);
}
@@ -386,16 +359,13 @@ class BrowseBrickHelper
}
}
// Adding fields attributes if necessary
if (!empty($aLevelsProperties[$key]['fields']))
{
$aRow[$key]['fields'] = array();
foreach ($aLevelsProperties[$key]['fields'] as $aField)
{
if (!empty($aLevelsProperties[$key]['fields'])) {
$aRow[$key]['fields'] = [];
foreach ($aLevelsProperties[$key]['fields'] as $aField) {
$oAttDef = MetaModel::GetAttributeDef($sCurrentObjectClass, $aField['code']);
$sAttDefClass = get_class($oAttDef);
switch (true)
{
switch (true) {
case $oAttDef instanceof AttributeTagSet:
/** @var \ormTagSet $oSetValues */
$oSetValues = $value->Get($aField['code']);
@@ -412,8 +382,7 @@ class BrowseBrickHelper
case $oAttDef instanceof AttributeImage:
// Todo: This should be refactored, it has been seen multiple times in the portal
$oOrmDoc = $value->Get($aField['code']);
if (is_object($oOrmDoc) && !$oOrmDoc->IsEmpty())
{
if (is_object($oOrmDoc) && !$oOrmDoc->IsEmpty()) {
$sUrl = $this->oUrlGenerator->generate('p_object_document_display', [
'sObjectClass' => $sCurrentObjectClass,
'sObjectId' => $sCurrentObjectId,
@@ -421,9 +390,7 @@ class BrowseBrickHelper
'cache' => 86400,
's' => $oOrmDoc->GetSignature(),
]);
}
else
{
} else {
$sUrl = $oAttDef->Get('default_image');
}
$sHtmlForFieldValue = '<img src="'.$sUrl.'" />';
@@ -436,24 +403,22 @@ class BrowseBrickHelper
// For simple fields, we get the raw (stored) value as well
$bExcludeRawValue = false;
foreach (ApplicationHelper::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
{
if (is_a($sAttDefClass, $sAttDefClassToExclude, true))
{
foreach (ApplicationHelper::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) {
if (is_a($sAttDefClass, $sAttDefClassToExclude, true)) {
$bExcludeRawValue = true;
break;
}
}
$attValueRaw = ($bExcludeRawValue === false) ? $value->Get($aField['code']) : null;
$aRow[$key]['fields'][$aField['code']] = array(
$aRow[$key]['fields'][$aField['code']] = [
'object_class' => $sCurrentObjectClass,
'object_id' => $sCurrentObjectId,
'attribute_code' => $aField['code'],
'attribute_type' => $sAttDefClass,
'value_raw' => $attValueRaw,
'value_html' => $sHtmlForFieldValue,
);
];
}
}
}
@@ -503,39 +468,34 @@ class BrowseBrickHelper
// 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;
}
if (!isset($aItems[$sCurrentIndex]))
{
$aItems[$sCurrentIndex] = array(
if (!isset($aItems[$sCurrentIndex])) {
$aItems[$sCurrentIndex] = [
'level_alias' => $aCurrentRowKeys[0],
'id' => $aCurrentRowValues[0]->GetKey(),
'name' => utils::EscapeHtml($aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]]['name_att'])),
'class' => get_class($aCurrentRowValues[0]),
'subitems' => array(),
'subitems' => [],
'filter_data' => $this->GetFilterData($aLevelsProperties[$aCurrentRowKeys[0]], $aCurrentRowKeys[0], $aCurrentRowValues[0]),
'action_rules_token' => $this->PrepareActionRulesForItems($aCurrentRowObjects, $aCurrentRowKeys[0], $aLevelsProperties),
);
];
// Adding optional attributes if necessary
foreach (static::OPTIONAL_ATTRIBUTES as $sOptionalAttribute)
{
if ($aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute] !== null)
{
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 (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty())
{
if ($sOptionalAttribute === 'image_att') {
if (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty()) {
$oOrmDoc = $tmpAttValue;
$tmpAttValue = $this->oUrlGenerator->generate('p_object_document_display', [
'sObjectClass' => get_class($aCurrentRowValues[0]),
@@ -544,15 +504,11 @@ class BrowseBrickHelper
'cache' => 86400,
's' => $oOrmDoc->GetSignature(),
]);
}
else
{
} else {
$tmpAttValue = $oAttDef->Get('default_image');
}
}
}
else
{
} else {
$tmpAttValue = $aCurrentRowValues[0]->GetAsHTML($aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute]);
}
@@ -562,8 +518,7 @@ class BrowseBrickHelper
}
$aCurrentRowSliced = array_slice($aCurrentRow, 1);
if (!empty($aCurrentRowSliced))
{
if (!empty($aCurrentRowSliced)) {
$this->AddToTreeItems($aItems[$sCurrentIndex]['subitems'], $aCurrentRowSliced, $aLevelsProperties, $aCurrentRowObjects);
}
}
@@ -580,7 +535,7 @@ class BrowseBrickHelper
* @throws \CoreException
* @throws \Exception
*/
private function GetFilterData(array $aLevelProperties, string $sRowKey, DBObject $oRowValue) : array
private function GetFilterData(array $aLevelProperties, string $sRowKey, DBObject $oRowValue): array
{
// result
$sValues = "";
@@ -599,17 +554,17 @@ class BrowseBrickHelper
$sValue = $oAttDef->GetAsHTML($oRowValue->Get($aField['code']));
// do not print empty fields
if(!utils::IsNullOrEmptyString($sValue)){
if (!utils::IsNullOrEmptyString($sValue)) {
// append to result
$sValues .= $sValue;
$sValuesAndCodes .= '<span><span class="tree-item-filter-data-label">' . $aField['label'] . ':</span> ' . $sValue . '</span>';
$sValuesAndCodes .= '<span><span class="tree-item-filter-data-label">'.$aField['label'].':</span> '.$sValue.'</span>';
}
}
return [
'values' => $sValues,
'values_and_codes' => $sValuesAndCodes
'values_and_codes' => $sValuesAndCodes,
];
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -93,4 +94,4 @@ class ExtensibilityHelper
return $aTabSectionExtensions;
}
}
}

View File

@@ -38,7 +38,7 @@ use MetaModel;
class LifecycleValidatorHelper
{
/** @var string DEFAULT_GENERATED_CLASS */
const DEFAULT_GENERATED_CLASS = 'PortalLifecycleValues';
public const DEFAULT_GENERATED_CLASS = 'PortalLifecycleValues';
/** @var string|null $sCachePath */
protected $sCachePath;
@@ -64,9 +64,10 @@ class LifecycleValidatorHelper
{
$this->sFilename = "{$sPortalId}.lifecycle.php";
$this->sCachePath = $sPortalCachePath;
$this->sInstancePrefix = "{$sPortalId}-";;
$this->sInstancePrefix = "{$sPortalId}-";
;
$this->sGeneratedClass = static::DEFAULT_GENERATED_CLASS;
$this->aProfilesMatrix = array();
$this->aProfilesMatrix = [];
$this->Init($moduleDesign->GetNodes('/module_design/classes/class'));
}
@@ -143,8 +144,7 @@ class LifecycleValidatorHelper
public function Init(DOMNodeList $oNodes)
{
// Checking cache path
if ($this->sCachePath === null)
{
if ($this->sCachePath === null) {
$this->sCachePath = utils::GetCachePath();
}
// Building full pathname for file
@@ -152,61 +152,48 @@ class LifecycleValidatorHelper
// 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))
{
if (!file_exists($sFilePath)) {
// - Build php array from xml
$aProfiles = array();
$aProfiles = [];
// This will be used to know which classes have been set, so we can set the missing ones.
$aProfileClasses = array();
$aProfileClasses = [];
// Iterating over the class nodes
/** @var \Combodo\iTop\DesignElement $oClassNode */
foreach ($oNodes as $oClassNode)
{
foreach ($oNodes as $oClassNode) {
// Retrieving mandatory class id attribute
$sClass = $oClassNode->getAttribute('id');
if ($sClass === '')
{
if ($sClass === '') {
throw new DOMFormatException('Class tag must have an id attribute.', null, null, $oClassNode);
}
// Retrieving lifecycle node of the class
$oLifecycleNode = $oClassNode->GetOptionalElement('lifecycle');
if ($oLifecycleNode !== null)
{
if ($oLifecycleNode !== null) {
// Iterating over scope nodes of the class
$oStimuliNode = $oLifecycleNode->GetOptionalElement('stimuli');
if ($oStimuliNode !== null)
{
if ($oStimuliNode !== null) {
/** @var \Combodo\iTop\DesignElement $oStimulusNode */
foreach ($oStimuliNode->GetNodes('./stimulus') as $oStimulusNode)
{
foreach ($oStimuliNode->GetNodes('./stimulus') as $oStimulusNode) {
// Retrieving mandatory scope id attribute
$sStimulusId = $oStimulusNode->getAttribute('id');
if ($sStimulusId === '')
{
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();
$aProfilesNames = [];
// 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)
{
if (($oProfilesNode === null) || ($oProfilesNode->GetNodes('./denied_profile')->length === 0)) {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
$aProfilesNames[] = $aValue['name'];
}
}
else
{
} else {
/** @var \Combodo\iTop\DesignElement $oProfileNode */
foreach ($oProfilesNode->GetNodes('./denied_profile') as $oProfileNode)
{
foreach ($oProfilesNode->GetNodes('./denied_profile') as $oProfileNode) {
// Retrieving mandatory profile id attribute
$sProfileId = $oProfileNode->getAttribute('id');
if ($sProfileId === '')
{
if ($sProfileId === '') {
throw new DOMFormatException('Profile tag must have an id attribute.', null, null, $oProfileNode);
}
$aProfilesNames[] = $sProfileId;
@@ -214,21 +201,18 @@ class LifecycleValidatorHelper
}
//
foreach ($aProfilesNames as $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();
if (!array_key_exists($sMatrixPrefix, $aProfiles)) {
$aProfiles[$sMatrixPrefix] = [];
}
// - Adding stimulus if not already present
if (!in_array($sStimulusId, $aProfiles[$sMatrixPrefix]))
{
if (!in_array($sStimulusId, $aProfiles[$sMatrixPrefix])) {
$aProfiles[$sMatrixPrefix][] = $sStimulusId;
}
}
@@ -244,20 +228,15 @@ class LifecycleValidatorHelper
// 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>
foreach ($aProfileClasses as $sProfileClass)
{
foreach (MetaModel::EnumChildClasses($sProfileClass) as $sChildClass)
{
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)
{
if (!in_array($sChildClass, $aProfileClasses)) {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
$iProfileId = $iKey;
// If the current profile has scope for that class in that mode, we duplicate it
if (isset($aProfiles[$iProfileId.'_'.$sProfileClass]))
{
if (isset($aProfiles[$iProfileId.'_'.$sProfileClass])) {
$aProfiles[$iProfileId.'_'.$sChildClass] = $aProfiles[$iProfileId.'_'.$sProfileClass];
}
}
@@ -270,14 +249,12 @@ class LifecycleValidatorHelper
// - Write file on disk
// - Creating dir if necessary
if (!is_dir($this->sCachePath))
{
if (!is_dir($this->sCachePath)) {
mkdir($this->sCachePath, 0777, true);
}
// -- Then creating the file
$ret = file_put_contents($sFilePath, $sPHP);
if ($ret === false)
{
if ($ret === false) {
$iLen = strlen($sPHP);
$fFree = @disk_free_space(dirname($sFilePath));
$aErr = error_get_last();
@@ -285,8 +262,7 @@ class LifecycleValidatorHelper
}
}
if (!class_exists($this->sGeneratedClass))
{
if (!class_exists($this->sGeneratedClass)) {
require_once $this->sCachePath.$this->sFilename;
}
}
@@ -303,7 +279,7 @@ class LifecycleValidatorHelper
*/
public function GetStimuliForProfile($sProfile, $sClass)
{
return $this->GetStimuliForProfiles(array($sProfile), $sClass);
return $this->GetStimuliForProfiles([$sProfile], $sClass);
}
/**
@@ -319,17 +295,15 @@ class LifecycleValidatorHelper
*/
public function GetStimuliForProfiles($aProfiles, $sClass)
{
$aStimuli = array();
$aStimuli = [];
// Preparing available stimuli
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $aData)
{
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $aData) {
$aStimuli[$sStimulusCode] = true;
}
// Iterating on profiles to retrieving the different OQLs parts
foreach ($aProfiles as $sProfile)
{
foreach ($aProfiles as $sProfile) {
// Retrieving matrix information
$iProfileId = $this->GetProfileIdFromProfileName($sProfile);
@@ -337,10 +311,8 @@ class LifecycleValidatorHelper
$sLifecycleValuesClass = $this->sGeneratedClass;
$aProfileMatrix = $sLifecycleValuesClass::GetProfileStimuli($iProfileId, $sClass);
foreach ($aProfileMatrix as $sStimulusCode)
{
if (array_key_exists($sStimulusCode, $aStimuli))
{
foreach ($aProfileMatrix as $sStimulusCode) {
if (array_key_exists($sStimulusCode, $aStimuli)) {
unset($aStimuli[$sStimulusCode]);
}
}
@@ -364,18 +336,12 @@ class LifecycleValidatorHelper
// We try to find the profile from its name in order to retrieve it's id
// - If the regular UserRights add-on is installed we check the profiles array
if (class_exists('ProfilesConfig'))
{
if (defined($sProfile) && in_array($sProfile, ProfilesConfig::GetProfilesValues()))
{
if (class_exists('ProfilesConfig')) {
if (defined($sProfile) && in_array($sProfile, ProfilesConfig::GetProfilesValues())) {
$iProfileId = constant($sProfile);
}
else
{
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue)
{
if ($aValue['name'] === $sProfile)
{
} else {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
if ($aValue['name'] === $sProfile) {
$iProfileId = $iKey;
break;
}
@@ -383,14 +349,12 @@ class LifecycleValidatorHelper
}
}
// - Else, we can't find the id from the name as we don't know the used UserRights add-on. It has to be a constant
else
{
else {
throw new Exception('Lifecycle validator : Unknown UserRights addon, lifecycle\'s profile must be a constant');
}
// If profile was not found from its name or from a constant, we throw an exception
if ($iProfileId === null)
{
if ($iProfileId === null) {
throw new Exception('Lifecycle validator : Could not find "'.$sProfile.'" in the profiles list');
}
@@ -404,7 +368,7 @@ class LifecycleValidatorHelper
*
* @return string
*/
protected function BuildPHPClass($aProfiles = array())
protected function BuildPHPClass($aProfiles = [])
{
$sProfiles = var_export($aProfiles, true);
$sClassName = $this->sGeneratedClass;
@@ -447,4 +411,3 @@ EOF;
}
}

View File

@@ -44,50 +44,50 @@ use utils;
class NavigationRuleHelper
{
// Available point of origin for the navigation
const ENUM_ORIGIN_PAGE = 'default';
const ENUM_ORIGIN_MODAL = 'modal';
public const ENUM_ORIGIN_PAGE = 'default';
public const ENUM_ORIGIN_MODAL = 'modal';
// Available rule categories (of rule types)
/** @var string ENUM_RULE_CAT_CLOSE (eg. close modal/window) */
const ENUM_RULE_CAT_CLOSE = 'close';
public const ENUM_RULE_CAT_CLOSE = 'close';
/** @var string ENUM_RULE_CAT_REDIRECT (eg. go-to-homepage, go-to-object, go-to-brick, ...) */
const ENUM_RULE_CAT_REDIRECT = 'redirect';
public const ENUM_RULE_CAT_REDIRECT = 'redirect';
// Available rule types
/** @var string ENUM_RULE_CLOSE */
const ENUM_RULE_CLOSE = 'close';
public const ENUM_RULE_CLOSE = 'close';
/** @var string ENUM_RULE_GO_TO_HOMEPAGE */
const ENUM_RULE_GO_TO_HOMEPAGE = 'go-to-homepage';
public const ENUM_RULE_GO_TO_HOMEPAGE = 'go-to-homepage';
/** @var string ENUM_RULE_GO_TO_OBJECT */
const ENUM_RULE_GO_TO_OBJECT = 'go-to-object';
public const ENUM_RULE_GO_TO_OBJECT = 'go-to-object';
/** @var string ENUM_RULE_GO_TO_BRICK */
const ENUM_RULE_GO_TO_BRICK = 'go-to-brick';
public const ENUM_RULE_GO_TO_BRICK = 'go-to-brick';
/** @var string ENUM_RULE_GO_TO_MANAGE_BRICK */
const ENUM_RULE_GO_TO_MANAGE_BRICK = 'go-to-manage-brick';
public const ENUM_RULE_GO_TO_MANAGE_BRICK = 'go-to-manage-brick';
/** @var string ENUM_RULE_GO_TO_BROWSE_BRICK */
const ENUM_RULE_GO_TO_BROWSE_BRICK = 'go-to-browse-brick';
public const ENUM_RULE_GO_TO_BROWSE_BRICK = 'go-to-browse-brick';
// - Defaults
/** @var string DEFAULT_RULE_SUBMIT_PAGE */
const DEFAULT_RULE_SUBMIT_PAGE = self::ENUM_RULE_GO_TO_OBJECT;
public const DEFAULT_RULE_SUBMIT_PAGE = self::ENUM_RULE_GO_TO_OBJECT;
/** @var string DEFAULT_RULE_SUBMIT_MODAL */
const DEFAULT_RULE_SUBMIT_MODAL = self::ENUM_RULE_CLOSE;
public const DEFAULT_RULE_SUBMIT_MODAL = self::ENUM_RULE_CLOSE;
/** @var string DEFAULT_RULE_CANCEL_PAGE */
const DEFAULT_RULE_CANCEL_PAGE = self::ENUM_RULE_CLOSE;
public const DEFAULT_RULE_CANCEL_PAGE = self::ENUM_RULE_CLOSE;
/** @var string DEFAULT_RULE_CANCEL_MODAL */
const DEFAULT_RULE_CANCEL_MODAL = self::ENUM_RULE_CLOSE;
public const DEFAULT_RULE_CANCEL_MODAL = self::ENUM_RULE_CLOSE;
// Rule go-to-object properties
/** @var string DEFAULT_RULE_GO_TO_OBJECT_PROP_MODE */
const DEFAULT_RULE_GO_TO_OBJECT_PROP_MODE = ObjectFormHandlerHelper::ENUM_MODE_VIEW;
public const DEFAULT_RULE_GO_TO_OBJECT_PROP_MODE = ObjectFormHandlerHelper::ENUM_MODE_VIEW;
/** @var string ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL */
const ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL = 'modal';
public const ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL = 'modal';
/** @var string ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_PAGE */
const ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_PAGE = 'page';
public const ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_PAGE = 'page';
/** @var string ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_CURRENT */
const ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_CURRENT = 'current';
public const ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_CURRENT = 'current';
/** @var string DEFAULT_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET */
const DEFAULT_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET = self::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL;
public const DEFAULT_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET = self::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL;
// Rule go-to-brick properties
// TODO
@@ -112,9 +112,12 @@ class NavigationRuleHelper
* @throws \DOMFormatException
*/
public function __construct(
ModuleDesign $oModuleDesign, RouterInterface $oRouter, BrickCollection $oBrickCollection, ScopeValidatorHelper $oScopeValidator
ModuleDesign $oModuleDesign,
RouterInterface $oRouter,
BrickCollection $oBrickCollection,
ScopeValidatorHelper $oScopeValidator
) {
$this->aRules = array();
$this->aRules = [];
$this->oRouter = $oRouter;
$this->oBrickCollection = $oBrickCollection;
@@ -132,31 +135,29 @@ class NavigationRuleHelper
*/
public function Init(DOMNodeList $oNodes)
{
$this->aRules = array();
$this->aRules = [];
// Iterating over the navigation_rule nodes
/** @var \Combodo\iTop\DesignElement $oRuleNode */
foreach ($oNodes as $oRuleNode)
{
foreach ($oNodes as $oRuleNode) {
// Checking node name
if ($oRuleNode->nodeName !== 'navigation_rule')
{
if ($oRuleNode->nodeName !== 'navigation_rule') {
continue;
}
// Retrieving mandatory attributes
// - ID
$sRuleId = $oRuleNode->getAttribute('id');
if ($sRuleId === '')
{
if ($sRuleId === '') {
throw new DOMFormatException('Rule tag must have an id attribute.', null, null, $oRuleNode);
}
// - Type
$sRuleType = $oRuleNode->getAttribute('xsi:type');
if (($sRuleType === '') || !in_array($sRuleType, static::GetAllowedTypes()))
{
throw new DOMFormatException('Navigation rule tag must have a valid xsi:type, "'.$sRuleType.'" given, expected '.implode('|',
static::GetAllowedTypes()), null, null, $oRuleNode);
if (($sRuleType === '') || !in_array($sRuleType, static::GetAllowedTypes())) {
throw new DOMFormatException('Navigation rule tag must have a valid xsi:type, "'.$sRuleType.'" given, expected '.implode(
'|',
static::GetAllowedTypes()
), null, null, $oRuleNode);
}
// Load rule from XML
@@ -176,10 +177,10 @@ class NavigationRuleHelper
*/
public static function GetAllowedOrigins()
{
return array(
return [
static::ENUM_ORIGIN_PAGE,
static::ENUM_ORIGIN_MODAL,
);
];
}
/**
@@ -189,14 +190,14 @@ class NavigationRuleHelper
*/
public static function GetAllowedTypes()
{
return array(
return [
static::ENUM_RULE_CLOSE,
static::ENUM_RULE_GO_TO_HOMEPAGE,
static::ENUM_RULE_GO_TO_OBJECT,
static::ENUM_RULE_GO_TO_BRICK,
static::ENUM_RULE_GO_TO_BROWSE_BRICK,
static::ENUM_RULE_GO_TO_MANAGE_BRICK,
);
];
}
/**
@@ -209,8 +210,7 @@ class NavigationRuleHelper
*/
public function GetRuleDefinition($sId)
{
if (!array_key_exists($sId, $this->aRules))
{
if (!array_key_exists($sId, $this->aRules)) {
throw new Exception('NavigationRuleHelper: Could not find "'.$sId.'" in the rules list');
}
@@ -251,10 +251,10 @@ class NavigationRuleHelper
*/
public function GetDefaultCloseRuleDefinition()
{
return array(
return [
'category' => static::ENUM_RULE_CAT_CLOSE,
'type' => static::ENUM_RULE_CLOSE,
);
];
}
/**
@@ -264,10 +264,10 @@ class NavigationRuleHelper
*/
public function GetDefaultGoToHomepageRuleDefinition()
{
return array(
return [
'category' => static::ENUM_RULE_CAT_REDIRECT,
'type' => static::ENUM_RULE_GO_TO_HOMEPAGE,
);
];
}
/**
@@ -277,15 +277,15 @@ class NavigationRuleHelper
*/
public function GetDefaultGoToObjectRuleDefinition()
{
return array(
return [
'category' => static::ENUM_RULE_CAT_REDIRECT,
'type' => static::ENUM_RULE_GO_TO_OBJECT,
'properties' => array(
'properties' => [
'mode' => static::DEFAULT_RULE_GO_TO_OBJECT_PROP_MODE,
'opening_target' => static::DEFAULT_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET,
'oql' => null,
),
);
],
];
}
/**
@@ -295,16 +295,16 @@ class NavigationRuleHelper
*/
public function GetDefaultGoToBrickRuleDefinition()
{
return array(
return [
'category' => static::ENUM_RULE_CAT_REDIRECT,
'type' => static::ENUM_RULE_GO_TO_BRICK,
'properties' => array(
'route' => array(
'properties' => [
'route' => [
'id' => null,
'params' => array(),
),
),
);
'params' => [],
],
],
];
}
//----------------------------
@@ -351,21 +351,18 @@ class NavigationRuleHelper
// Default values
$aRule = $this->GetDefaultGoToObjectRuleDefinition();
$aAllowedOpeningTarget = array(
$aAllowedOpeningTarget = [
static::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_CURRENT,
static::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL,
static::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_PAGE,
);
];
/** @var \Combodo\iTop\DesignElement $oPropNode */
foreach($oRuleNode->GetNodes('*') as $oPropNode)
{
switch($oPropNode->nodeName)
{
foreach ($oRuleNode->GetNodes('*') as $oPropNode) {
switch ($oPropNode->nodeName) {
case 'mode':
$sMode = $oPropNode->GetText();
if(!in_array($sMode, ObjectFormHandlerHelper::GetAllowedModes()))
{
if (!in_array($sMode, ObjectFormHandlerHelper::GetAllowedModes())) {
throw new DOMFormatException('mode tag of navigation_rule "'.$sRuleId.'" must be valid. Expected '.implode('|', ObjectFormHandlerHelper::GetAllowedModes()).', "'.$sMode.'" given.', null, null, $oRuleNode);
}
$aRule['properties']['mode'] = $sMode;
@@ -373,8 +370,7 @@ class NavigationRuleHelper
case 'opening_target':
$sOpeningTarget = $oPropNode->GetText();
if(!in_array($sOpeningTarget, $aAllowedOpeningTarget))
{
if (!in_array($sOpeningTarget, $aAllowedOpeningTarget)) {
throw new DOMFormatException('opening_target tag of navigation_rule "'.$sRuleId.'" must be valid. Expected '.implode('|', $aAllowedOpeningTarget).', "'.$sOpeningTarget.'" given.', null, null, $oRuleNode);
}
$aRule['properties']['opening_target'] = $sOpeningTarget;
@@ -382,8 +378,7 @@ class NavigationRuleHelper
case 'oql':
$sOQL = $oPropNode->GetText();
if(empty($sOQL))
{
if (empty($sOQL)) {
throw new DOMFormatException('oql tag of navigation_rule "'.$sRuleId.'" can not be empty.');
}
$aRule['properties']['oql'] = $sOQL;
@@ -409,30 +404,24 @@ class NavigationRuleHelper
$aRule = $this->GetDefaultGoToBrickRuleDefinition();
/** @var \Combodo\iTop\DesignElement $oPropNode */
foreach($oRuleNode->GetNodes('*') as $oPropNode)
{
switch($oPropNode->nodeName)
{
foreach ($oRuleNode->GetNodes('*') as $oPropNode) {
switch ($oPropNode->nodeName) {
case 'route':
/** @var array $aRouteProperties Route ID and parameters */
$aRouteProperties = array();
$aRouteProperties = [];
/** @var DesignElement $oRoutePropNode */
foreach($oPropNode->GetNodes('*') as $oRoutePropNode)
{
switch($oRoutePropNode->nodeName)
{
foreach ($oPropNode->GetNodes('*') as $oRoutePropNode) {
switch ($oRoutePropNode->nodeName) {
case 'id':
$aRouteProperties['id'] = $oRoutePropNode->GetText();
break;
case 'params':
/** @var DesignElement $oRouteParamNode */
foreach($oRoutePropNode->GetNodes('*') as $oRouteParamNode)
{
foreach ($oRoutePropNode->GetNodes('*') as $oRouteParamNode) {
$sRouteParamId = $oRouteParamNode->getAttribute('id');
$sRouteParamValue = $oRouteParamNode->GetText();
if(empty($sRouteParamId) || empty($sRouteParamValue))
{
if (empty($sRouteParamId) || empty($sRouteParamValue)) {
throw new DOMFormatException('param tag of navigation_rule "'.$sRuleId.'" must have a valid ID and value.', null, null, $oRuleNode);
}
@@ -443,8 +432,7 @@ class NavigationRuleHelper
}
// Consistency check
if(empty($aRouteProperties['id']))
{
if (empty($aRouteProperties['id'])) {
throw new DOMFormatException('navigation_rule "'.$sRuleId.'" must have a valid ID', null, null, $oRuleNode);
}
@@ -474,16 +462,15 @@ class NavigationRuleHelper
$aRule['properties']['route']['params']['sDisplayMode'] = ManageBrick::DEFAULT_DISPLAY_MODE;
// Rule parameters to automatically map to the route parameters
$aParamsMapping = array(
$aParamsMapping = [
'id' => 'sBrickId',
'display_mode' => 'sDisplayMode',
'grouping_tab' => 'sGroupingTab',
'filter' => 'sSearchValue',
);
];
/** @var \Combodo\iTop\DesignElement $oPropNode */
foreach($oRuleNode->GetNodes('*') as $oPropNode)
{
foreach ($oRuleNode->GetNodes('*') as $oPropNode) {
$sRouteParamId = (array_key_exists($oPropNode->nodeName, $aParamsMapping)) ? $aParamsMapping[$oPropNode->nodeName] : $oPropNode->nodeName;
$aRule['properties']['route']['params'][$sRouteParamId] = $oPropNode->GetText();
}
@@ -509,15 +496,14 @@ class NavigationRuleHelper
$aRule['properties']['route']['params']['sBrowseMode'] = BrowseBrick::DEFAULT_BROWSE_MODE;
// Rule parameters to automatically map to the route parameters
$aParamsMapping = array(
$aParamsMapping = [
'id' => 'sBrickId',
'browse_mode' => 'sBrowseMode',
'filter' => 'sSearchValue',
);
];
/** @var \Combodo\iTop\DesignElement $oPropNode */
foreach($oRuleNode->GetNodes('*') as $oPropNode)
{
foreach ($oRuleNode->GetNodes('*') as $oPropNode) {
$sRouteParamId = (array_key_exists($oPropNode->nodeName, $aParamsMapping)) ? $aParamsMapping[$oPropNode->nodeName] : $oPropNode->nodeName;
$aRule['properties']['route']['params'][$sRouteParamId] = $oPropNode->GetText();
}
@@ -555,33 +541,30 @@ class NavigationRuleHelper
public function PrepareRulesForForm(array $aFormProperties, DBObject $oCurrentObject, $bIsCurrentFormInModal = false)
{
// Default values
$aResults = array(
'submit' => array(
$aResults = [
'submit' => [
'category' => static::ENUM_RULE_CAT_REDIRECT,
'url' => null,
'modal' => false,
),
'cancel' => array(
],
'cancel' => [
'category' => static::ENUM_RULE_CAT_CLOSE,
'url' => null,
'modal' => false,
),
);
],
];
// Get form's navigation rules
$aFormNavRules = (isset($aFormProperties['properties']['navigation_rules'])) ? $aFormProperties['properties']['navigation_rules'] : array('submit' => null, 'cancel' => null);
$aFormNavRules = (isset($aFormProperties['properties']['navigation_rules'])) ? $aFormProperties['properties']['navigation_rules'] : ['submit' => null, 'cancel' => null];
// Check from which origin the rule will be called
$sRuleCallOrigin = ($bIsCurrentFormInModal) ? 'modal' : 'default';
foreach(array_keys($aResults) as $sButtonCode)
{
foreach (array_keys($aResults) as $sButtonCode) {
// Retrieve rule definition
// - Default behavior when no rule specified
if(empty($aFormNavRules[$sButtonCode][$sRuleCallOrigin]))
{
switch($sButtonCode)
{
if (empty($aFormNavRules[$sButtonCode][$sRuleCallOrigin])) {
switch ($sButtonCode) {
case 'submit':
$sDefaultRuleType = ($bIsCurrentFormInModal) ? static::DEFAULT_RULE_SUBMIT_MODAL : static::DEFAULT_RULE_SUBMIT_PAGE;
break;
@@ -593,8 +576,7 @@ class NavigationRuleHelper
$aRuleDef = $this->GetDefaultRuleDefinitionFromType($sDefaultRuleType);
}
// - Specified rule
else
{
else {
$sRuleId = $aFormNavRules[$sButtonCode][$sRuleCallOrigin];
$aRuleDef = $this->GetRuleDefinition($sRuleId);
}
@@ -603,36 +585,31 @@ class NavigationRuleHelper
$aResults[$sButtonCode]['category'] = $aRuleDef['category'];
// Set properties regarding the type
switch($aRuleDef['type'])
{
switch ($aRuleDef['type']) {
case static::ENUM_RULE_GO_TO_HOMEPAGE:
$aResults[$sButtonCode]['url'] = $this->oRouter->generate('p_home');
break;
case static::ENUM_RULE_GO_TO_OBJECT:
// Target opening mode to modal if specified or should be as current form
if( ($aRuleDef['properties']['opening_target'] === static::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL)
if (($aRuleDef['properties']['opening_target'] === static::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_MODAL)
|| (($aRuleDef['properties']['opening_target'] === static::ENUM_RULE_GO_TO_OBJECT_PROP_OPENING_TARGET_CURRENT) && ($bIsCurrentFormInModal === true))
)
{
) {
$aResults[$sButtonCode]['modal'] = true;
}
// Target URL
// - Find object
if(empty($aRuleDef['properties']['oql']))
{
if (empty($aRuleDef['properties']['oql'])) {
$oTargetObject = $oCurrentObject;
}
else
{
} else {
$oSearch = DBSearch::FromOQL($aRuleDef['properties']['oql']);
$oSet = new DBObjectSet($oSearch, array(), array('this' => $oCurrentObject));
$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => array()));
$oSet = new DBObjectSet($oSearch, [], ['this' => $oCurrentObject]);
$oSet->OptimizeColumnLoad([$oSearch->GetClassAlias() => []]);
$oTargetObject = $oSet->Fetch();
}
// - Build URL
$aResults[$sButtonCode]['url'] = $this->oRouter->generate('p_object_'.$aRuleDef['properties']['mode'], array('sObjectClass' => get_class($oTargetObject), 'sObjectId' => $oTargetObject->GetKey()));
$aResults[$sButtonCode]['url'] = $this->oRouter->generate('p_object_'.$aRuleDef['properties']['mode'], ['sObjectClass' => get_class($oTargetObject), 'sObjectId' => $oTargetObject->GetKey()]);
break;
case static::ENUM_RULE_GO_TO_BRICK:

View File

@@ -18,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Portal\Helper;
use ApplicationContext;
@@ -51,16 +50,16 @@ use UserRights;
class ObjectFormHandlerHelper
{
/** @var string */
const ENUM_MODE_VIEW = 'view';
public const ENUM_MODE_VIEW = 'view';
/** @var string */
const ENUM_MODE_EDIT = 'edit';
public const ENUM_MODE_EDIT = 'edit';
/** @var string */
const ENUM_MODE_CREATE = 'create';
public const ENUM_MODE_CREATE = 'create';
/**
* @var string
* @since 2.7.7 3.0.1 3.1.0
*/
const ENUM_MODE_APPLY_STIMULUS = 'apply_stimulus';
public const ENUM_MODE_APPLY_STIMULUS = 'apply_stimulus';
/** @var \Combodo\iTop\Portal\Helper\RequestManipulatorHelper $oRequestManipulator */
private $oRequestManipulator;
@@ -95,10 +94,16 @@ class ObjectFormHandlerHelper
* @param \Combodo\iTop\Portal\Twig\AppExtension $oAppExtension
*/
public function __construct(
RequestManipulatorHelper $oRequestManipulator, ContextManipulatorHelper $oContextManipulator, NavigationRuleHelper $oNavigationRuleHelper, ScopeValidatorHelper $oScopeValidator, SecurityHelper $oSecurityHelper, UrlGeneratorInterface $oUrlGenerator, $aCombodoPortalInstanceConf, $sPortalId,
RequestManipulatorHelper $oRequestManipulator,
ContextManipulatorHelper $oContextManipulator,
NavigationRuleHelper $oNavigationRuleHelper,
ScopeValidatorHelper $oScopeValidator,
SecurityHelper $oSecurityHelper,
UrlGeneratorInterface $oUrlGenerator,
$aCombodoPortalInstanceConf,
$sPortalId,
AppExtension $oAppExtension
)
{
) {
$this->oRequestManipulator = $oRequestManipulator;
$this->oContextManipulator = $oContextManipulator;
$this->oNavigationRuleHelper = $oNavigationRuleHelper;
@@ -126,7 +131,7 @@ class ObjectFormHandlerHelper
*/
public function HandleForm(Request $oRequest, $sMode, $sObjectClass, $sObjectId = null, array $aFormProperties = null)
{
$aFormData = array();
$aFormData = [];
$sOperation = $this->oRequestManipulator->ReadParam('operation', '');
$bModal = ($oRequest->isXmlHttpRequest() && empty($sOperation));
@@ -134,71 +139,58 @@ class ObjectFormHandlerHelper
$aFormProperties = $aFormProperties ?? ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
// - Create and
if (empty($sOperation))
{
if (empty($sOperation)) {
// Retrieving action rules
//
// Note : The action rules must be a base64-encoded JSON object, this is just so users are tempted to changes values.
// But it would not be a security issue as it only presets values in the form.
$sActionRulesToken = $this->oRequestManipulator->ReadParam('ar_token', '');
$aActionRules = (!empty($sActionRulesToken)) ? ContextManipulatorHelper::DecodeRulesToken($sActionRulesToken) : array();
$aActionRules = (!empty($sActionRulesToken)) ? ContextManipulatorHelper::DecodeRulesToken($sActionRulesToken) : [];
// Preparing object
if ($sObjectId === null)
{
if ($sObjectId === null) {
// Create new UserRequest
$oObject = MetaModel::NewObject($sObjectClass);
// Retrieve action rules information to auto-fill the form if available
// Preparing object
$this->oContextManipulator->PrepareObject($aActionRules, $oObject);
$aPrefillFormParam = array(
$aPrefillFormParam = [
'user' => UserRights::GetUser(),
'origin' => 'portal',
);
];
$oObject->PrefillForm('creation_from_0', $aPrefillFormParam);
}
else
{
} else {
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, true, $this->oScopeValidator->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
}
// Preparing buttons
$aFormData['buttons'] = array(
'transitions' => array(),
'actions' => array(),
'links' => array(),
'submit' => array(
$aFormData['buttons'] = [
'transitions' => [],
'actions' => [],
'links' => [],
'submit' => [
'label' => Dict::S('Portal:Button:Submit'),
),
);
if ($sMode !== static::ENUM_MODE_APPLY_STIMULUS)
{
],
];
if ($sMode !== static::ENUM_MODE_APPLY_STIMULUS) {
// Add transition buttons
$oSetToCheckRights = DBObjectSet::FromObject($oObject);
$aStimuli = Metamodel::EnumStimuli($sObjectClass);
foreach ($oObject->EnumTransitions() as $sStimulusCode => $aTransitionDef)
{
if ($this->oSecurityHelper->IsStimulusAllowed($sStimulusCode, $sObjectClass, $oSetToCheckRights))
{
foreach ($oObject->EnumTransitions() as $sStimulusCode => $aTransitionDef) {
if ($this->oSecurityHelper->IsStimulusAllowed($sStimulusCode, $sObjectClass, $oSetToCheckRights)) {
$aFormData['buttons']['transitions'][$sStimulusCode] = $aStimuli[$sStimulusCode]->GetLabel();
}
}
// Add plugin buttons
/** @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)
{
if (is_object($oMenuItem))
{
if ($oMenuItem instanceof JSButtonItem)
{
$aFormData['buttons']['actions'][] = $oMenuItem->GetMenuItem() + array('js_files' => $oMenuItem->GetLinkedScripts());
}
elseif ($oMenuItem instanceof URLButtonItem)
{
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) {
foreach ($oExtensionInstance->EnumItems(iPopupMenuExtension::PORTAL_OBJDETAILS_ACTIONS, ['portal_id' => $this->sPortalId, 'object' => $oObject, 'mode' => $sMode]) as $oMenuItem) {
if (is_object($oMenuItem)) {
if ($oMenuItem instanceof JSButtonItem) {
$aFormData['buttons']['actions'][] = $oMenuItem->GetMenuItem() + ['js_files' => $oMenuItem->GetLinkedScripts()];
} elseif ($oMenuItem instanceof URLButtonItem) {
$aFormData['buttons']['links'][] = $oMenuItem->GetMenuItem();
}
}
@@ -206,22 +198,17 @@ 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');
}
}
else
{
$aPrefillFormParam = array(
} else {
$aPrefillFormParam = [
'user' => UserRights::GetUser(),
'origin' => 'portal',
'stimulus' => $this->oRequestManipulator->ReadParam('apply_stimulus', null, FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY)['code'],
);
];
$oObject->PrefillForm('state_change', $aPrefillFormParam);
}
@@ -235,32 +222,31 @@ class ObjectFormHandlerHelper
// Preparing renderer
// Note : We might need to distinguish form & renderer endpoints
switch($sMode)
{
switch ($sMode) {
case static::ENUM_MODE_CREATE:
case static::ENUM_MODE_EDIT:
case static::ENUM_MODE_VIEW:
if(array_key_exists('submit_endpoint', $aFormProperties)) {
$sFormEndpoint = $aFormProperties['submit_endpoint'];
} else {
$sFormEndpoint = $this->oUrlGenerator->generate(
'p_object_' . $sMode,
array(
'sObjectClass' => $sObjectClass,
'sObjectId' => $sObjectId,
)
);
}
if (array_key_exists('submit_endpoint', $aFormProperties)) {
$sFormEndpoint = $aFormProperties['submit_endpoint'];
} else {
$sFormEndpoint = $this->oUrlGenerator->generate(
'p_object_'.$sMode,
[
'sObjectClass' => $sObjectClass,
'sObjectId' => $sObjectId,
]
);
}
break;
case static::ENUM_MODE_APPLY_STIMULUS:
$sFormEndpoint = $this->oUrlGenerator->generate(
'p_object_apply_stimulus',
array(
[
'sObjectClass' => $sObjectClass,
'sObjectId' => $sObjectId,
'sStimulusCode' => $this->oRequestManipulator->ReadParam('sStimulusCode'),
)
]
);
break;
@@ -294,8 +280,7 @@ class ObjectFormHandlerHelper
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $sFormManagerClass */
$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 formmanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameters formmanager_class and formmanager_data must be defined.');
}
@@ -312,48 +297,45 @@ class ObjectFormHandlerHelper
$oFormManager->SetObject($oObj);
}
switch ($sOperation)
{
switch ($sOperation) {
case 'submit':
// Applying modification to object
$aFormData['validation'] = $oFormManager->OnSubmit(
array(
'currentValues' => $this->oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY),
'attachmentIds' => $this->oRequestManipulator->ReadParam('attachment_ids', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY),
[
'currentValues' => $this->oRequestManipulator->ReadParam('current_values', [], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY),
'attachmentIds' => $this->oRequestManipulator->ReadParam('attachment_ids', [], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY),
'formProperties' => $aFormProperties,
'applyStimulus' => $this->oRequestManipulator->ReadParam('apply_stimulus', null, FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY),
)
]
);
if ($aFormData['validation']['valid'] === true)
{
if ($aFormData['validation']['valid'] === true) {
// Note : We don't use $sObjectId there as it can be null if we are creating a new one. Instead we use the id from the created object once it has been serialized
// Check if stimulus has to be applied
$sStimulusCode = $this->oRequestManipulator->ReadParam('stimulus_code', '');
if (!empty($sStimulusCode))
{
$aFormData['validation']['redirection'] = array(
'url' => $this->oUrlGenerator->generate('p_object_apply_stimulus', array('sObjectClass' => $sObjectClass, 'sObjectId' => $oFormManager->GetObject()->GetKey(), 'sStimulusCode' => $sStimulusCode)),
if (!empty($sStimulusCode)) {
$aFormData['validation']['redirection'] = [
'url' => $this->oUrlGenerator->generate('p_object_apply_stimulus', ['sObjectClass' => $sObjectClass, 'sObjectId' => $oFormManager->GetObject()->GetKey(), 'sStimulusCode' => $sStimulusCode]),
'modal' => true,
);
];
}
} else {
$sErrorMessages = '';
foreach ($aFormData['validation']['messages']['error'] as $sFieldId => $aMessages) {
if ($sFieldId == '_main') {
$sErrorMessages .= implode(' - ', $aFormData['validation']['messages']['error']['_main']);
} else {
$oObj = $oFormManager->GetObject();
$sLabel = $oObj->GetLabel($sFieldId);
$sErrorMessages .= Dict::Format('Portal:Error:CheckToWriteFailed', $sLabel, (is_array($aMessages) ? implode(' - ', $aMessages) : $aMessages));
}
}
$sErrorMessages = '';
foreach ($aFormData['validation']['messages']['error'] as $sFieldId => $aMessages) {
if ($sFieldId == '_main') {
$sErrorMessages .= implode(' - ', $aFormData['validation']['messages']['error']['_main']);
} else {
$oObj = $oFormManager->GetObject();
$sLabel = $oObj->GetLabel($sFieldId);
$sErrorMessages .= Dict::Format('Portal:Error:CheckToWriteFailed', $sLabel, (is_array($aMessages) ? implode(' - ', $aMessages) : $aMessages));
}
}
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, $sErrorMessages);
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, $sErrorMessages);
}
break;
case 'update':
$oFormManager->OnUpdate(array('currentValues' => $this->oRequestManipulator->ReadParam('current_values', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY), 'formProperties' => $aFormProperties));
$oFormManager->OnUpdate(['currentValues' => $this->oRequestManipulator->ReadParam('current_values', [], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY), 'formProperties' => $aFormProperties]);
break;
case 'cancel':
@@ -363,33 +345,27 @@ class ObjectFormHandlerHelper
}
// Preparing field_set data
$aFieldSetData = array(
$aFieldSetData = [
//'fields_list' => $oFormManager->GetRenderer()->Render(), // GLA : This should be done just after in the if statement.
'fields_impacts' => $oFormManager->GetForm()->GetFieldsImpacts(),
'form_path' => $oFormManager->GetForm()->GetId(),
);
];
// Preparing fields list regarding the operation
if ($sOperation === 'update')
{
$aRequestedFields = $this->oRequestManipulator->ReadParam('requested_fields', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
if ($sOperation === 'update') {
$aRequestedFields = $this->oRequestManipulator->ReadParam('requested_fields', [], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
$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);
$oSubFormRenderer->SetEndpoint($oFormManager->GetRenderer()->GetEndpoint());
$aFormData['updated_fields'] = $oSubFormRenderer->Render($aRequestedFields);
}
else
{
} else {
$aFormData['updated_fields'] = $oFormManager->GetRenderer()->Render($aRequestedFields);
}
}
else
{
} else {
$aFieldSetData['fields_list'] = $oFormManager->GetRenderer()->Render();
}
@@ -407,8 +383,7 @@ class ObjectFormHandlerHelper
$aFormData['display_mode'] = (isset($aFormProperties['properties'])) ? $aFormProperties['properties']['display_mode'] : ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE;
$aFormData['hidden_fields'] = $oFormManager->GetHiddenFieldsId();
// - Set a text to be copied on title if the object is not in creation
if($sMode !== static::ENUM_MODE_CREATE && !empty($sObjectId))
{
if ($sMode !== static::ENUM_MODE_CREATE && !empty($sObjectId)) {
$aFormData['title_clipboard_text'] = Dict::Format(
'Brick:Portal:Object:Copy:TextToCopy',
$aFormData['object_name'],
@@ -435,17 +410,15 @@ class ObjectFormHandlerHelper
public function RenderFormFromTwig($sId, $sTwigString, $aData)
{
// Creating sandbox twig env. to load and test the custom form template
$oTwig = new Environment(new ArrayLoader(array($sId => $sTwigString)));
$oTwig = new Environment(new ArrayLoader([$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);
}
@@ -469,9 +442,9 @@ class ObjectFormHandlerHelper
public function CheckReadFormDataAllowed($sFormManagerData)
{
$aJsonFromData = ObjectFormManager::DecodeFormManagerData($sFormManagerData);
if(isset($aJsonFromData['formobject_class'])
if (isset($aJsonFromData['formobject_class'])
&& isset($aJsonFromData['formobject_id'])
&& !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $aJsonFromData['formobject_class'], $aJsonFromData['formobject_id'])){
&& !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $aJsonFromData['formobject_class'], $aJsonFromData['formobject_id'])) {
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Form data access denied.');
}
}
@@ -484,11 +457,11 @@ class ObjectFormHandlerHelper
*/
public static function GetAllowedModes()
{
return array(
return [
static::ENUM_MODE_VIEW,
static::ENUM_MODE_EDIT,
static::ENUM_MODE_CREATE,
);
];
}
/**
@@ -530,4 +503,4 @@ class ObjectFormHandlerHelper
{
return $this->aCombodoPortalInstanceConf;
}
}
}

View File

@@ -63,18 +63,15 @@ class RequestManipulatorHelper
*/
public function HasParam($sKey)
{
if ($this->GetCurrentRequest()->query->has($sKey))
{
if ($this->GetCurrentRequest()->query->has($sKey)) {
return true;
}
if ($this->GetCurrentRequest()->attributes->has($sKey))
{
if ($this->GetCurrentRequest()->attributes->has($sKey)) {
return true;
}
if ($this->GetCurrentRequest()->request->has($sKey))
{
if ($this->GetCurrentRequest()->request->has($sKey)) {
return true;
}
@@ -90,7 +87,7 @@ class RequestManipulatorHelper
* @param string $sKey
* @param mixed $default
* @param int $iFilter Default is FILTER_SANITIZE_SPECIAL_CHARS
* @param int $aFilterOptions @since 3.2.0 - N°6934 - Symfony 6.4 - upgrade Symfony bundles to 6.4
* @param int $aFilterOptions @since 3.2.0 - N°6934 - Symfony 6.4 - upgrade Symfony bundles to 6.4
*
* @return mixed|null
*
@@ -98,18 +95,15 @@ class RequestManipulatorHelper
*/
public function ReadParam($sKey, $default = null, $iFilter = FILTER_SANITIZE_SPECIAL_CHARS, $aFilterOptions = [])
{
if ($this->GetCurrentRequest()->query->has($sKey))
{
if ($this->GetCurrentRequest()->query->has($sKey)) {
return $this->GetCurrentRequest()->query->filter($sKey, $default, $iFilter, $aFilterOptions);
}
if ($this->GetCurrentRequest()->attributes->has($sKey))
{
if ($this->GetCurrentRequest()->attributes->has($sKey)) {
return $this->GetCurrentRequest()->attributes->filter($sKey, $default, $iFilter, $aFilterOptions);
}
if ($this->GetCurrentRequest()->request->has($sKey))
{
if ($this->GetCurrentRequest()->request->has($sKey)) {
return $this->GetCurrentRequest()->request->filter($sKey, $default, $iFilter, $aFilterOptions);
}

View File

@@ -41,18 +41,18 @@ use utils;
class ScopeValidatorHelper
{
/** @var string ENUM_MODE_READ */
const ENUM_MODE_READ = 'r';
public const ENUM_MODE_READ = 'r';
/** @var string ENUM_MODE_WRITE */
const ENUM_MODE_WRITE = 'w';
public const ENUM_MODE_WRITE = 'w';
/** @var string ENUM_TYPE_ALLOW */
const ENUM_TYPE_ALLOW = 'allow';
public const ENUM_TYPE_ALLOW = 'allow';
/** @var string ENUM_TYPE_RESTRICT */
const ENUM_TYPE_RESTRICT = 'restrict';
public const ENUM_TYPE_RESTRICT = 'restrict';
/** @var string DEFAULT_GENERATED_CLASS */
const DEFAULT_GENERATED_CLASS = '\\PortalScopesValues';
public const DEFAULT_GENERATED_CLASS = '\\PortalScopesValues';
/** @var bool DEFAULT_IGNORE_SILOS */
const DEFAULT_IGNORE_SILOS = false;
public const DEFAULT_IGNORE_SILOS = false;
/** @var string|null $sCachePath */
protected $sCachePath;
@@ -80,7 +80,7 @@ class ScopeValidatorHelper
$this->sCachePath = $sPortalCachePath;
$this->sInstancePrefix = "{$sPortalId}-";
$this->sGeneratedClass = static::DEFAULT_GENERATED_CLASS;
$this->aProfilesMatrix = array();
$this->aProfilesMatrix = [];
$this->Init($moduleDesign->GetNodes('/module_design/classes/class'));
}
@@ -96,8 +96,7 @@ class ScopeValidatorHelper
public function Init(DOMNodeList $oNodes)
{
// Checking cache path
if ($this->sCachePath === null)
{
if ($this->sCachePath === null) {
$this->sCachePath = utils::GetCachePath();
}
// Building full pathname for file
@@ -105,20 +104,18 @@ class ScopeValidatorHelper
// 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))
{
if (!file_exists($sFilePath)) {
$this->InitGenerateAndWriteCache($oNodes, $sFilePath);
}
if (!class_exists($this->sGeneratedClass))
{
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);
return [static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT];
}
/**
@@ -197,7 +194,7 @@ class ScopeValidatorHelper
*/
public function GetScopeFilterForProfile($sProfile, $sClass, $iAction = null)
{
return $this->GetScopeFilterForProfiles(array($sProfile), $sClass, $iAction);
return $this->GetScopeFilterForProfiles([$sProfile], $sClass, $iAction);
}
/**
@@ -217,19 +214,17 @@ class ScopeValidatorHelper
public function GetScopeFilterForProfiles($aProfiles, $sClass, $iAction = null)
{
$oSearch = null;
$aAllowSearches = array();
$aRestrictSearches = array();
$aAllowSearches = [];
$aRestrictSearches = [];
$bIgnoreSilos = static::DEFAULT_IGNORE_SILOS;
// Checking the default mode
if ($iAction === null)
{
if ($iAction === null) {
$iAction = UR_ACTION_READ;
}
// Iterating on profiles to retrieving the different OQLs parts
foreach ($aProfiles as $sProfile)
{
foreach ($aProfiles as $sProfile) {
// Retrieving matrix information
$iProfileId = $this->GetProfileIdFromProfileName($sProfile);
$sMode = ($iAction === UR_ACTION_READ) ? static::ENUM_MODE_READ : static::ENUM_MODE_WRITE;
@@ -237,39 +232,31 @@ class ScopeValidatorHelper
// Retrieving profile OQLs
$sScopeValuesClass = $this->sGeneratedClass;
$aProfileMatrix = $sScopeValuesClass::GetProfileScope($iProfileId, $sClass, $sMode);
if ($aProfileMatrix !== null)
{
if (isset($aProfileMatrix['allow']) && $aProfileMatrix['allow'] !== null)
{
if ($aProfileMatrix !== null) {
if (isset($aProfileMatrix['allow']) && $aProfileMatrix['allow'] !== null) {
$aAllowSearches[] = DBSearch::FromOQL($aProfileMatrix['allow']);
}
if (isset($aProfileMatrix['restrict']) && $aProfileMatrix['restrict'] !== null)
{
if (isset($aProfileMatrix['restrict']) && $aProfileMatrix['restrict'] !== null) {
$aRestrictSearches[] = DBSearch::FromOQL($aProfileMatrix['restrict']);
}
// If a profile should ignore allowed org, we set it for all its queries no matter the profile
if (isset($aProfileMatrix['ignore_silos']) && $aProfileMatrix['ignore_silos'] === true)
{
if (isset($aProfileMatrix['ignore_silos']) && $aProfileMatrix['ignore_silos'] === true) {
$bIgnoreSilos = true;
}
}
}
// Building the real OQL from all the parts from the different profiles
for ($i = 0; $i < count($aAllowSearches); $i++)
{
foreach ($aRestrictSearches as $oRestrictSearch)
{
for ($i = 0; $i < count($aAllowSearches); $i++) {
foreach ($aRestrictSearches as $oRestrictSearch) {
$aAllowSearches[$i] = $aAllowSearches[$i]->Intersect($oRestrictSearch);
}
}
if (count($aAllowSearches) > 0)
{
if (count($aAllowSearches) > 0) {
$oSearch = new DBUnionSearch($aAllowSearches);
$oSearch = $oSearch->RemoveDuplicateQueries();
}
if ($bIgnoreSilos === true)
{
if ($bIgnoreSilos === true) {
$oSearch->AllowAllData();
}
@@ -291,12 +278,10 @@ class ScopeValidatorHelper
public function AddScopeToQuery(DBSearch &$oQuery, $sClass, $sAction = UR_ACTION_READ)
{
$oScopeQuery = $this->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sClass, $sAction);
if ($oScopeQuery !== null)
{
if ($oScopeQuery !== null) {
$oQuery = $oQuery->Intersect($oScopeQuery);
// - Allowing all data if necessary
if ($oScopeQuery->IsAllDataAllowed())
{
if ($oScopeQuery->IsAllDataAllowed()) {
$oQuery->AllowAllData();
}
@@ -321,19 +306,16 @@ class ScopeValidatorHelper
$bIgnoreSilos = false;
// Iterating on profiles to retrieving the different OQLs parts
foreach ($aProfiles as $sProfile)
{
foreach ($aProfiles as $sProfile) {
// Retrieving matrix information
$iProfileId = $this->GetProfileIdFromProfileName($sProfile);
// Retrieving profile OQLs
$sScopeValuesClass = $this->sGeneratedClass;
$aProfileMatrix = $sScopeValuesClass::GetProfileScope($iProfileId, $sClass, static::ENUM_MODE_READ);
if ($aProfileMatrix !== null)
{
if ($aProfileMatrix !== null) {
// If a profile should ignore allowed org, we set it for all its queries no matter the profile
if (isset($aProfileMatrix['ignore_silos']) && $aProfileMatrix['ignore_silos'] === true)
{
if (isset($aProfileMatrix['ignore_silos']) && $aProfileMatrix['ignore_silos'] === true) {
$bIgnoreSilos = true;
}
}
@@ -357,18 +339,12 @@ class ScopeValidatorHelper
// We try to find the profile from its name in order to retrieve it's id
// - If the regular UserRights add-on is installed we check the profiles array
if (class_exists('ProfilesConfig'))
{
if (defined($sProfile) && in_array($sProfile, ProfilesConfig::GetProfilesValues()))
{
if (class_exists('ProfilesConfig')) {
if (defined($sProfile) && in_array($sProfile, ProfilesConfig::GetProfilesValues())) {
$iProfileId = constant($sProfile);
}
else
{
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue)
{
if ($aValue['name'] === $sProfile)
{
} else {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
if ($aValue['name'] === $sProfile) {
$iProfileId = $iKey;
break;
}
@@ -376,14 +352,12 @@ class ScopeValidatorHelper
}
}
// - Else, we can't find the id from the name as we don't know the used UserRights add-on. It has to be a constant
else
{
else {
throw new Exception('Scope validator : Unknown UserRights addon, scope\'s profile must be a constant');
}
// If profile was not found from its name or from a constant, we throw an exception
if ($iProfileId === null)
{
if ($iProfileId === null) {
throw new Exception('Scope validator : Could not find "'.$sProfile.'" in the profiles list');
}
@@ -397,7 +371,7 @@ class ScopeValidatorHelper
*
* @return string
*/
protected function BuildPHPClass($aProfiles = array())
protected function BuildPHPClass($aProfiles = [])
{
$sProfiles = var_export($aProfiles, true);
$sClassName = ltrim($this->sGeneratedClass, '\\');
@@ -450,31 +424,26 @@ EOF;
protected function InitGenerateAndWriteCache(DOMNodeList $oNodes, $sFilePath)
{
// - Build php array from xml
$aProfiles = array();
$aProfiles = [];
// This will be used to know which classes have been set, so we can set the missing ones.
$aProfileClasses = array();
$aProfileClasses = [];
// Iterating over the class nodes
/** @var \Combodo\iTop\DesignElement $oClassNode */
foreach ($oNodes as $oClassNode)
{
foreach ($oNodes as $oClassNode) {
// retrieving mandatory class id attribute
$sClass = $oClassNode->getAttribute('id');
if ($sClass === '')
{
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)
{
if ($oScopesNode !== null) {
/** @var \Combodo\iTop\DesignElement $oScopeNode */
foreach ($oScopesNode->GetNodes('./scope') as $oScopeNode)
{
foreach ($oScopesNode->GetNodes('./scope') as $oScopeNode) {
// Retrieving mandatory scope id attribute
$sScopeId = $oScopeNode->getAttribute('id');
if ($sScopeId === '')
{
if ($sScopeId === '') {
throw new DOMFormatException('Scope tag must have an id attribute.', null, null, $oScopeNode);
}
@@ -486,8 +455,7 @@ EOF;
// Retrieving the view query
$oOqlViewNode = $oScopeNode->GetUniqueElement('oql_view');
$sOqlView = $oOqlViewNode->GetText();
if ($sOqlView === null)
{
if ($sOqlView === null) {
throw new DOMFormatException(
'Scope tag in class must have a not empty oql_view tag',
0,
@@ -504,24 +472,18 @@ EOF;
// Retrieving profiles for the scope
$oProfilesNode = $oScopeNode->GetOptionalElement('allowed_profiles');
$aProfilesNames = array();
$aProfilesNames = [];
// 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)
{
if (($oProfilesNode === null) || ($oProfilesNode->GetNodes('./allowed_profile')->length === 0)) {
foreach (ProfilesConfig::GetProfilesValues() as $iKey => $aValue) {
$aProfilesNames[] = $aValue['name'];
}
}
else
{
} else {
/** @var \Combodo\iTop\DesignElement $oProfileNode */
foreach ($oProfilesNode->GetNodes('./allowed_profile') as $oProfileNode)
{
foreach ($oProfilesNode->GetNodes('./allowed_profile') as $oProfileNode) {
// Retrieving mandatory profile id attribute
$sProfileId = $oProfileNode->getAttribute('id');
if ($sProfileId === '')
{
if ($sProfileId === '') {
throw new DOMFormatException(
'Scope tag must have an id attribute.',
null,
@@ -534,8 +496,7 @@ EOF;
}
//
foreach ($aProfilesNames as $sProfileName)
{
foreach ($aProfilesNames as $sProfileName) {
// Scope profile id
$iProfileId = $this->GetProfileIdFromProfileName($sProfileName);
@@ -545,48 +506,37 @@ EOF;
$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]
))
{
$sOqlViewType,
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ]
)) {
$oExistingFilter = DBSearch::FromOQL(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ][$sOqlViewType]
);
$aFilters = array($oExistingFilter, $oViewFilter);
$aFilters = [$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)
{
if ($aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ]['ignore_silos'] === true) {
$bIgnoreSilos = true;
}
}
else
{
} else {
$oResFilter = $oViewFilter;
}
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ] = array(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_READ] = [
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos,
);
];
// - Edit query
if ($sOqlEdit !== null)
{
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)
{
if ($sOqlEdit === $sOqlView) {
// Do not intersect, edit query is identical to view query
}
else
{
if (($oEditFilter->GetClass() === $oViewFilter->GetClass()) && $oEditFilter->IsAny())
{
} else {
if (($oEditFilter->GetClass() === $oViewFilter->GetClass()) && $oEditFilter->IsAny()) {
$oEditFilter = $oViewFilter;
// Do not intersect, edit query is identical to view query
}
else
{
} else {
// Intersect
$oEditFilter = $oViewFilter->Intersect($oEditFilter);
}
@@ -594,27 +544,24 @@ EOF;
// ... 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]
))
{
$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);
$aFilters = [$oExistingFilter, $oEditFilter];
$oResFilter = new DBUnionSearch($aFilters);
}
else
{
} else {
$oResFilter = $oEditFilter;
}
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE] = array(
$aProfiles[$sMatrixPrefix.static::ENUM_MODE_WRITE] = [
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos,
);
];
}
}
}
@@ -626,27 +573,19 @@ EOF;
// 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)
{
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)
{
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)
{
foreach ([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]))
{
if (isset($aProfiles[$iProfileId.'_'.$sProfileClass.'_'.$sAction])) {
$aTmpProfile = $aProfiles[$iProfileId.'_'.$sProfileClass.'_'.$sAction];
foreach ($aTmpProfile as $sType => $sOql)
{
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)))
{
if (in_array($sType, [static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT])) {
$oTmpFilter = DBSearch::FromOQL($sOql);
$oTmpFilter->ChangeClass($sChildClass);
@@ -667,14 +606,12 @@ EOF;
// - Write file on disk
// - Creating dir if necessary
if (!is_dir($this->sCachePath))
{
if (!is_dir($this->sCachePath)) {
mkdir($this->sCachePath, 0777, true);
}
// -- Then creating the file
$ret = file_put_contents($sFilePath, $sPHP);
if ($ret === false)
{
if ($ret === false) {
$iLen = strlen($sPHP);
$fFree = @disk_free_space(dirname($sFilePath));
$aErr = error_get_last();
@@ -685,4 +622,3 @@ EOF;
}
}

View File

@@ -43,10 +43,10 @@ use BinaryExpression;
class SecurityHelper
{
/** @var array $aAllowedScopeObjectsCache */
public static $aAllowedScopeObjectsCache = array(
UR_ACTION_READ => array(),
UR_ACTION_MODIFY => array(),
);
public static $aAllowedScopeObjectsCache = [
UR_ACTION_READ => [],
UR_ACTION_MODIFY => [],
];
/** @var \Combodo\iTop\Portal\Helper\ScopeValidatorHelper $oScopeValidator */
private $oScopeValidator;
@@ -69,7 +69,6 @@ class SecurityHelper
$this->bDebug = $bDebug;
}
/**
* Returns true if the current user is allowed to do the $sAction on an $sObjectClass object (with optional $sObjectId id)
* Checks are:
@@ -94,45 +93,37 @@ class SecurityHelper
$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 (!in_array($sAction, [UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_CREATE])) {
IssueLog::Debug($sDebugTracePrefix.' as the action value could not be understood ('.UR_ACTION_READ.'/'.UR_ACTION_MODIFY.'/'.UR_ACTION_CREATE.' expected', LogChannels::PORTAL);
return false;
}
// Forcing allowed writing on the object if necessary. This is used in some particular cases.
$bObjectIsCurrentUser = ($sObjectClass === 'Person' && $sObjectId == UserRights::GetContactId());
if(in_array($sAction , array(UR_ACTION_MODIFY, UR_ACTION_READ)) && $bObjectIsCurrentUser){
if (in_array($sAction, [UR_ACTION_MODIFY, UR_ACTION_READ]) && $bObjectIsCurrentUser) {
return true;
}
}
// Checking the scopes layer
// - Transforming scope action as there is only 2 values
$sScopeAction = ($sAction === UR_ACTION_READ) ? UR_ACTION_READ : UR_ACTION_MODIFY;
// - Retrieving the query. If user has no scope, it can't access that kind of objects
$oScopeQuery = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sObjectClass, $sScopeAction);
if ($oScopeQuery === null)
{
if ($oScopeQuery === null) {
IssueLog::Debug($sDebugTracePrefix.' as there was no scope defined for action '.$sScopeAction.' and profiles '.implode('/', UserRights::ListProfiles()), LogChannels::PORTAL);
return false;
}
// - If action != create we do some additionnal checks
if ($sAction !== UR_ACTION_CREATE)
{
if ($sAction !== UR_ACTION_CREATE) {
// - Checking specific object if id is specified
if ($sObjectId !== null)
{
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 (isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId])) {
if (static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] === false) {
IssueLog::Debug($sDebugTracePrefix.' as it was denied in the scope objects cache', LogChannels::PORTAL);
return false;
}
}
else
{
} else {
// Modifying query to filter on the ID
// - Adding expression
$sObjectKeyAtt = MetaModel::DBGetKey($sObjectClass);
@@ -147,8 +138,7 @@ class SecurityHelper
// - 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)
{
if ($oSet->Count() === 0) {
// Updating cache
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = false;
@@ -163,8 +153,7 @@ class SecurityHelper
}
// Checking reading security layer. The object could be listed, check if it is actually allowed to view it
if (UserRights::IsActionAllowed($sObjectClass, $sAction) == UR_ALLOWED_NO)
{
if (UserRights::IsActionAllowed($sObjectClass, $sAction) == UR_ALLOWED_NO) {
// For security reasons, we don't want to give the user too many information on why he cannot access the object.
//throw new SecurityException('User not allowed to view this object', array('class' => $sObjectClass, 'id' => $sObjectId));
IssueLog::Debug($sDebugTracePrefix.' as the user is not allowed to access this object according to the datamodel security (cf. Console settings)', LogChannels::PORTAL);
@@ -187,15 +176,13 @@ class SecurityHelper
// 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))
{
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))
{
if (!in_array($sStimulusCode, $aStimuliFromPortal)) {
return false;
}
@@ -217,20 +204,17 @@ class SecurityHelper
public function PreloadForCache(DBSearch $oSearch, $aExtKeysToPreload = null)
{
$sObjectClass = $oSearch->GetClass();
$aObjectIds = array();
$aExtKeysIds = array();
$aColumnsToLoad = array();
$aObjectIds = [];
$aExtKeysIds = [];
$aColumnsToLoad = [];
if ($aExtKeysToPreload !== null)
{
foreach ($aExtKeysToPreload as $sAttCode)
{
if ($aExtKeysToPreload !== null) {
foreach ($aExtKeysToPreload as $sAttCode) {
/** @var \AttributeDefinition $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
if ($oAttDef->IsExternalKey())
{
if ($oAttDef->IsExternalKey()) {
/** @var \AttributeExternalKey $oAttDef */
$aExtKeysIds[$oAttDef->GetTargetClass()] = array();
$aExtKeysIds[$oAttDef->GetTargetClass()] = [];
$aColumnsToLoad[] = $sAttCode;
}
}
@@ -239,69 +223,56 @@ class SecurityHelper
// 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())
{
$oSet->OptimizeColumnLoad([$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)
{
foreach ($aColumnsToLoad as $sAttCode) {
$iExtKey = $oCurrentRow->Get($sAttCode);
if ($iExtKey > 0)
{
if ($iExtKey > 0) {
/** @var \AttributeExternalKey $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
if (!in_array($iExtKey, $aExtKeysIds[$oAttDef->GetTargetClass()]))
{
if (!in_array($iExtKey, $aExtKeysIds[$oAttDef->GetTargetClass()])) {
$aExtKeysIds[$oAttDef->GetTargetClass()][] = $iExtKey;
}
}
}
}
foreach (array(UR_ACTION_READ, UR_ACTION_MODIFY) as $sScopeAction)
{
foreach ([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)
{
if ($oScopeQuery !== null) {
// Restricting scope if specified
if (!empty($aObjectIds))
{
if (!empty($aObjectIds)) {
$oScopeQuery->AddCondition('id', array_keys($aObjectIds), 'IN');
}
// Preparing object set
$oScopeSet = new DBObjectSet($oScopeQuery);
$oScopeSet->OptimizeColumnLoad(array($oScopeQuery->GetClassAlias() => array()));
$oScopeSet->OptimizeColumnLoad([$oScopeQuery->GetClassAlias() => []]);
// Checking objects status
$aScopeObjectIds = $aObjectIds;
while ($oCurrentRow = $oScopeSet->Fetch())
{
while ($oCurrentRow = $oScopeSet->Fetch()) {
$aScopeObjectIds[$oCurrentRow->GetKey()] = true;
}
// Updating cache
if (!isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass]))
{
if (!isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass])) {
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = $aScopeObjectIds;
}
else
{
} else {
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = array_merge_recursive(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass], $aScopeObjectIds);
}
}
}
// Preloading ExtKeys
foreach ($aExtKeysIds as $sTargetClass => $aTargetIds)
{
if (!empty($aTargetIds))
{
foreach ($aExtKeysIds as $sTargetClass => $aTargetIds) {
if (!empty($aTargetIds)) {
$oTargetSearch = new DBObjectSearch($sTargetClass);
$oTargetSearch->AddCondition('id', $aTargetIds, 'IN');

View File

@@ -18,10 +18,8 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Portal\Helper;
use InvalidParameterException;
use iPortalUIExtension;
use MetaModel;
@@ -66,13 +64,11 @@ class UIExtensionsHelper
*/
public function __get($sPropName)
{
if ($this->aUIExtensions === null)
{
if ($this->aUIExtensions === null) {
$this->InitUIExtensions();
}
if (array_key_exists($sPropName, $this->aUIExtensions))
{
if (array_key_exists($sPropName, $this->aUIExtensions)) {
return $this->aUIExtensions[$sPropName];
}
@@ -87,8 +83,7 @@ class UIExtensionsHelper
*/
public function __isset($sPropName)
{
if ($this->aUIExtensions === null)
{
if ($this->aUIExtensions === null) {
$this->InitUIExtensions();
}
@@ -110,67 +105,63 @@ class UIExtensionsHelper
*/
protected function InitUIExtensions()
{
$aUIExtensions = array(
'css_files' => array(),
$aUIExtensions = [
'css_files' => [],
'css_inline' => null,
'js_files' => array(),
'js_files' => [],
'js_inline' => null,
'html' => array(),
);
'html' => [],
];
$aUIExtensionHooks = array(
$aUIExtensionHooks = [
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)
{
foreach (MetaModel::EnumPlugins('iPortalUIExtension') as $oExtensionInstance) {
// Adding CSS files
$aImportPaths = array($_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/');
foreach ($oExtensionInstance->GetCSSFiles($this->oContainer) as $sCSSFile)
{
$aImportPaths = [$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/'];
foreach ($oExtensionInstance->GetCSSFiles($this->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 = utils::GetAbsoluteUrlAppRoot().utils::GetCSSFromSASS($sCSSFilePath,
$aImportPaths);
$sCSSFileCompiled = utils::GetAbsoluteUrlAppRoot().utils::GetCSSFromSASS(
$sCSSFilePath,
$aImportPaths
);
if (!in_array($sCSSFileCompiled, $aUIExtensions['css_files']))
{
if (!in_array($sCSSFileCompiled, $aUIExtensions['css_files'])) {
$aUIExtensions['css_files'][] = $sCSSFileCompiled;
}
}
// Adding CSS inline
$sCSSInline = $oExtensionInstance->GetCSSInline($this->oContainer);
if ($sCSSInline !== null)
{
if ($sCSSInline !== null) {
$aUIExtensions['css_inline'] .= "\n\n".$sCSSInline;
}
// Adding JS files
$aUIExtensions['js_files'] = array_merge($aUIExtensions['js_files'],
$oExtensionInstance->GetJSFiles($this->oContainer));
$aUIExtensions['js_files'] = array_merge(
$aUIExtensions['js_files'],
$oExtensionInstance->GetJSFiles($this->oContainer)
);
// Adding JS inline
$sJSInline = $oExtensionInstance->GetJSInline($this->oContainer);
if ($sJSInline !== null)
{
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)
{
foreach ($aUIExtensionHooks as $sUIExtensionHook) {
$sFunctionName = 'Get'.$sUIExtensionHook.'HTML';
$sHTML = $oExtensionInstance->$sFunctionName($this->oContainer);
if ($sHTML !== null)
{
if (!array_key_exists($sUIExtensionHook, $aUIExtensions['html']))
{
if ($sHTML !== null) {
if (!array_key_exists($sUIExtensionHook, $aUIExtensions['html'])) {
$aUIExtensions['html'][$sUIExtensionHook] = '';
}
$aUIExtensions['html'][$sUIExtensionHook] .= "\n\n".$sHTML;
@@ -180,4 +171,4 @@ class UIExtensionsHelper
$this->aUIExtensions = $aUIExtensions;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -70,4 +71,4 @@ interface iAbstractPortalTabContentExtension
* @since iTop 3.2.1
*/
public function GetSectionRank(): float;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -59,4 +60,4 @@ interface iAbstractPortalTabExtension
* @since iTop 3.2.1
*/
public function GetTabLabel(): string;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -14,5 +15,4 @@ namespace Combodo\iTop\Portal\Hook;
*/
interface iUserProfileTabContentExtension extends iAbstractPortalTabContentExtension
{
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -14,5 +15,4 @@ namespace Combodo\iTop\Portal\Hook;
*/
interface iUserProfileTabExtension extends iAbstractPortalTabExtension
{
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -19,7 +20,6 @@
namespace Combodo\iTop\Portal\Routing;
use Exception;
/**
@@ -32,13 +32,13 @@ use Exception;
class ItopExtensionsExtraRoutes
{
/** @var array $aRoutes */
static private $aRoutes = array();
private static $aRoutes = [];
/**
* @var array $aControllersClasses
* @since 3.1.0
*/
static private $aControllersClasses = array();
private static $aControllersClasses = [];
/**
* @param array $extraRoutes
@@ -85,4 +85,4 @@ class ItopExtensionsExtraRoutes
{
return self::$aControllersClasses;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -117,4 +118,4 @@ class UrlGenerator implements RouterInterface
return $aParameters;
}
}
}

View File

@@ -64,8 +64,7 @@ class TemplateDefinitionDto
private ?string $sPath = null,
private readonly ?bool $bIsOverridable = false,
private readonly ?string $sAlias = null,
)
{
) {
// save overridable values
$this->sInitialValue = $sPath;
}
@@ -89,7 +88,7 @@ class TemplateDefinitionDto
*/
public function GetPath(bool $bInitialValue = false): string
{
if($bInitialValue){
if ($bInitialValue) {
return $this->sInitialValue !== null ? $this->sInitialValue : '';
}
@@ -142,4 +141,4 @@ class TemplateDefinitionDto
return $this->bIsOverridden;
}
}
}

View File

@@ -36,4 +36,4 @@ interface TemplatesProviderInterface
* @return void
*/
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void;
}
}

View File

@@ -281,8 +281,7 @@ class TemplatesProviderService
if ($oParent) {
$sCurrentClass = $oReflexion->getParentClass()->getName();
}
}
catch (Exception) {
} catch (Exception) {
}
} while ($oParent); // continue while parent class exists
@@ -327,4 +326,4 @@ class TemplatesProviderService
&& array_key_exists($sTemplateId, $this->aInstancesOverriddenTemplatesPaths[$sObjectId]['templates']));
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -22,7 +23,6 @@ namespace Combodo\iTop\Portal\Twig;
use Combodo\iTop\Application\TwigBase\Twig\Extension;
use Twig\Extension\AbstractExtension;
/**
* Class AppExtension
*
@@ -50,4 +50,4 @@ class AppExtension extends AbstractExtension
{
return Extension::GetFunctions();
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -55,7 +56,7 @@ class AppGlobal extends AbstractExtension implements GlobalsInterface
*/
public function getGlobals(): array
{
$data = array();
$data = [];
$data['allowed_portals'] = $this->userProvider->getAllowedPortals();
$data['user_preferences'] = json_decode(appUserPreferences::GetAsJSON(), true);
@@ -64,4 +65,4 @@ class AppGlobal extends AbstractExtension implements GlobalsInterface
return $data;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -33,93 +34,92 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class AppVariable implements ArrayAccess
{
/** @var ContainerInterface */
private $container;
/** @var ContainerInterface */
private $container;
/** @var DecoratedAppVariable */
private $decorated;
/** @var DecoratedAppVariable */
private $decorated;
public function __construct(DecoratedAppVariable $decorated, ContainerInterface $container = null)
{
$this->decorated = $decorated;
$this->container = $container;
}
public function __construct(DecoratedAppVariable $decorated, ContainerInterface $container = null)
{
$this->decorated = $decorated;
$this->container = $container;
}
public function __call($name, $arguments)
{
if ($this->silexApplicationEmulation->offsetExists($name)) {
return $this->silexApplicationEmulation->offsetGet($name);
}
public function __call($name, $arguments)
{
if ($this->silexApplicationEmulation->offsetExists($name)) {
return $this->silexApplicationEmulation->offsetGet($name);
}
return $this->decorated->$name(...$arguments); //WARNING: use of http://php.net/manual/fr/functions.arguments.php#functions.variable-arg-list
}
return $this->decorated->$name(...$arguments); //WARNING: use of http://php.net/manual/fr/functions.arguments.php#functions.variable-arg-list
}
/**
* @inheritDoc
*/
public function offsetExists($offset): bool
{
if ($this->container->hasParameter($offset)) {
return true;
}
if ($this->container->has($offset)) {
return true;
}
/**
* @inheritDoc
*/
public function offsetExists($offset): bool
{
if ($this->container->hasParameter($offset)) {
return true;
}
if ($this->container->has($offset)) {
return true;
}
return false;
}
return false;
}
/**
* @inheritDoc
*/
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
if ($this->container->hasParameter($offset)) {
return $this->container->getParameter($offset);
}
if ($this->container->has($offset)) {
return $this->container->get($offset);
}
public function offsetGet($offset)
{
if ($this->container->hasParameter($offset)) {
return $this->container->getParameter($offset);
}
if ($this->container->has($offset)) {
return $this->container->get($offset);
}
return null;
}
return null;
}
/**
* @inheritDoc
*/
public function offsetSet($offset, $value): void
{
/**
* @inheritDoc
*/
public function offsetSet($offset, $value): void
{
if ($this->container->hasParameter($offset)) {
$this->container->setParameter($offset, $value);
return;
}
if ($this->container->hasParameter($offset)) {
$this->container->setParameter($offset, $value);
return;
}
if ($this->container->has($offset)) {
$this->container->set($offset, $value);
return;
}
if ($this->container->has($offset)) {
$this->container->set($offset, $value);
return;
}
if (is_object($value)) {
$this->container->set($offset, $value);
return;
}
if (is_object($value)) {
$this->container->set($offset, $value);
return;
}
$this->container->setParameter($offset, $value);
}
$this->container->setParameter($offset, $value);
}
/**
* @inheritDoc
*/
public function offsetUnset($offset): void
{
if ($this->container->hasParameter($offset)) {
$this->container->setParameter($offset, null);
} else if ($this->container->has($offset)) {
$this->container->set($offset, null);
}
}
/**
* @inheritDoc
*/
public function offsetUnset($offset): void
{
if ($this->container->hasParameter($offset)) {
$this->container->setParameter($offset, null);
} elseif ($this->container->has($offset)) {
$this->container->set($offset, null);
}
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2023 Combodo SARL
*
@@ -35,7 +36,7 @@ use Twig\TwigFunction;
class CKEditorExtension extends AbstractExtension
{
/** @inheritdoc */
public function getFunctions() : array
public function getFunctions(): array
{
return [
new TwigFunction('inject_ckeditor_resources', [$this, 'injectCKEditorResources']),
@@ -48,17 +49,17 @@ class CKEditorExtension extends AbstractExtension
* @return string
* @throws \Exception
*/
public function injectCKEditorResources() : string
public function injectCKEditorResources(): string
{
$sScriptTemplate = '';
$aJSFilesRelPaths = CKEditorHelper::GetJSFilesRelPathsForCKEditor();
foreach ($aJSFilesRelPaths as $sJSFileRelPath){
$sUrl = \utils::GetAbsoluteUrlAppRoot() . $sJSFileRelPath;
foreach ($aJSFilesRelPaths as $sJSFileRelPath) {
$sUrl = \utils::GetAbsoluteUrlAppRoot().$sJSFileRelPath;
$sUrl = \utils::AddParameterToUrl($sUrl, 't', \utils::GetCacheBusterTimestamp());
$sScriptTemplate .= '<script type="text/javascript" src="' . $sUrl . '"></script>';
$sScriptTemplate .= '<script type="text/javascript" src="'.$sUrl.'"></script>';
}
return $sScriptTemplate;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -70,4 +71,4 @@ class CurrentUserAccessor
{
return $this->userProvider->getCurrentUserCanLogOff();
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -34,7 +35,7 @@ class PortalBlockExtension
*
* @since iTop 3.2.1
*/
function __construct(string $sTwig, array $aData = [])
public function __construct(string $sTwig, array $aData = [])
{
$this->sTwig = $sTwig;
$this->aData = $aData;

View File

@@ -1,4 +1,5 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -16,7 +17,6 @@ namespace Combodo\iTop\Portal\Twig;
*/
class PortalTwigContext
{
private array $aBlockExtension;
public function __construct()
@@ -35,7 +35,7 @@ class PortalTwigContext
*
* @since iTop 3.2.1
*/
function AddBlockExtension(string $sBlockName, PortalBlockExtension $oBlockExtension): void
public function AddBlockExtension(string $sBlockName, PortalBlockExtension $oBlockExtension): void
{
$this->aBlockExtension[$sBlockName] = $oBlockExtension;
}
@@ -58,4 +58,4 @@ class PortalTwigContext
$oBlockExtension = $this->aBlockExtension[$sBlockName] ?? null;
return $oBlockExtension;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2023 Combodo SARL
*
@@ -31,7 +32,7 @@ use Twig\TwigFunction;
*/
class TemplatesTwigExtension extends AbstractExtension
{
const DEFAULT_PROVIDER_CLASS = 'Combodo\\iTop\\Portal\\Controller\\AbstractController';
public const DEFAULT_PROVIDER_CLASS = 'Combodo\\iTop\\Portal\\Controller\\AbstractController';
public function __construct(private readonly TemplatesProviderService $oTemplatesService)
{
@@ -78,4 +79,4 @@ class TemplatesTwigExtension extends AbstractExtension
{
return $this->oTemplatesService->GetTemplatePath($sProviderClass, $sId, true);
}
}
}

View File

@@ -37,10 +37,10 @@ use utils;
abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
{
/** @var string PORTAL_ID */
const PORTAL_ID = '';
public const PORTAL_ID = '';
/** @var \Combodo\iTop\Portal\Kernel[] $aKernels */
private static $aKernels = array();
private static $aKernels = [];
/**
* Generate an (absolute) URL to an object, either in view or edit mode.
@@ -64,8 +64,7 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
$sUrl = self::DoPrepareObjectURL($sClass, $iId, $sMode);
if (!empty($sPreviousPortalId))
{
if (!empty($sPreviousPortalId)) {
$_ENV['PORTAL_ID'] = $sPreviousPortalId;
}
@@ -97,48 +96,39 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
//
// Note: Scopes only apply when URL check is triggered from the portal GUI.
$sObjectQueryString = null;
switch ($sMode)
{
switch ($sMode) {
case 'view':
if (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId))
{
$sObjectQueryString = $oUrlGenerator->generate('p_object_view', array('sObjectClass' => $sClass, 'sObjectId' => $iId));
if (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId)) {
$sObjectQueryString = $oUrlGenerator->generate('p_object_view', ['sObjectClass' => $sClass, 'sObjectId' => $iId]);
}
break;
case 'edit':
default:
// Checking if user is allowed to edit object, if not we check if it can at least view it.
if (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $sClass, $iId))
{
$sObjectQueryString = $oUrlGenerator->generate('p_object_edit', array('sObjectClass' => $sClass, 'sObjectId' => $iId));
}
elseif (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId))
{
$sObjectQueryString = $oUrlGenerator->generate('p_object_view', array('sObjectClass' => $sClass, 'sObjectId' => $iId));
if (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $sClass, $iId)) {
$sObjectQueryString = $oUrlGenerator->generate('p_object_edit', ['sObjectClass' => $sClass, 'sObjectId' => $iId]);
} elseif (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId)) {
$sObjectQueryString = $oUrlGenerator->generate('p_object_view', ['sObjectClass' => $sClass, 'sObjectId' => $iId]);
}
break;
}
$sPortalAbsoluteUrl = utils::GetAbsoluteUrlModulePage('itop-portal-base', 'index.php', array('portal_id' => $sPortalId));
if ($sObjectQueryString === null)
{
$sPortalAbsoluteUrl = utils::GetAbsoluteUrlModulePage('itop-portal-base', 'index.php', ['portal_id' => $sPortalId]);
if ($sObjectQueryString === null) {
$sUrl = null;
}
elseif (strpos($sPortalAbsoluteUrl, '?') !== false)
{
} elseif (strpos($sPortalAbsoluteUrl, '?') !== false) {
// Removing generated url query parameters so it can be replaced with those from the absolute url
// Mostly necessary when iTop instance has multiple portals
if (strpos($sObjectQueryString, '?') !== false)
{
if (strpos($sObjectQueryString, '?') !== false) {
$sObjectQueryString = substr($sObjectQueryString, 0, strpos($sObjectQueryString, '?'));
}
$sUrl = substr($sPortalAbsoluteUrl, 0, strpos($sPortalAbsoluteUrl, '?')).$sObjectQueryString.substr($sPortalAbsoluteUrl,
strpos($sPortalAbsoluteUrl, '?'));
}
else
{
$sUrl = substr($sPortalAbsoluteUrl, 0, strpos($sPortalAbsoluteUrl, '?')).$sObjectQueryString.substr(
$sPortalAbsoluteUrl,
strpos($sPortalAbsoluteUrl, '?')
);
} else {
$sUrl = $sPortalAbsoluteUrl.$sObjectQueryString;
}
@@ -153,8 +143,7 @@ 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]->boot();
}
@@ -175,4 +164,3 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker
return static::PrepareObjectURL($sClass, $iId, 'edit');
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -34,4 +35,4 @@ abstract class AbstractStringVariableAccessor extends AbstractVariableAccessor
{
return $this->getVariable();
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -27,22 +28,22 @@ namespace Combodo\iTop\Portal\VariableAccessor;
*/
abstract class AbstractVariableAccessor
{
/** @var string $storedVariable */
private $storedVariable;
/** @var string $storedVariable */
private $storedVariable;
/**
* @param string $variableToStore
*/
public function __construct($variableToStore)
{
$this->storedVariable = $variableToStore;
}
/**
* @param string $variableToStore
*/
public function __construct($variableToStore)
{
$this->storedVariable = $variableToStore;
}
/**
* @return string
*/
public function getVariable()
{
return $this->storedVariable;
}
}
public function getVariable()
{
return $this->storedVariable;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -19,7 +20,6 @@
namespace Combodo\iTop\Portal\VariableAccessor;
use Combodo\iTop\Portal\EventListener\UserProvider;
use Exception;
use MetaModel;
@@ -85,8 +85,7 @@ class CombodoCurrentContactPhotoUrl
try {
/** @var \cmdbAbstractObject $oContact */
$oContact = UserRights::GetContactObject();
}
catch (Exception $e) {
} catch (Exception $e) {
$oUser = $this->oUserProvider->getCurrentUser();
$oAllowedOrgSet = $oUser->Get('allowed_org_list');
if ($oAllowedOrgSet->Count() > 0) {
@@ -118,4 +117,4 @@ class CombodoCurrentContactPhotoUrl
return $sContactPhotoUrl;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
@@ -28,5 +29,4 @@ namespace Combodo\iTop\Portal\VariableAccessor;
*/
class CombodoPortalInstanceConf extends AbstractVariableAccessor
{
}
}