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 <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -48,8 +49,7 @@ class DBSearchHelper
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); $oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode); $oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
} }
} } catch (Exception $e) {
catch (Exception $e) {
// If filtering fails just ignore it // If filtering fails just ignore it
} }
} }
@@ -57,4 +57,4 @@ class DBSearchHelper
} }
} }
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Class ApplicationContext * Class ApplicationContext
* *
@@ -47,16 +47,16 @@ interface iDBObjectURLMaker
/** /**
* Direct end-users to the standard iTop application: UI.php * Direct end-users to the standard iTop application: UI.php
*/ */
class iTopStandardURLMaker implements iDBObjectURLMaker class iTopStandardURLMaker implements iDBObjectURLMaker
{ {
/** /**
* @param string $sClass * @param string $sClass
* @param string $iId * @param string $iId
* *
* @return string * @return string
* @throws \Exception * @throws \Exception
*/ */
public static function MakeObjectURL($sClass, $iId) public static function MakeObjectURL($sClass, $iId)
{ {
$sPage = DBObject::ComputeStandardUIPage($sClass); $sPage = DBObject::ComputeStandardUIPage($sClass);
@@ -68,16 +68,16 @@ class iTopStandardURLMaker implements iDBObjectURLMaker
/** /**
* Direct end-users to the standard Portal application * Direct end-users to the standard Portal application
*/ */
class PortalURLMaker implements iDBObjectURLMaker class PortalURLMaker implements iDBObjectURLMaker
{ {
/** /**
* @param string $sClass * @param string $sClass
* @param string $iId * @param string $iId
* *
* @return string * @return string
* @throws \Exception * @throws \Exception
*/ */
public static function MakeObjectURL($sClass, $iId) public static function MakeObjectURL($sClass, $iId)
{ {
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
@@ -86,7 +86,6 @@ class PortalURLMaker implements iDBObjectURLMaker
} }
} }
/** /**
* Helper class to store and manipulate the parameters that make the application's context * Helper class to store and manipulate the parameters that make the application's context
* *
@@ -99,99 +98,90 @@ class PortalURLMaker implements iDBObjectURLMaker
*/ */
class ApplicationContext class ApplicationContext
{ {
public static $m_sUrlMakerClass = null; public static $m_sUrlMakerClass = null;
protected static $m_aPluginProperties = null; protected static $m_aPluginProperties = null;
protected static $aDefaultValues; // Cache shared among all instances protected static $aDefaultValues; // Cache shared among all instances
protected $aNames; protected $aNames;
protected $aValues; protected $aValues;
/** /**
* ApplicationContext constructor. * ApplicationContext constructor.
* *
* @param bool $bReadContext * @param bool $bReadContext
* *
* @throws \Exception * @throws \Exception
*/ */
public function __construct($bReadContext = true) public function __construct($bReadContext = true)
{ {
$this->aNames = array( $this->aNames = [
'org_id', 'menu' 'org_id', 'menu',
); ];
if ($bReadContext) if ($bReadContext) {
{ $this->ReadContext();
$this->ReadContext();
} }
} }
/** /**
* Read the context directly in the PHP parameters (either POST or GET) * Read the context directly in the PHP parameters (either POST or GET)
* return nothing * return nothing
* *
* @throws \Exception * @throws \Exception
*/ */
protected function ReadContext() protected function ReadContext()
{ {
if (!isset(self::$aDefaultValues)) if (!isset(self::$aDefaultValues)) {
{ self::$aDefaultValues = [];
self::$aDefaultValues = array(); $aContext = utils::ReadParam('c', [], false, 'context_param');
$aContext = utils::ReadParam('c', array(), false, 'context_param'); foreach ($this->aNames as $sName) {
foreach($this->aNames as $sName)
{
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : ''; $sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
// TO DO: check if some of the context parameters are mandatory (or have default values) // TO DO: check if some of the context parameters are mandatory (or have default values)
if (!empty($sValue)) if (!empty($sValue)) {
{
self::$aDefaultValues[$sName] = $sValue; self::$aDefaultValues[$sName] = $sValue;
} }
// Hmm, there must be a better (more generic) way to handle the case below: // Hmm, there must be a better (more generic) way to handle the case below:
// When there is only one possible (allowed) organization, the context must be // When there is only one possible (allowed) organization, the context must be
// fixed to this org unless there is only one organization in the system then // fixed to this org unless there is only one organization in the system then
// no filter is applied // no filter is applied
if ($sName == 'org_id') if ($sName == 'org_id') {
{ if (MetaModel::IsValidClass('Organization')) {
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization'); $oSearchFilter = new DBObjectSearch('Organization');
$oSet = new CMDBObjectSet($oSearchFilter); $oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2); $iCount = $oSet->CountWithLimit(2);
if ($iCount > 1) if ($iCount > 1) {
{
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter); $oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2); $iCount = $oSet->CountWithLimit(2);
if ($iCount == 1) if ($iCount == 1) {
{
// Only one possible value for org_id, set it in the context // Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch(); $oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey(); self::$aDefaultValues[$sName] = $oOrg->GetKey();
} }
} }
} }
} }
} }
} }
$this->aValues = self::$aDefaultValues; $this->aValues = self::$aDefaultValues;
} }
/** /**
* Returns the current value for the given parameter * Returns the current value for the given parameter
* *
* @param string $sParamName Name of the parameter to read * @param string $sParamName Name of the parameter to read
* @param string $defaultValue * @param string $defaultValue
* *
* @return mixed The value for this parameter * @return mixed The value for this parameter
*/ */
public function GetCurrentValue($sParamName, $defaultValue = '') public function GetCurrentValue($sParamName, $defaultValue = '')
{ {
if (isset($this->aValues[$sParamName])) if (isset($this->aValues[$sParamName])) {
{
return $this->aValues[$sParamName]; return $this->aValues[$sParamName];
} }
return $defaultValue; return $defaultValue;
} }
/** /**
* Returns the context as string with the format name1=value1&name2=value2.... * Returns the context as string with the format name1=value1&name2=value2....
* @return string The context as a string to be appended to an href property * @return string The context as a string to be appended to an href property
@@ -200,21 +190,20 @@ class ApplicationContext
public function GetForLink(bool $bWithLeadingAmpersand = false) public function GetForLink(bool $bWithLeadingAmpersand = false)
{ {
// If there are no parameters, return an empty string // If there are no parameters, return an empty string
if(empty($this->aValues)){ if (empty($this->aValues)) {
return ''; return '';
} }
// Build the query string with ampersand separated parameters // Build the query string with ampersand separated parameters
$aParams = array(); $aParams = [];
foreach($this->aValues as $sName => $sValue) foreach ($this->aValues as $sName => $sValue) {
{
$aParams[] = "c[$sName]".'='.urlencode($sValue); $aParams[] = "c[$sName]".'='.urlencode($sValue);
} }
$sReturnValue = implode('&', $aParams); $sReturnValue = implode('&', $aParams);
// add the leading ampersand if requested // add the leading ampersand if requested
if($bWithLeadingAmpersand){ if ($bWithLeadingAmpersand) {
$sReturnValue = '&' . $sReturnValue; $sReturnValue = '&'.$sReturnValue;
} }
return $sReturnValue; return $sReturnValue;
@@ -278,14 +267,13 @@ class ApplicationContext
*/ */
public function GetAsHash() public function GetAsHash()
{ {
$aReturn = array(); $aReturn = [];
foreach($this->aValues as $sName => $sValue) foreach ($this->aValues as $sName => $sValue) {
{
$aReturn["c[$sName]"] = $sValue; $aReturn["c[$sName]"] = $sValue;
} }
return $aReturn; return $aReturn;
} }
/** /**
* Returns an array of the context parameters NAMEs * Returns an array of the context parameters NAMEs
* @return array The list of context parameters * @return array The list of context parameters
@@ -298,11 +286,10 @@ class ApplicationContext
* Removes the specified parameter from the context, for example when the same parameter * Removes the specified parameter from the context, for example when the same parameter
* is already a search parameter * is already a search parameter
* @param string $sParamName Name of the parameter to remove * @param string $sParamName Name of the parameter to remove
*/ */
public function Reset($sParamName) public function Reset($sParamName)
{ {
if (isset($this->aValues[$sParamName])) if (isset($this->aValues[$sParamName])) {
{
unset($this->aValues[$sParamName]); unset($this->aValues[$sParamName]);
} }
} }
@@ -318,27 +305,22 @@ class ApplicationContext
public function InitObjectFromContext(DBObject &$oObj) public function InitObjectFromContext(DBObject &$oObj)
{ {
$sClass = get_class($oObj); $sClass = get_class($oObj);
foreach($this->GetNames() as $key) foreach ($this->GetNames() as $key) {
{ $aCallSpec = [$sClass, 'MapContextParam'];
$aCallSpec = array($sClass, 'MapContextParam'); if (is_callable($aCallSpec)) {
if (is_callable($aCallSpec)) $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) if (MetaModel::IsValidAttCode($sClass, $sAttCode)) {
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsWritable()) if ($oAttDef->IsWritable()) {
{
$value = $this->GetCurrentValue($key, null); $value = $this->GetCurrentValue($key, null);
if (!is_null($value)) if (!is_null($value)) {
{
$oObj->Set($sAttCode, $value); $oObj->Set($sAttCode, $value);
} }
} }
} }
} }
} }
} }
/** /**
@@ -362,14 +344,10 @@ class ApplicationContext
*/ */
public static function GetUrlMakerClass() public static function GetUrlMakerClass()
{ {
if (is_null(self::$m_sUrlMakerClass)) if (is_null(self::$m_sUrlMakerClass)) {
{ if (Session::IsSet('UrlMakerClass')) {
if (Session::IsSet('UrlMakerClass'))
{
self::$m_sUrlMakerClass = Session::Get('UrlMakerClass'); self::$m_sUrlMakerClass = Session::Get('UrlMakerClass');
} } else {
else
{
self::$m_sUrlMakerClass = 'iTopStandardURLMaker'; self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
} }
} }
@@ -387,23 +365,23 @@ class ApplicationContext
* @return string the name of the class * @return string the name of the class
* @throws \Exception * @throws \Exception
*/ */
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true) public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
{ {
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
if (is_null($sUrlMakerClass)) { if (is_null($sUrlMakerClass)) {
$sUrlMakerClass = self::GetUrlMakerClass(); $sUrlMakerClass = self::GetUrlMakerClass();
} }
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey); $sUrl = call_user_func([$sUrlMakerClass, 'MakeObjectUrl'], $sObjClass, $sObjKey);
if (utils::StrLen($sUrl) > 0) { if (utils::StrLen($sUrl) > 0) {
if ($bWithNavigationContext) { if ($bWithNavigationContext) {
return $sUrl.$oAppContext->GetForLink(true); return $sUrl.$oAppContext->GetForLink(true);
} else { } else {
return $sUrl; return $sUrl;
} }
} else { } else {
return ''; return '';
} }
} }
/** /**
@@ -412,13 +390,10 @@ class ApplicationContext
*/ */
protected static function LoadPluginProperties() protected static function LoadPluginProperties()
{ {
if (Session::IsSet('PluginProperties')) if (Session::IsSet('PluginProperties')) {
{
self::$m_aPluginProperties = Session::Get('PluginProperties'); self::$m_aPluginProperties = Session::Get('PluginProperties');
} } else {
else self::$m_aPluginProperties = [];
{
self::$m_aPluginProperties = array();
} }
} }
@@ -431,7 +406,9 @@ class ApplicationContext
*/ */
public static function SetPluginProperty($sPluginClass, $sProperty, $value) public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{ {
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties(); if (is_null(self::$m_aPluginProperties)) {
self::LoadPluginProperties();
}
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value; self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value); Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value);
@@ -444,15 +421,14 @@ class ApplicationContext
*/ */
public static function GetPluginProperties($sPluginClass) public static function GetPluginProperties($sPluginClass)
{ {
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties(); if (is_null(self::$m_aPluginProperties)) {
self::LoadPluginProperties();
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass];
} }
else
{ if (array_key_exists($sPluginClass, self::$m_aPluginProperties)) {
return array(); return self::$m_aPluginProperties[$sPluginClass];
} else {
return [];
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "categories". Each category defines a set of objects * This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects * to check and is linked to a set of rules that determine the valid or invalid objects
@@ -32,34 +32,36 @@ class AuditCategory extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => ['name'],
"db_table" => "priv_auditcategory", "db_table" => "priv_auditcategory",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", ["allowed_values" => null, "sql" => "definition_set", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL))); MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", ["linked_class" => "AuditRule", "ext_key_to_me" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL]));
MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", array("allowed_values"=>null, "sql"=>"ok_error_tolerance", "default_value"=>5, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", ["allowed_values" => null, "sql" => "ok_error_tolerance", "default_value" => 5, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", array("allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", ["allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("domains_list", MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property'))); "domains_list",
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "display_style" => 'property']
));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', ['name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list']); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', ['description', ]); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', ['description', 'definition_set']); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form
} }
/** /**
@@ -74,9 +76,9 @@ class AuditCategory extends cmdbAbstractObject
public function GetReportColor($iTotal, $iErrors) public function GetReportColor($iTotal, $iErrors)
{ {
$sResult = 'red'; $sResult = 'red';
if ( ($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100) ) { if (($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100)) {
$sResult = 'green'; $sResult = 'green';
} else if (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) { } elseif (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
$sResult = 'orange'; $sResult = 'orange';
} }
@@ -93,4 +95,3 @@ class AuditCategory extends cmdbAbstractObject
return $aShortcutActions; return $aShortcutActions;
} }
} }
?>

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "categories". Each category defines a set of objects * This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects * to check and is linked to a set of rules that determine the valid or invalid objects
@@ -33,32 +33,34 @@ class AuditDomain extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"complementary_name_attcode" => array('description'), "complementary_name_attcode" => ['description'],
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => ['name'],
"db_table" => "priv_auditdomain", "db_table" => "priv_auditdomain",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeImage("icon", array("is_null_allowed" => true, "depends_on" => array(), "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false))); MetaModel::Init_AddAttribute(new AttributeImage("icon", ["is_null_allowed" => true, "depends_on" => [], "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false]));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("categories_list", MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array()))); "categories_list",
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => []]
));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'icon', 'categories_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', ['name', 'description', 'icon', 'categories_list']); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description',)); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', ['description',]); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description')); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', ['description']); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form
} }
public static function GetShortcutActions($sFinalClass) public static function GetShortcutActions($sFinalClass)
@@ -84,40 +86,39 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
*/ */
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('category_id', 'domain_id'), "reconc_keys" => ['category_id', 'domain_id'],
"db_table" => "priv_link_audit_category_domain", "db_table" => "priv_link_audit_category_domain",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"is_link" => true, "is_link" => true,
'uniqueness_rules' => array( 'uniqueness_rules' => [
'no_duplicate' => array( 'no_duplicate' => [
'attributes' => array( 'attributes' => [
0 => 'category_id', 0 => 'category_id',
1 => 'domain_id', 1 => 'domain_id',
), ],
'filter' => '', 'filter' => '',
'disabled' => false, 'disabled' => false,
'is_blocking' => true, 'is_blocking' => true,
), ],
), ],
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"))); MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"]));
MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", array("targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", ["targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", array("allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name"))); MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", ["allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name"]));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('category_id', 'domain_id')); MetaModel::Init_SetZListItems('details', ['category_id', 'domain_id']);
MetaModel::Init_SetZListItems('list', array('category_id', 'domain_id')); MetaModel::Init_SetZListItems('list', ['category_id', 'domain_id']);
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'domain_id')); MetaModel::Init_SetZListItems('standard_search', ['category_id', 'domain_id']);
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "rule" linked to a given audit category. * This class manages the audit "rule" linked to a given audit category.
* Each rule is based on an OQL expression that returns either the "good" objects * Each rule is based on an OQL expression that returns either the "good" objects
@@ -33,35 +33,34 @@ class AuditRule extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => ['name'],
"db_table" => "priv_auditrule", "db_table" => "priv_auditrule",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeOQL("query", ["allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", ["allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"))); MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"]));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', ['category_id', 'name', 'description', 'query', 'valid_flag']); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', ['category_id', 'description', 'valid_flag']); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', ['category_id', 'name', 'description', 'valid_flag', 'query']); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form MetaModel::Init_SetZListItems('default_search', ['name', 'description', 'category_id']); // Criteria of the advanced search form
} }
public static function GetShortcutActions($sFinalClass) public static function GetShortcutActions($sFinalClass)
{ {
$aShortcutActions = parent::GetShortcutActions($sFinalClass); $aShortcutActions = parent::GetShortcutActions($sFinalClass);
@@ -72,4 +71,3 @@ class AuditRule extends cmdbAbstractObject
return $aShortcutActions; return $aShortcutActions;
} }
} }
?>

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -32,7 +33,8 @@ class CompileCSSService
{ {
} }
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){ public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = [])
{
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables); return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -38,21 +39,21 @@ abstract class DashboardLayout
* @since 2.7.0 * @since 2.7.0
*/ */
abstract public function GetDashletCoordinates($iCellIdx); abstract public function GetDashletCoordinates($iCellIdx);
public static function GetInfo() public static function GetInfo()
{ {
return array( return [
'label' => '', 'label' => '',
'icon' => '', 'icon' => '',
'description' => '', 'description' => '',
); ];
} }
} }
abstract class DashboardLayoutMultiCol extends DashboardLayout abstract class DashboardLayoutMultiCol extends DashboardLayout
{ {
protected $iNbCols; protected $iNbCols;
public function __construct() public function __construct()
{ {
$this->iNbCols = 1; $this->iNbCols = 1;
@@ -63,47 +64,38 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$aKeys = array_reverse(array_keys($aDashlets)); $aKeys = array_reverse(array_keys($aDashlets));
$idx = 0; $idx = 0;
$bNoVisibleFound = true; $bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound) while ($idx < count($aKeys) && $bNoVisibleFound) {
{
/** @var \Dashlet $oDashlet */ /** @var \Dashlet $oDashlet */
$oDashlet = $aDashlets[$aKeys[$idx]]; $oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet::IsVisible()) if ($oDashlet::IsVisible()) {
{
$bNoVisibleFound = false; $bNoVisibleFound = false;
} } else {
else
{
unset($aDashlets[$aKeys[$idx]]); unset($aDashlets[$aKeys[$idx]]);
} }
$idx++; $idx++;
} }
return $aDashlets; return $aDashlets;
} }
protected function TrimCellsArray($aCells) protected function TrimCellsArray($aCells)
{ {
foreach($aCells as $key => $aDashlets) foreach ($aCells as $key => $aDashlets) {
{
$aCells[$key] = $this->TrimCell($aDashlets); $aCells[$key] = $this->TrimCell($aDashlets);
} }
$aKeys = array_reverse(array_keys($aCells)); $aKeys = array_reverse(array_keys($aCells));
$idx = 0; $idx = 0;
$bNoVisibleFound = true; $bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound) while ($idx < count($aKeys) && $bNoVisibleFound) {
{
$aDashlets = $aCells[$aKeys[$idx]]; $aDashlets = $aCells[$aKeys[$idx]];
if (count($aDashlets) > 0) if (count($aDashlets) > 0) {
{
$bNoVisibleFound = false; $bNoVisibleFound = false;
} } else {
else
{
unset($aCells[$aKeys[$idx]]); unset($aCells[$aKeys[$idx]]);
} }
$idx++; $idx++;
} }
return $aCells; return $aCells;
} }
/** /**
@@ -112,7 +104,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
* @param bool $bEditMode * @param bool $bEditMode
* @param array $aExtraParams * @param array $aExtraParams
*/ */
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array()) public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = [])
{ {
// Trim the list of cells to remove the invisible/empty ones at the end of the array // Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells); $aCells = $this->TrimCellsArray($aCells);
@@ -157,8 +149,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}"); $oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
if ($bEditMode) // Add one row for extensibility if ($bEditMode) { // Add one row for extensibility
{
$oDashboardRow = new DashboardRow(); $oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow); $oDashboardLayout->AddDashboardRow($oDashboardRow);
@@ -180,7 +171,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$iColNumber = (int) $iCellIdx % $this->iNbCols; $iColNumber = (int) $iCellIdx % $this->iNbCols;
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols); $iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
return array($iColNumber, $iRowNumber); return [$iColNumber, $iRowNumber];
} }
} }
@@ -191,13 +182,13 @@ class DashboardLayoutOneCol extends DashboardLayoutMultiCol
parent::__construct(); parent::__construct();
$this->iNbCols = 1; $this->iNbCols = 1;
} }
static public function GetInfo() public static function GetInfo()
{ {
return array( return [
'label' => 'One Column', 'label' => 'One Column',
'icon' => 'images/layout_1col.png', 'icon' => 'images/layout_1col.png',
'description' => '', 'description' => '',
); ];
} }
} }
@@ -208,13 +199,13 @@ class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
parent::__construct(); parent::__construct();
$this->iNbCols = 2; $this->iNbCols = 2;
} }
static public function GetInfo() public static function GetInfo()
{ {
return array( return [
'label' => 'Two Columns', 'label' => 'Two Columns',
'icon' => 'images/layout_2col.png', 'icon' => 'images/layout_2col.png',
'description' => '', 'description' => '',
); ];
} }
} }
@@ -225,12 +216,12 @@ class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
parent::__construct(); parent::__construct();
$this->iNbCols = 3; $this->iNbCols = 3;
} }
static public function GetInfo() public static function GetInfo()
{ {
return array( return [
'label' => 'Two Columns', 'label' => 'Two Columns',
'icon' => 'images/layout_3col.png', 'icon' => 'images/layout_3col.png',
'description' => '', 'description' => '',
); ];
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class BulkChangeException extends CoreException class BulkChangeException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class CSVParserException extends CoreException class CSVParserException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class ConfigException extends CoreException class ConfigException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -63,21 +64,20 @@ class CoreCannotSaveObjectException extends CoreException
public function getTextMessage() public function getTextMessage()
{ {
$sTitle = Dict::S('UI:Error:SaveFailed'); $sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = $sTitle; $sContent = $sTitle;
if (count($this->aIssues) == 1) { if (count($this->aIssues) == 1) {
$sIssue = reset($this->aIssues); $sIssue = reset($this->aIssues);
$sContent .= $sIssue; $sContent .= $sIssue;
} else { } else {
foreach ($this->aIssues as $sError) { foreach ($this->aIssues as $sError) {
$sContent .= " " . $sError . ", "; $sContent .= " ".$sError.", ";
} }
} }
return $sContent; return $sContent;
} }
public function getIssues() public function getIssues()
{ {
return $this->aIssues; return $this->aIssues;

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -35,10 +36,10 @@ class CoreException extends Exception
} }
if (count($this->m_aContextData) > 0) { if (count($this->m_aContextData) > 0) {
$sMessage .= ": "; $sMessage .= ": ";
$aContextItems = array(); $aContextItems = [];
foreach ($this->m_aContextData as $sKey => $value) { foreach ($this->m_aContextData as $sKey => $value) {
if (is_array($value)) { if (is_array($value)) {
$aPairs = array(); $aPairs = [];
foreach ($value as $key => $val) { foreach ($value as $key => $val) {
if (is_array($val)) { if (is_array($val)) {
$aPairs[] = $key.'=>('.implode(', ', $val).')'; $aPairs[] = $key.'=>('.implode(', ', $val).')';
@@ -109,4 +110,4 @@ class CoreException extends Exception
{ {
return $this->m_aContextData; return $this->m_aContextData;
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,5 +10,4 @@
*/ */
class CorePortalInvalidActionRuleException extends CoreException class CorePortalInvalidActionRuleException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -14,4 +15,4 @@ class CoreTemplateException extends CoreException
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage(); $sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
parent::__construct($sMessage, null, '', $oTwigException); parent::__construct($sMessage, null, '', $oTwigException);
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class DeleteException extends CoreException class DeleteException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -12,13 +12,13 @@ class InvalidExternalKeyValueException extends CoreUnexpectedValue
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null) public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
{ {
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey(); $aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject).'::'.$oObject->GetKey();
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode; $aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode); $aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
$oCurrentUser = UserRights::GetUserObject(); $oCurrentUser = UserRights::GetUserObject();
if (false === is_null($oCurrentUser)) { if (false === is_null($oCurrentUser)) {
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey(); $aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser).'::'.$oCurrentUser->GetKey();
} }
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious); parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -11,4 +12,4 @@
*/ */
class InvalidPasswordAttributeOneWayPassword extends CoreException class InvalidPasswordAttributeOneWayPassword extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -10,4 +11,4 @@ use Exception;
class PageNotFoundException extends Exception class PageNotFoundException extends Exception
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class SynchroExceptionNotStarted extends CoreException class SynchroExceptionNotStarted extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class UserRightException extends CoreException class UserRightException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,4 +7,4 @@
class DictException extends CoreException class DictException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -8,9 +9,9 @@ class DictExceptionMissingString extends DictException
{ {
public function __construct($sLanguageCode, $sStringCode) public function __construct($sLanguageCode, $sStringCode)
{ {
$aContext = array(); $aContext = [];
$aContext['language_code'] = $sLanguageCode; $aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode; $aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext); parent::__construct('Missing localized string', $aContext);
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -8,8 +9,8 @@ class DictExceptionUnknownLanguage extends DictException
{ {
public function __construct($sLanguageCode) public function __construct($sLanguageCode)
{ {
$aContext = array(); $aContext = [];
$aContext['language_code'] = $sLanguageCode; $aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext); parent::__construct('Unknown localization language', $aContext);
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -6,5 +7,4 @@
class iTopXmlException extends CoreException class iTopXmlException extends CoreException
{ {
}
}

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -20,7 +21,7 @@ class MySQLException extends CoreException
$aContext['mysql_errno'] = $oException->getCode(); $aContext['mysql_errno'] = $oException->getCode();
$this->code = $oException->getCode(); $this->code = $oException->getCode();
$aContext['mysql_error'] = $oException->getMessage(); $aContext['mysql_error'] = $oException->getMessage();
} else if ($oMysqli != null) { } elseif ($oMysqli != null) {
$aContext['mysql_errno'] = $oMysqli->errno; $aContext['mysql_errno'] = $oMysqli->errno;
$this->code = $oMysqli->errno; $this->code = $oMysqli->errno;
$aContext['mysql_error'] = $oMysqli->error; $aContext['mysql_error'] = $oMysqli->error;
@@ -36,4 +37,4 @@ class MySQLException extends CoreException
error_reporting(0); error_reporting(0);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -19,14 +20,14 @@ class MySQLHasGoneAwayException extends MySQLException
*/ */
public static function getErrorCodes() public static function getErrorCodes()
{ {
return array( return [
2006, 2006,
2013, 2013,
); ];
} }
public function __construct($sIssue, $aContext) public function __construct($sIssue, $aContext)
{ {
parent::__construct($sIssue, $aContext, null); parent::__construct($sIssue, $aContext, null);
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,5 +10,4 @@
*/ */
class MySQLNoTransactionException extends MySQLException class MySQLNoTransactionException extends MySQLException
{ {
}
}

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -11,5 +12,4 @@
*/ */
class MySQLQueryHasNoResultException extends MySQLException class MySQLQueryHasNoResultException extends MySQLException
{ {
}
}

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,5 +10,4 @@
*/ */
class MySQLTransactionNotClosedException extends MySQLException class MySQLTransactionNotClosedException extends MySQLException
{ {
}
}

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -12,4 +13,4 @@
*/ */
class ProcessException extends CoreException class ProcessException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -13,4 +14,4 @@
*/ */
class ProcessFatalException extends CoreException class ProcessFatalException extends CoreException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,4 +10,4 @@
*/ */
class ProcessInvalidConfigException extends ProcessException class ProcessInvalidConfigException extends ProcessException
{ {
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -22,8 +23,8 @@
* @author Olivier DAIN <olivier.dain@combodo.com> * @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°3588 * @since 3.0.0 N°3588
*/ */
class FindStylesheetObject{ class FindStylesheetObject
{
//file URIs //file URIs
private $aStylesheetFileURIs; private $aStylesheetFileURIs;
@@ -64,7 +65,7 @@ class FindStylesheetObject{
return $this->aStylesheetFileURIs; return $this->aStylesheetFileURIs;
} }
public function GetLastModified() : int public function GetLastModified(): int
{ {
return $this->iLastModified; return $this->iLastModified;
} }
@@ -92,7 +93,8 @@ class FindStylesheetObject{
$this->sLastStyleSheetPath = $sStylesheetFilePath; $this->sLastStyleSheetPath = $sStylesheetFilePath;
} }
public function AlreadyFetched(string $sStylesheetFilePath) : bool { public function AlreadyFetched(string $sStylesheetFilePath): bool
{
return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths); return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths);
} }
@@ -111,4 +113,4 @@ class FindStylesheetObject{
{ {
$this->sLastStyleSheetPath = ""; $this->sLastStyleSheetPath = "";
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -18,23 +18,17 @@ class LoginBasic extends AbstractLoginFSMExtension
*/ */
public function ListSupportedLoginModes() public function ListSupportedLoginModes()
{ {
return array('basic'); return ['basic'];
} }
protected function OnModeDetection(&$iErrorCode) protected function OnModeDetection(&$iErrorCode)
{ {
if (!Session::IsSet('login_mode')) if (!Session::IsSet('login_mode')) {
{ if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
{
Session::Set('login_mode', 'basic'); Session::Set('login_mode', 'basic');
} } elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
Session::Set('login_mode', 'basic'); Session::Set('login_mode', 'basic');
} } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
elseif (isset($_SERVER['PHP_AUTH_USER']))
{
Session::Set('login_mode', 'basic'); Session::Set('login_mode', 'basic');
} }
} }
@@ -43,22 +37,18 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnReadCredentials(&$iErrorCode) protected function OnReadCredentials(&$iErrorCode)
{ {
if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'basic') if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'basic') {
{
list($sAuthUser) = $this->GetAuthUserAndPassword(); list($sAuthUser) = $this->GetAuthUserAndPassword();
Session::Set('login_temp_auth_user', $sAuthUser); Session::Set('login_temp_auth_user', $sAuthUser);
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
} }
protected function OnCheckCredentials(&$iErrorCode) protected function OnCheckCredentials(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'basic') if (Session::Get('login_mode') == 'basic') {
{
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword(); list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) {
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS; $iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR; return LoginWebPage::LOGIN_FSM_ERROR;
} }
@@ -69,8 +59,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnCredentialsOK(&$iErrorCode) protected function OnCredentialsOK(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'basic') if (Session::Get('login_mode') == 'basic') {
{
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode')); LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -78,13 +67,11 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode) protected function OnError(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'basic') if (Session::Get('login_mode') == 'basic') {
{ $iOnExit = LoginWebPage::getIOnExit();
$iOnExit = LoginWebPage::getIOnExit(); if ($iOnExit === LoginWebPage::EXIT_RETURN) {
if ($iOnExit === LoginWebPage::EXIT_RETURN) return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
{ }
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
LoginWebPage::HTTP401Error(); LoginWebPage::HTTP401Error();
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -92,8 +79,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode) protected function OnConnected(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'basic') if (Session::Get('login_mode') == 'basic') {
{
Session::Set('can_logoff', true); Session::Set('can_logoff', true);
return LoginWebPage::CheckLoggedUser($iErrorCode); return LoginWebPage::CheckLoggedUser($iErrorCode);
} }
@@ -105,42 +91,33 @@ class LoginBasic extends AbstractLoginFSMExtension
$sAuthUser = ''; $sAuthUser = '';
$sAuthPwd = null; $sAuthPwd = null;
$sAuthorization = ''; $sAuthorization = '';
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
{
$sAuthorization = $_SERVER['HTTP_AUTHORIZATION']; $sAuthorization = $_SERVER['HTTP_AUTHORIZATION'];
} } elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
$sAuthorization = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; $sAuthorization = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
} }
if (!empty($sAuthorization)) if (!empty($sAuthorization)) {
{
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($sAuthorization, 6))); list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($sAuthorization, 6)));
} } else {
else if (isset($_SERVER['PHP_AUTH_USER'])) {
{
if (isset($_SERVER['PHP_AUTH_USER']))
{
$sAuthUser = $_SERVER['PHP_AUTH_USER']; $sAuthUser = $_SERVER['PHP_AUTH_USER'];
// Unfortunately, the RFC is not clear about the encoding... // Unfortunately, the RFC is not clear about the encoding...
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8 // IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base // So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
if (!LoginWebPage::LooksLikeUTF8($sAuthUser)) if (!LoginWebPage::LooksLikeUTF8($sAuthUser)) {
{
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8 // Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string... // Supposed to be harmless in case of a plain ASCII string...
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser); $sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
} }
$sAuthPwd = $_SERVER['PHP_AUTH_PW']; $sAuthPwd = $_SERVER['PHP_AUTH_PW'];
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd)) if (!LoginWebPage::LooksLikeUTF8($sAuthPwd)) {
{
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8 // Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string... // Supposed to be harmless in case of a plain ASCII string...
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd); $sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
} }
} }
} }
return array($sAuthUser, $sAuthPwd); return [$sAuthUser, $sAuthPwd];
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -18,7 +19,7 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
*/ */
public function ListSupportedLoginModes() public function ListSupportedLoginModes()
{ {
return array('before'); return ['before'];
} }
protected function OnStart(&$iErrorCode) protected function OnStart(&$iErrorCode)
@@ -31,13 +32,10 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes(); $aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
$sProposedLoginMode = utils::ReadParam('login_mode', ''); $sProposedLoginMode = utils::ReadParam('login_mode', '');
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes); $index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
if ($index !== false) if ($index !== false) {
{
// Force login mode // Force login mode
Session::Set('login_mode', $sProposedLoginMode); Session::Set('login_mode', $sProposedLoginMode);
} } else {
else
{
Session::Unset('login_mode'); Session::Unset('login_mode');
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -49,8 +47,7 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes(); $aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
$sProposedLoginMode = utils::ReadParam('login_mode', ''); $sProposedLoginMode = utils::ReadParam('login_mode', '');
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes); $index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
if ($index !== false) if ($index !== false) {
{
// Force login mode // Force login mode
LoginWebPage::SetLoginModeAndReload($sProposedLoginMode); LoginWebPage::SetLoginModeAndReload($sProposedLoginMode);
} else { } else {
@@ -69,8 +66,6 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
*/ */
class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExtension class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExtension
{ {
/** /**
* Must be executed after the other login plugins * Must be executed after the other login plugins
* *
@@ -78,19 +73,16 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
*/ */
public function ListSupportedLoginModes() public function ListSupportedLoginModes()
{ {
return array('after'); return ['after'];
} }
protected function OnError(&$iErrorCode) protected function OnError(&$iErrorCode)
{ {
self::ResetLoginSession(); self::ResetLoginSession();
$iOnExit = LoginWebPage::getIOnExit(); $iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit === LoginWebPage::EXIT_RETURN) if ($iOnExit === LoginWebPage::EXIT_RETURN) {
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
} } elseif ($iOnExit == LoginWebPage::EXIT_HTTP_401) {
elseif ($iOnExit == LoginWebPage::EXIT_HTTP_401)
{
LoginWebPage::HTTP401Error(); // Error, exit LoginWebPage::HTTP401Error(); // Error, exit
} }
// LoginWebPage::EXIT_PROMPT // LoginWebPage::EXIT_PROMPT
@@ -99,13 +91,12 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnCredentialsOk(&$iErrorCode) protected function OnCredentialsOk(&$iErrorCode)
{ {
if (!Session::IsSet('login_mode')) if (!Session::IsSet('login_mode')) {
{ // N°6358 - if EXIT_RETURN was asked, send an error
// N°6358 - if EXIT_RETURN was asked, send an error if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) { $iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS; return LoginWebPage::LOGIN_FSM_ERROR;
return LoginWebPage::LOGIN_FSM_ERROR; }
}
// If no plugin validated the user, exit // If no plugin validated the user, exit
self::ResetLoginSession(); self::ResetLoginSession();
@@ -125,7 +116,7 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnConnected(&$iErrorCode) protected function OnConnected(&$iErrorCode)
{ {
Session::Unset('login_temp_auth_user'); Session::Unset('login_temp_auth_user');
if (is_null(UserRights::GetUserObject())){ if (is_null(UserRights::GetUserObject())) {
//N°7085 avoid infinite loop //N°7085 avoid infinite loop
IssueLog::Error("No user logged in. exit"); IssueLog::Error("No user logged in. exit");
exit(-1); exit(-1);
@@ -137,10 +128,8 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
private static function ResetLoginSession() private static function ResetLoginSession()
{ {
LoginWebPage::ResetSession(); LoginWebPage::ResetSession();
foreach (Session::ListVariables() as $sKey) foreach (Session::ListVariables() as $sKey) {
{ if (utils::StartsWith($sKey, 'login_')) {
if (utils::StartsWith($sKey, 'login_'))
{
Session::Unset($sKey); Session::Unset($sKey);
} }
} }

View File

@@ -11,7 +11,6 @@ use Combodo\iTop\Application\Helper\Session;
class LoginExternal extends AbstractLoginFSMExtension class LoginExternal extends AbstractLoginFSMExtension
{ {
/** /**
* Return the list of supported login modes for this plugin * Return the list of supported login modes for this plugin
* *
@@ -19,16 +18,14 @@ class LoginExternal extends AbstractLoginFSMExtension
*/ */
public function ListSupportedLoginModes() public function ListSupportedLoginModes()
{ {
return array('external'); return ['external'];
} }
protected function OnModeDetection(&$iErrorCode) protected function OnModeDetection(&$iErrorCode)
{ {
if (!Session::IsSet('login_mode')) if (!Session::IsSet('login_mode')) {
{
$sAuthUser = $this->GetAuthUser(); $sAuthUser = $this->GetAuthUser();
if ($sAuthUser && (strlen($sAuthUser) > 0)) if ($sAuthUser && (strlen($sAuthUser) > 0)) {
{
Session::Set('login_mode', 'external'); Session::Set('login_mode', 'external');
} }
} }
@@ -37,11 +34,9 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode) protected function OnCheckCredentials(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'external') if (Session::Get('login_mode') == 'external') {
{
$sAuthUser = $this->GetAuthUser(); $sAuthUser = $this->GetAuthUser();
if (!UserRights::CheckCredentials($sAuthUser, '', Session::Get('login_mode'), 'external')) if (!UserRights::CheckCredentials($sAuthUser, '', Session::Get('login_mode'), 'external')) {
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS; $iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR; return LoginWebPage::LOGIN_FSM_ERROR;
} }
@@ -52,8 +47,7 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnCredentialsOK(&$iErrorCode) protected function OnCredentialsOK(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'external') if (Session::Get('login_mode') == 'external') {
{
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'external', Session::Get('login_mode')); LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'external', Session::Get('login_mode'));
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -61,8 +55,7 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode) protected function OnConnected(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'external') if (Session::Get('login_mode') == 'external') {
{
Session::Set('can_logoff', false); Session::Set('can_logoff', false);
return LoginWebPage::CheckLoggedUser($iErrorCode); return LoginWebPage::CheckLoggedUser($iErrorCode);
} }
@@ -71,13 +64,11 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode) protected function OnError(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'external') if (Session::Get('login_mode') == 'external') {
{ $iOnExit = LoginWebPage::getIOnExit();
$iOnExit = LoginWebPage::getIOnExit(); if ($iOnExit === LoginWebPage::EXIT_RETURN) {
if ($iOnExit === LoginWebPage::EXIT_RETURN) return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
{ }
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
LoginWebPage::HTTP401Error(); LoginWebPage::HTTP401Error();
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;

View File

@@ -23,7 +23,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/ */
public function ListSupportedLoginModes() public function ListSupportedLoginModes()
{ {
return array('form'); return ['form'];
} }
/** /**
@@ -34,19 +34,17 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'form') { if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'form') {
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data'); $sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data'); $sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
if ($this->bForceFormOnError || empty($sAuthUser) || empty($sAuthPwd)) if ($this->bForceFormOnError || empty($sAuthUser) || empty($sAuthPwd)) {
{ if (array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER)) {
if (array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER))
{
// X-Combodo-Ajax is a special header automatically added to all ajax requests // X-Combodo-Ajax is a special header automatically added to all ajax requests
// Let's reply that we're currently logged-out // Let's reply that we're currently logged-out
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
exit; exit;
} }
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) { if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
} }
// No credentials yet, display the form // No credentials yet, display the form
$oPage = LoginWebPage::NewLoginWebPage(); $oPage = LoginWebPage::NewLoginWebPage();
@@ -66,12 +64,10 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/ */
protected function OnCheckCredentials(&$iErrorCode) protected function OnCheckCredentials(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'form') if (Session::Get('login_mode') == 'form') {
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data'); $sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data'); $sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) {
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS; $iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR; return LoginWebPage::LOGIN_FSM_ERROR;
} }
@@ -85,8 +81,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/ */
protected function OnCredentialsOK(&$iErrorCode) protected function OnCredentialsOK(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'form') if (Session::Get('login_mode') == 'form') {
{
// Store 'auth_user' in session for further use // Store 'auth_user' in session for further use
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode')); LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
} }
@@ -98,8 +93,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/ */
protected function OnError(&$iErrorCode) protected function OnError(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'form') if (Session::Get('login_mode') == 'form') {
{
$this->bForceFormOnError = true; $this->bForceFormOnError = true;
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -110,8 +104,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/ */
protected function OnConnected(&$iErrorCode) protected function OnConnected(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'form') if (Session::Get('login_mode') == 'form') {
{
Session::Set('can_logoff', true); Session::Set('can_logoff', true);
return LoginWebPage::CheckLoggedUser($iErrorCode); return LoginWebPage::CheckLoggedUser($iErrorCode);
} }
@@ -131,24 +124,23 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data'); $sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data'); $sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
$aData = array( $aData = [
'sAuthUser' => $sAuthUser, 'sAuthUser' => $sAuthUser,
'sAuthPwd' => $sAuthPwd, 'sAuthPwd' => $sAuthPwd,
); ];
$oLoginContext->AddBlockExtension('login_input', new LoginBlockExtension('extensionblock/loginforminput.html.twig', $aData)); $oLoginContext->AddBlockExtension('login_input', new LoginBlockExtension('extensionblock/loginforminput.html.twig', $aData));
$oLoginContext->AddBlockExtension('login_submit', new LoginBlockExtension('extensionblock/loginformsubmit.html.twig')); $oLoginContext->AddBlockExtension('login_submit', new LoginBlockExtension('extensionblock/loginformsubmit.html.twig'));
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig')); $oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
$bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password'); $bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password');
$sResetPasswordUrl = MetaModel::GetConfig()->Get('forgot_password.url'); $sResetPasswordUrl = MetaModel::GetConfig()->Get('forgot_password.url');
if ($sResetPasswordUrl == '') if ($sResetPasswordUrl == '') {
{ $sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=forgot_pwd';
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
} }
$aData = array( $aData = [
'bEnableResetPassword' => $bEnableResetPassword, 'bEnableResetPassword' => $bEnableResetPassword,
'sResetPasswordUrl' => $sResetPasswordUrl, 'sResetPasswordUrl' => $sResetPasswordUrl,
); ];
$oLoginContext->AddBlockExtension('login_links', new LoginBlockExtension('extensionblock/loginformlinks.html.twig', $aData)); $oLoginContext->AddBlockExtension('login_links', new LoginBlockExtension('extensionblock/loginformlinks.html.twig', $aData));
return $oLoginContext; return $oLoginContext;

View File

@@ -6,7 +6,6 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
use Combodo\iTop\Application\Branding; use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\TwigBase\Twig\Extension; use Combodo\iTop\Application\TwigBase\Twig\Extension;
use Combodo\iTop\Application\WebPage\NiceWebPage; use Combodo\iTop\Application\WebPage\NiceWebPage;
@@ -41,11 +40,11 @@ class LoginTwigContext
*/ */
public function __construct() public function __construct()
{ {
$this->aBlockExtension = array(); $this->aBlockExtension = [];
$this->aPostedVars = array(); $this->aPostedVars = [];
$this->sTwigLoaderPath = null; $this->sTwigLoaderPath = null;
$this->aCSSFiles = array(); $this->aCSSFiles = [];
$this->aJsFiles = array(); $this->aJsFiles = [];
$this->sTwigNameSpace = null; $this->sTwigNameSpace = null;
} }
@@ -179,7 +178,7 @@ class LoginBlockExtension
* @param array $aData Data given to the twig template (into the variable {{ aData }}) * @param array $aData Data given to the twig template (into the variable {{ aData }})
* @api * @api
*/ */
public function __construct($sTwig, $aData = array()) public function __construct($sTwig, $aData = [])
{ {
$this->sTwig = $sTwig; $this->sTwig = $sTwig;
$this->aData = $aData; $this->aData = $aData;
@@ -210,21 +209,18 @@ class LoginTwigRenderer
public function __construct() public function __construct()
{ {
$this->aLoginPluginList = LoginWebPage::GetLoginPluginList('iLoginUIExtension', false); $this->aLoginPluginList = LoginWebPage::GetLoginPluginList('iLoginUIExtension', false);
$this->aPluginFormData = array(); $this->aPluginFormData = [];
$aTwigLoaders = array(); $aTwigLoaders = [];
$this->aPostedVars = array(); $this->aPostedVars = [];
foreach ($this->aLoginPluginList as $oLoginPlugin) foreach ($this->aLoginPluginList as $oLoginPlugin) {
{
/** @var \iLoginUIExtension $oLoginPlugin */ /** @var \iLoginUIExtension $oLoginPlugin */
$oLoginContext = $oLoginPlugin->GetTwigContext(); $oLoginContext = $oLoginPlugin->GetTwigContext();
if (is_null($oLoginContext)) if (is_null($oLoginContext)) {
{
continue; continue;
} }
$this->aPluginFormData[] = $oLoginContext; $this->aPluginFormData[] = $oLoginContext;
$sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath(); $sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath();
if ($sTwigLoaderPath != null) if ($sTwigLoaderPath != null) {
{
$oExtensionLoader = new FilesystemLoader(); $oExtensionLoader = new FilesystemLoader();
$oExtensionLoader->setPaths($sTwigLoaderPath); $oExtensionLoader->setPaths($sTwigLoaderPath);
$aTwigLoaders[] = $oExtensionLoader; $aTwigLoaders[] = $oExtensionLoader;
@@ -232,8 +228,8 @@ class LoginTwigRenderer
$this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars()); $this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars());
} }
$oCoreLoader = new FilesystemLoader(array(), APPROOT.'templates'); $oCoreLoader = new FilesystemLoader([], APPROOT.'templates');
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password'); $aCoreTemplatesPaths = ['pages/login', 'pages/login/password'];
// Having this path declared after the plugins let the plugins replace the core templates // Having this path declared after the plugins let the plugins replace the core templates
$oCoreLoader->setPaths($aCoreTemplatesPaths); $oCoreLoader->setPaths($aCoreTemplatesPaths);
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them // Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them
@@ -251,19 +247,19 @@ class LoginTwigRenderer
$sIconUrl = Utils::GetConfig()->Get('app_icon_url'); $sIconUrl = Utils::GetConfig()->Get('app_icon_url');
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl(); $sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
$aVars = array( $aVars = [
'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(), 'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(),
'aPluginFormData' => $this->GetPluginFormData(), 'aPluginFormData' => $this->GetPluginFormData(),
'sItopVersion' => ITOP_VERSION, 'sItopVersion' => ITOP_VERSION,
'sVersionShort' => $sVersionShort, 'sVersionShort' => $sVersionShort,
'sIconUrl' => $sIconUrl, 'sIconUrl' => $sIconUrl,
'sDisplayIcon' => $sDisplayIcon, 'sDisplayIcon' => $sDisplayIcon,
); ];
return $aVars; return $aVars;
} }
public function Render(NiceWebPage $oPage, $sTwigFile, $aVars = array()) public function Render(NiceWebPage $oPage, $sTwigFile, $aVars = [])
{ {
$oTemplate = $this->GetTwig()->load($sTwigFile); $oTemplate = $this->GetTwig()->load($sTwigFile);
$oPage->add($oTemplate->renderBlock('body', $aVars)); $oPage->add($oTemplate->renderBlock('body', $aVars));
@@ -272,17 +268,14 @@ class LoginTwigRenderer
$oPage->add_style($oTemplate->renderBlock('css', $aVars)); $oPage->add_style($oTemplate->renderBlock('css', $aVars));
// Render CSS links // Render CSS links
foreach ($this->aPluginFormData as $oFormData) foreach ($this->aPluginFormData as $oFormData) {
{
/** @var \LoginTwigContext $oFormData */ /** @var \LoginTwigContext $oFormData */
$aCSSFiles = $oFormData->GetCSSFiles(); $aCSSFiles = $oFormData->GetCSSFiles();
foreach ($aCSSFiles as $sCSSFile) foreach ($aCSSFiles as $sCSSFile) {
{
$oPage->LinkStylesheetFromURI($sCSSFile); $oPage->LinkStylesheetFromURI($sCSSFile);
} }
$aJsFiles = $oFormData->GetJsFiles(); $aJsFiles = $oFormData->GetJsFiles();
foreach ($aJsFiles as $sJsFile) foreach ($aJsFiles as $sJsFile) {
{
$oPage->LinkScriptFromURI($sJsFile); $oPage->LinkScriptFromURI($sJsFile);
} }

View File

@@ -23,17 +23,15 @@ class LoginURL extends AbstractLoginFSMExtension
*/ */
public function ListSupportedLoginModes() public function ListSupportedLoginModes()
{ {
return array('url'); return ['url'];
} }
protected function OnModeDetection(&$iErrorCode) protected function OnModeDetection(&$iErrorCode)
{ {
if (!Session::IsSet('login_mode') && !$this->bErrorOccurred) if (!Session::IsSet('login_mode') && !$this->bErrorOccurred) {
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data'); $sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data'); $sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (!empty($sAuthUser) && !empty($sAuthPwd)) if (!empty($sAuthUser) && !empty($sAuthPwd)) {
{
Session::Set('login_mode', 'url'); Session::Set('login_mode', 'url');
} }
} }
@@ -42,8 +40,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnReadCredentials(&$iErrorCode) protected function OnReadCredentials(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'url') if (Session::Get('login_mode') == 'url') {
{
Session::Set('login_temp_auth_user', utils::ReadParam('auth_user', '', false, 'raw_data')); Session::Set('login_temp_auth_user', utils::ReadParam('auth_user', '', false, 'raw_data'));
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -51,12 +48,10 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode) protected function OnCheckCredentials(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'url') if (Session::Get('login_mode') == 'url') {
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data'); $sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data'); $sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) {
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS; $iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR; return LoginWebPage::LOGIN_FSM_ERROR;
} }
@@ -67,8 +62,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnCredentialsOK(&$iErrorCode) protected function OnCredentialsOK(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'url') if (Session::Get('login_mode') == 'url') {
{
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode')); LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -76,8 +70,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode) protected function OnError(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'url') if (Session::Get('login_mode') == 'url') {
{
$this->bErrorOccurred = true; $this->bErrorOccurred = true;
} }
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -85,8 +78,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode) protected function OnConnected(&$iErrorCode)
{ {
if (Session::Get('login_mode') == 'url') if (Session::Get('login_mode') == 'url') {
{
Session::Set('can_logoff', true); Session::Set('can_logoff', true);
return LoginWebPage::CheckLoggedUser($iErrorCode); return LoginWebPage::CheckLoggedUser($iErrorCode);
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Class LoginWebPage * Class LoginWebPage
* *
@@ -37,33 +37,33 @@ use Combodo\iTop\Service\Events\EventService;
class LoginWebPage extends NiceWebPage class LoginWebPage extends NiceWebPage
{ {
const EXIT_PROMPT = 0; public const EXIT_PROMPT = 0;
const EXIT_HTTP_401 = 1; public const EXIT_HTTP_401 = 1;
const EXIT_RETURN = 2; public const EXIT_RETURN = 2;
const EXIT_CODE_OK = 0; public const EXIT_CODE_OK = 0;
const EXIT_CODE_MISSINGLOGIN = 1; public const EXIT_CODE_MISSINGLOGIN = 1;
const EXIT_CODE_MISSINGPASSWORD = 2; public const EXIT_CODE_MISSINGPASSWORD = 2;
const EXIT_CODE_WRONGCREDENTIALS = 3; public const EXIT_CODE_WRONGCREDENTIALS = 3;
const EXIT_CODE_MUSTBEADMIN = 4; public const EXIT_CODE_MUSTBEADMIN = 4;
const EXIT_CODE_PORTALUSERNOTAUTHORIZED = 5; public const EXIT_CODE_PORTALUSERNOTAUTHORIZED = 5;
const EXIT_CODE_NOTAUTHORIZED = 6; public const EXIT_CODE_NOTAUTHORIZED = 6;
// Login FSM States // Login FSM States
const LOGIN_STATE_START = 'start'; // Entry state public const LOGIN_STATE_START = 'start'; // Entry state
const LOGIN_STATE_MODE_DETECTION = 'login mode detection'; // Detect which login plugin to use public const LOGIN_STATE_MODE_DETECTION = 'login mode detection'; // Detect which login plugin to use
const LOGIN_STATE_READ_CREDENTIALS = 'read credentials'; // Read the credentials public const LOGIN_STATE_READ_CREDENTIALS = 'read credentials'; // Read the credentials
const LOGIN_STATE_CHECK_CREDENTIALS = 'check credentials'; // Check if the credentials are valid public const LOGIN_STATE_CHECK_CREDENTIALS = 'check credentials'; // Check if the credentials are valid
const LOGIN_STATE_CREDENTIALS_OK = 'credentials ok'; // User provisioning public const LOGIN_STATE_CREDENTIALS_OK = 'credentials ok'; // User provisioning
const LOGIN_STATE_USER_OK = 'user ok'; // Additional check (2FA) public const LOGIN_STATE_USER_OK = 'user ok'; // Additional check (2FA)
const LOGIN_STATE_CONNECTED = 'connected'; // User connected public const LOGIN_STATE_CONNECTED = 'connected'; // User connected
const LOGIN_STATE_SET_ERROR = 'prepare for error'; // Internal state to trigger ERROR state public const LOGIN_STATE_SET_ERROR = 'prepare for error'; // Internal state to trigger ERROR state
const LOGIN_STATE_ERROR = 'error'; // An error occurred, next state will be NONE public const LOGIN_STATE_ERROR = 'error'; // An error occurred, next state will be NONE
// Login FSM Returns // Login FSM Returns
const LOGIN_FSM_RETURN = 0; // End the FSM OK (connected) public const LOGIN_FSM_RETURN = 0; // End the FSM OK (connected)
const LOGIN_FSM_ERROR = 1; // Error signaled public const LOGIN_FSM_ERROR = 1; // Error signaled
const LOGIN_FSM_CONTINUE = 2; // Continue FSM public const LOGIN_FSM_CONTINUE = 2; // Continue FSM
protected static $sHandlerClass = __class__; protected static $sHandlerClass = __class__;
private static $iOnExit; private static $iOnExit;
@@ -78,7 +78,7 @@ class LoginWebPage extends NiceWebPage
*/ */
public static function NewLoginWebPage() public static function NewLoginWebPage()
{ {
return new self::$sHandlerClass; return new self::$sHandlerClass();
} }
protected static $m_sLoginFailedMessage = ''; protected static $m_sLoginFailedMessage = '';
@@ -94,7 +94,7 @@ class LoginWebPage extends NiceWebPage
$this->no_cache(); $this->no_cache();
$this->add_http_headers(); $this->add_http_headers();
} }
public function SetStyleSheet() public function SetStyleSheet()
{ {
$this->LinkStylesheetFromAppRoot('css/login.css'); $this->LinkStylesheetFromAppRoot('css/login.css');
@@ -128,23 +128,18 @@ class LoginWebPage extends NiceWebPage
$oProfilesSet = $oUser->Get('profile_list'); $oProfilesSet = $oUser->Get('profile_list');
//delete old profiles //delete old profiles
$aExistingProfiles = []; $aExistingProfiles = [];
while ($oProfile = $oProfilesSet->Fetch()) while ($oProfile = $oProfilesSet->Fetch()) {
{
array_push($aExistingProfiles, $oProfile->Get('profileid')); array_push($aExistingProfiles, $oProfile->Get('profileid'));
$iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles); $iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles);
if (!$iArrayKey) if (!$iArrayKey) {
{
$oProfilesSet->RemoveItem($oProfile->Get('profileid')); $oProfilesSet->RemoveItem($oProfile->Get('profileid'));
} } else {
else
{
unset($aProfiles[$iArrayKey]); unset($aProfiles[$iArrayKey]);
} }
} }
//add profiles not already linked with user //add profiles not already linked with user
foreach ($aProfiles as $iProfileId) foreach ($aProfiles as $iProfileId) {
{ $oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => $iProfileId, 'reason' => $sOrigin]));
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
} }
$oUser->Set('profile_list', $oProfilesSet); $oUser->Set('profile_list', $oProfilesSet);
} }
@@ -154,56 +149,49 @@ class LoginWebPage extends NiceWebPage
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION); $sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
$sIconUrl = Utils::GetConfig()->Get('app_icon_url'); $sIconUrl = Utils::GetConfig()->Get('app_icon_url');
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl(); $sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES, $this->add("<div id=\"login-logo\"><a href=\"".htmlentities(
self::PAGES_CHARSET)."\"><img title=\"$sVersionShort\" src=\"$sDisplayIcon\"></a></div>\n"); $sIconUrl,
ENT_QUOTES,
self::PAGES_CHARSET
)."\"><img title=\"$sVersionShort\" src=\"$sDisplayIcon\"></a></div>\n");
} }
public function DisplayLoginForm($bFailedLogin = false) public function DisplayLoginForm($bFailedLogin = false)
{ {
$oTwigContext = new LoginTwigRenderer(); $oTwigContext = new LoginTwigRenderer();
$aPostedVars = array_merge(array('login_mode', 'loginop'), $oTwigContext->GetPostedVars()); $aPostedVars = array_merge(['login_mode', 'loginop'], $oTwigContext->GetPostedVars());
$sMessage = Dict::S('UI:Login:IdentifyYourself'); $sMessage = Dict::S('UI:Login:IdentifyYourself');
// Error message // Error message
if ($bFailedLogin) if ($bFailedLogin) {
{ if (self::$m_sLoginFailedMessage != '') {
if (self::$m_sLoginFailedMessage != '')
{
$sMessage = self::$m_sLoginFailedMessage; $sMessage = self::$m_sLoginFailedMessage;
} } else {
else
{
$sMessage = Dict::S('UI:Login:IncorrectLoginPassword'); $sMessage = Dict::S('UI:Login:IncorrectLoginPassword');
} }
} }
// Keep the OTHER parameters posted // Keep the OTHER parameters posted
$aPreviousPostedVars = array(); $aPreviousPostedVars = [];
foreach($_POST as $sPostedKey => $postedValue) foreach ($_POST as $sPostedKey => $postedValue) {
{ if (!in_array($sPostedKey, $aPostedVars)) {
if (!in_array($sPostedKey, $aPostedVars)) if (is_array($postedValue)) {
{ foreach ($postedValue as $sKey => $sValue) {
if (is_array($postedValue))
{
foreach($postedValue as $sKey => $sValue)
{
$sName = "{$sPostedKey}[{$sKey}]"; $sName = "{$sPostedKey}[{$sKey}]";
$aPreviousPostedVars[$sName] = $sValue; $aPreviousPostedVars[$sName] = $sValue;
} }
} } else {
else
{
$aPreviousPostedVars[$sPostedKey] = $postedValue; $aPreviousPostedVars[$sPostedKey] = $postedValue;
} }
} }
} }
$aVars = array( $aVars = [
'bFailedLogin' => $bFailedLogin, 'bFailedLogin' => $bFailedLogin,
'sMessage' => $sMessage, 'sMessage' => $sMessage,
'aPreviousPostedVars' => $aPreviousPostedVars, 'aPreviousPostedVars' => $aPreviousPostedVars,
); ];
$aVars = array_merge($aVars, $oTwigContext->GetDefaultVars()); $aVars = array_merge($aVars, $oTwigContext->GetDefaultVars());
$oTwigContext->Render($this, 'login.html.twig', $aVars); $oTwigContext->Render($this, 'login.html.twig', $aVars);
@@ -226,26 +214,21 @@ class LoginWebPage extends NiceWebPage
{ {
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data'); $sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
try try {
{
UserRights::Login($sAuthUser); // Set the user's language (if possible!) UserRights::Login($sAuthUser); // Set the user's language (if possible!)
/** @var UserInternal $oUser */ /** @var UserInternal $oUser */
$oUser = UserRights::GetUserObject(); $oUser = UserRights::GetUserObject();
if ($oUser != null) if ($oUser != null) {
{ if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token')) {
if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token'))
{
throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible')); throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible'));
} }
if (!$oUser->CanChangePassword()) if (!$oUser->CanChangePassword()) {
{
throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd')); throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd'));
} }
$sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed $sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed
if ($sTo == '') if ($sTo == '') {
{
throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail')); throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail'));
} }
@@ -265,8 +248,7 @@ class LoginWebPage extends NiceWebPage
$sResetUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=reset_pwd&auth_user='.urlencode($oUser->Get('login')).'&token='.urlencode($sToken); $sResetUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=reset_pwd&auth_user='.urlencode($oUser->Get('login')).'&token='.urlencode($sToken);
$oEmail->SetBody(Dict::Format('UI:ResetPwd-EmailBody', $sResetUrl, $oUser->Get('login'))); $oEmail->SetBody(Dict::Format('UI:ResetPwd-EmailBody', $sResetUrl, $oUser->Get('login')));
$iRes = $oEmail->Send($aIssues, true /* force synchronous exec */); $iRes = $oEmail->Send($aIssues, true /* force synchronous exec */);
switch ($iRes) switch ($iRes) {
{
//case EMAIL_SEND_PENDING: //case EMAIL_SEND_PENDING:
case EMAIL_SEND_OK: case EMAIL_SEND_OK:
break; break;
@@ -278,13 +260,10 @@ class LoginWebPage extends NiceWebPage
} }
} }
$oTwigContext = new LoginTwigRenderer(); $oTwigContext = new LoginTwigRenderer();
$aVars = $oTwigContext->GetDefaultVars(); $aVars = $oTwigContext->GetDefaultVars();
$oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars); $oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars);
} } catch (Exception $e) {
catch(Exception $e)
{
$this->DisplayForgotPwdForm(true, $e->getMessage()); $this->DisplayForgotPwdForm(true, $e->getMessage());
} }
} }
@@ -304,22 +283,16 @@ class LoginWebPage extends NiceWebPage
$aVars['sToken'] = $sToken; $aVars['sToken'] = $sToken;
$aVars['sErrorMessage'] = $sErrorMessage; $aVars['sErrorMessage'] = $sErrorMessage;
if (($oUser == null)) if (($oUser == null)) {
{
$aVars['bNoUser'] = true; $aVars['bNoUser'] = true;
} } else {
else
{
$aVars['bNoUser'] = false; $aVars['bNoUser'] = false;
$aVars['sUserName'] = $oUser->GetFriendlyName(); $aVars['sUserName'] = $oUser->GetFriendlyName();
$oEncryptedToken = $oUser->Get('reset_pwd_token'); $oEncryptedToken = $oUser->Get('reset_pwd_token');
if (!$oEncryptedToken->CheckPassword($sToken)) if (!$oEncryptedToken->CheckPassword($sToken)) {
{
$aVars['bBadToken'] = true; $aVars['bBadToken'] = true;
} } else {
else
{
$aVars['bBadToken'] = false; $aVars['bBadToken'] = false;
} }
} }
@@ -342,21 +315,15 @@ class LoginWebPage extends NiceWebPage
$aVars['sAuthUser'] = $sAuthUser; $aVars['sAuthUser'] = $sAuthUser;
$aVars['sToken'] = $sToken; $aVars['sToken'] = $sToken;
if (($oUser == null)) if (($oUser == null)) {
{
$aVars['bNoUser'] = true; $aVars['bNoUser'] = true;
} } else {
else
{
$aVars['bNoUser'] = false; $aVars['bNoUser'] = false;
$oEncryptedToken = $oUser->Get('reset_pwd_token'); $oEncryptedToken = $oUser->Get('reset_pwd_token');
if (!$oEncryptedToken->CheckPassword($sToken)) if (!$oEncryptedToken->CheckPassword($sToken)) {
{
$aVars['bBadToken'] = true; $aVars['bBadToken'] = true;
} } else {
else
{
$aVars['bBadToken'] = false; $aVars['bBadToken'] = false;
// Trash the token and change the password // Trash the token and change the password
$oUser->Set('reset_pwd_token', new ormPassword()); $oUser->Set('reset_pwd_token', new ormPassword());
@@ -413,7 +380,7 @@ class LoginWebPage extends NiceWebPage
// Note: This will destroy the session, and not just the session data! // Note: This will destroy the session, and not just the session data!
} }
static function SecureConnectionRequired() public static function SecureConnectionRequired()
{ {
return MetaModel::GetConfig()->GetSecureConnectionRequired(); return MetaModel::GetConfig()->GetSecureConnectionRequired();
} }
@@ -423,7 +390,7 @@ class LoginWebPage extends NiceWebPage
* @param string $sString * @param string $sString
* @return bool True if the string contains some typical UTF-8 multi-byte sequences * @return bool True if the string contains some typical UTF-8 multi-byte sequences
*/ */
static function LooksLikeUTF8($sString) public static function LooksLikeUTF8($sString)
{ {
return preg_match('%(?: return preg_match('%(?:
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
@@ -446,22 +413,19 @@ class LoginWebPage extends NiceWebPage
protected static function Login($iOnExit) protected static function Login($iOnExit)
{ {
self::$iOnExit = $iOnExit; self::$iOnExit = $iOnExit;
if (self::SecureConnectionRequired() && !utils::IsConnectionSecure()) if (self::SecureConnectionRequired() && !utils::IsConnectionSecure()) {
{
// Non secured URL... request for a secure connection // Non secured URL... request for a secure connection
throw new Exception('Secure connection required!'); throw new Exception('Secure connection required!');
} }
$bLoginDebug = MetaModel::GetConfig()->Get('login_debug'); $bLoginDebug = MetaModel::GetConfig()->Get('login_debug');
if (Session::Get('login_state') == self::LOGIN_STATE_ERROR) if (Session::Get('login_state') == self::LOGIN_STATE_ERROR) {
{
Session::Set('login_state', self::LOGIN_STATE_START); Session::Set('login_state', self::LOGIN_STATE_START);
} }
$sLoginState = Session::Get('login_state'); $sLoginState = Session::Get('login_state');
$sSessionLog = ''; $sSessionLog = '';
if ($bLoginDebug) if ($bLoginDebug) {
{
IssueLog::Info("---------------------------------"); IssueLog::Info("---------------------------------");
IssueLog::Info($_SERVER['REQUEST_URI']); IssueLog::Info($_SERVER['REQUEST_URI']);
IssueLog::Info("--> Entering Login FSM with state: [$sLoginState]"); IssueLog::Info("--> Entering Login FSM with state: [$sLoginState]");
@@ -472,38 +436,30 @@ class LoginWebPage extends NiceWebPage
$iErrorCode = self::EXIT_CODE_OK; $iErrorCode = self::EXIT_CODE_OK;
// Finite state machine loop // Finite state machine loop
while (true) while (true) {
{ try {
try
{
$aLoginPlugins = self::GetLoginPluginList(); $aLoginPlugins = self::GetLoginPluginList();
if (empty($aLoginPlugins)) if (empty($aLoginPlugins)) {
{
throw new Exception("Missing login classes"); throw new Exception("Missing login classes");
} }
/** @var iLoginFSMExtension $oLoginFSMExtensionInstance */ /** @var iLoginFSMExtension $oLoginFSMExtensionInstance */
foreach ($aLoginPlugins as $oLoginFSMExtensionInstance) foreach ($aLoginPlugins as $oLoginFSMExtensionInstance) {
{ if ($bLoginDebug) {
if ($bLoginDebug)
{
$sCurrSessionLog = session_id().' '.utils::GetSessionLog(); $sCurrSessionLog = session_id().' '.utils::GetSessionLog();
if ($sCurrSessionLog != $sSessionLog) if ($sCurrSessionLog != $sSessionLog) {
{
$sSessionLog = $sCurrSessionLog; $sSessionLog = $sCurrSessionLog;
IssueLog::Info("SESSION: $sSessionLog"); IssueLog::Info("SESSION: $sSessionLog");
} }
IssueLog::Info("Login: state: [$sLoginState] call: ".get_class($oLoginFSMExtensionInstance)); IssueLog::Info("Login: state: [$sLoginState] call: ".get_class($oLoginFSMExtensionInstance));
} }
$iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode); $iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode);
if ($iResponse == self::LOGIN_FSM_RETURN) if ($iResponse == self::LOGIN_FSM_RETURN) {
{
EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState])); EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState]));
Session::WriteClose(); Session::WriteClose();
return $iErrorCode; // Asked to exit FSM, generally login OK return $iErrorCode; // Asked to exit FSM, generally login OK
} }
if ($iResponse == self::LOGIN_FSM_ERROR) if ($iResponse == self::LOGIN_FSM_ERROR) {
{
EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState])); EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState]));
$sLoginState = self::LOGIN_STATE_SET_ERROR; // Next state will be error $sLoginState = self::LOGIN_STATE_SET_ERROR; // Next state will be error
// An error was detected, skip the other plugins turn // An error was detected, skip the other plugins turn
@@ -515,9 +471,7 @@ class LoginWebPage extends NiceWebPage
// Every plugin has nothing else to do in this state, go forward // Every plugin has nothing else to do in this state, go forward
$sLoginState = self::AdvanceLoginFSMState($sLoginState); $sLoginState = self::AdvanceLoginFSMState($sLoginState);
Session::Set('login_state', $sLoginState); Session::Set('login_state', $sLoginState);
} } catch (Exception $e) {
catch (Exception $e)
{
EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['state' => $_SESSION['login_state']])); EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['state' => $_SESSION['login_state']]));
IssueLog::Error($e->getTraceAsString()); IssueLog::Error($e->getTraceAsString());
static::ResetSession(); static::ResetSession();
@@ -537,30 +491,23 @@ class LoginWebPage extends NiceWebPage
*/ */
public static function GetLoginPluginList($sInterface = 'iLoginFSMExtension', $bFilterWithMode = true) public static function GetLoginPluginList($sInterface = 'iLoginFSMExtension', $bFilterWithMode = true)
{ {
$aAllPlugins = array(); $aAllPlugins = [];
if ($bFilterWithMode) if ($bFilterWithMode) {
{
$sCurrentLoginMode = Session::Get('login_mode', ''); $sCurrentLoginMode = Session::Get('login_mode', '');
} } else {
else
{
$sCurrentLoginMode = ''; $sCurrentLoginMode = '';
} }
/** @var iLoginExtension $oLoginExtensionInstance */ /** @var iLoginExtension $oLoginExtensionInstance */
foreach (MetaModel::EnumPlugins($sInterface) as $oLoginExtensionInstance) foreach (MetaModel::EnumPlugins($sInterface) as $oLoginExtensionInstance) {
{
$aLoginModes = $oLoginExtensionInstance->ListSupportedLoginModes(); $aLoginModes = $oLoginExtensionInstance->ListSupportedLoginModes();
$aLoginModes = (is_array($aLoginModes) ? $aLoginModes : array()); $aLoginModes = (is_array($aLoginModes) ? $aLoginModes : []);
foreach ($aLoginModes as $sLoginMode) foreach ($aLoginModes as $sLoginMode) {
{
// Keep only the plugins for the current login mode + before + after // Keep only the plugins for the current login mode + before + after
if (empty($sCurrentLoginMode) || ($sLoginMode == $sCurrentLoginMode) || ($sLoginMode == 'before') || ($sLoginMode == 'after')) if (empty($sCurrentLoginMode) || ($sLoginMode == $sCurrentLoginMode) || ($sLoginMode == 'before') || ($sLoginMode == 'after')) {
{ if (!isset($aAllPlugins[$sLoginMode])) {
if (!isset($aAllPlugins[$sLoginMode])) $aAllPlugins[$sLoginMode] = [];
{
$aAllPlugins[$sLoginMode] = array();
} }
$aAllPlugins[$sLoginMode][] = $oLoginExtensionInstance; $aAllPlugins[$sLoginMode][] = $oLoginExtensionInstance;
break; // Stop here to avoid registering a plugin twice break; // Stop here to avoid registering a plugin twice
@@ -569,12 +516,10 @@ class LoginWebPage extends NiceWebPage
} }
// Order and filter by the config list of allowed types (allowed_login_types) // Order and filter by the config list of allowed types (allowed_login_types)
$aAllowedLoginModes = array_merge(array('before'), MetaModel::GetConfig()->GetAllowedLoginTypes(), array('after')); $aAllowedLoginModes = array_merge(['before'], MetaModel::GetConfig()->GetAllowedLoginTypes(), ['after']);
$aPlugins = array(); $aPlugins = [];
foreach ($aAllowedLoginModes as $sAllowedMode) foreach ($aAllowedLoginModes as $sAllowedMode) {
{ if (isset($aAllPlugins[$sAllowedMode])) {
if (isset($aAllPlugins[$sAllowedMode]))
{
$aPlugins = array_merge($aPlugins, $aAllPlugins[$sAllowedMode]); $aPlugins = array_merge($aPlugins, $aAllPlugins[$sAllowedMode]);
} }
} }
@@ -590,8 +535,7 @@ class LoginWebPage extends NiceWebPage
*/ */
private static function AdvanceLoginFSMState($sLoginState) private static function AdvanceLoginFSMState($sLoginState)
{ {
switch ($sLoginState) switch ($sLoginState) {
{
case self::LOGIN_STATE_START: case self::LOGIN_STATE_START:
return self::LOGIN_STATE_MODE_DETECTION; return self::LOGIN_STATE_MODE_DETECTION;
@@ -638,8 +582,7 @@ class LoginWebPage extends NiceWebPage
public static function CheckUser($sAuthUser, $sAuthPassword = '', $sAuthentication = 'external') public static function CheckUser($sAuthUser, $sAuthPassword = '', $sAuthentication = 'external')
{ {
$oUser = self::FindUser($sAuthUser, true, ucfirst(strtolower($sAuthentication))); $oUser = self::FindUser($sAuthUser, true, ucfirst(strtolower($sAuthentication)));
if (is_null($oUser)) if (is_null($oUser)) {
{
return false; return false;
} }
@@ -668,8 +611,7 @@ class LoginWebPage extends NiceWebPage
{ {
// User is Ok, let's save it in the session and proceed with normal login // User is Ok, let's save it in the session and proceed with normal login
$bLoginSuccess = UserRights::Login($sAuthUser, $sAuthentication); // Login & set the user's language $bLoginSuccess = UserRights::Login($sAuthUser, $sAuthentication); // Login & set the user's language
if (!$bLoginSuccess) if (!$bLoginSuccess) {
{
throw new Exception("Bad user"); throw new Exception("Bad user");
} }
if (MetaModel::GetConfig()->Get('log_usage')) { if (MetaModel::GetConfig()->Get('log_usage')) {
@@ -696,12 +638,10 @@ class LoginWebPage extends NiceWebPage
*/ */
public static function CheckLoggedUser(&$iErrorCode) public static function CheckLoggedUser(&$iErrorCode)
{ {
if (Session::IsSet('auth_user')) if (Session::IsSet('auth_user')) {
{
// Already authenticated // Already authenticated
$bRet = UserRights::Login(Session::Get('auth_user')); // Login & set the user's language $bRet = UserRights::Login(Session::Get('auth_user')); // Login & set the user's language
if ($bRet) if ($bRet) {
{
$iErrorCode = self::EXIT_CODE_OK; $iErrorCode = self::EXIT_CODE_OK;
return self::LOGIN_FSM_RETURN; return self::LOGIN_FSM_RETURN;
} }
@@ -727,8 +667,7 @@ class LoginWebPage extends NiceWebPage
public static function SetLoginModeAndReload($sNewLoginMode) public static function SetLoginModeAndReload($sNewLoginMode)
{ {
if (Session::Get('login_mode') == $sNewLoginMode) if (Session::Get('login_mode') == $sNewLoginMode) {
{
return; return;
} }
Session::Set('login_mode', $sNewLoginMode); Session::Set('login_mode', $sNewLoginMode);
@@ -738,8 +677,7 @@ class LoginWebPage extends NiceWebPage
public static function HTTPReload() public static function HTTPReload()
{ {
$sOriginURL = utils::GetCurrentAbsoluteUrl(); $sOriginURL = utils::GetCurrentAbsoluteUrl();
if (!utils::StartsWith($sOriginURL, utils::GetAbsoluteUrlAppRoot())) if (!utils::StartsWith($sOriginURL, utils::GetAbsoluteUrlAppRoot())) {
{
// If the found URL does not start with the configured AppRoot URL // If the found URL does not start with the configured AppRoot URL
$sOriginURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php'; $sOriginURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
} }
@@ -753,7 +691,6 @@ class LoginWebPage extends NiceWebPage
exit; exit;
} }
/** /**
* Provisioning API: Find a User * Provisioning API: Find a User
* *
@@ -767,33 +704,28 @@ class LoginWebPage extends NiceWebPage
*/ */
public static function FindUser($sAuthUser, $bMustBeValid = true, $sType = 'External') public static function FindUser($sAuthUser, $bMustBeValid = true, $sType = 'External')
{ {
try try {
{ $aArgs = ['login' => $sAuthUser];
$aArgs = array('login' => $sAuthUser);
$sUserClass = "User$sType"; $sUserClass = "User$sType";
$oSearch = DBObjectSearch::FromOQL("SELECT $sUserClass WHERE login = :login"); $oSearch = DBObjectSearch::FromOQL("SELECT $sUserClass WHERE login = :login");
if ($bMustBeValid) if ($bMustBeValid) {
{
$oSearch->AddCondition('status', 'enabled'); $oSearch->AddCondition('status', 'enabled');
} }
$oSet = new DBObjectSet($oSearch, array(), $aArgs); $oSet = new DBObjectSet($oSearch, [], $aArgs);
if ($oSet->CountExceeds(0)) if ($oSet->CountExceeds(0)) {
{
/** @var User $oUser */ /** @var User $oUser */
$oUser = $oSet->Fetch(); $oUser = $oSet->Fetch();
return $oUser; return $oUser;
} }
} } catch (Exception $e) {
catch (Exception $e)
{
IssueLog::Error($e->getMessage()); IssueLog::Error($e->getMessage());
} }
return null; return null;
} }
/** /**
* Provisioning API: Find a Person by email * Provisioning API: Find a Person by email
* *
* @api * @api
* *
@@ -805,19 +737,15 @@ class LoginWebPage extends NiceWebPage
{ {
/** @var \Person $oPerson */ /** @var \Person $oPerson */
$oPerson = null; $oPerson = null;
try try {
{
$oSearch = new DBObjectSearch('Person'); $oSearch = new DBObjectSearch('Person');
$oSearch->AddCondition('email', $sEmail); $oSearch->AddCondition('email', $sEmail);
$oSet = new DBObjectSet($oSearch); $oSet = new DBObjectSet($oSearch);
if ($oSet->CountExceeds(1)) if ($oSet->CountExceeds(1)) {
{
throw new Exception(Dict::S('UI:Login:Error:MultipleContactsHaveSameEmail')); throw new Exception(Dict::S('UI:Login:Error:MultipleContactsHaveSameEmail'));
} }
$oPerson = $oSet->Fetch(); $oPerson = $oSet->Fetch();
} } catch (Exception $e) {
catch (Exception $e)
{
IssueLog::Error($e->getMessage()); IssueLog::Error($e->getMessage());
} }
return $oPerson; return $oPerson;
@@ -836,16 +764,14 @@ class LoginWebPage extends NiceWebPage
* *
* @return \Person * @return \Person
*/ */
public static function ProvisionPerson($sFirstName, $sLastName, $sEmail, $sOrganization, $aAdditionalParams = array()) public static function ProvisionPerson($sFirstName, $sLastName, $sEmail, $sOrganization, $aAdditionalParams = [])
{ {
/** @var Person $oPerson */ /** @var Person $oPerson */
$oPerson = null; $oPerson = null;
try try {
{
CMDBObject::SetTrackOrigin('custom-extension'); CMDBObject::SetTrackOrigin('custom-extension');
$sInfo = 'External User provisioning'; $sInfo = 'External User provisioning';
if (Session::IsSet('login_mode')) if (Session::IsSet('login_mode')) {
{
$sInfo .= " (".Session::Get('login_mode').")"; $sInfo .= " (".Session::Get('login_mode').")";
} }
CMDBObject::SetTrackInfo($sInfo); CMDBObject::SetTrackInfo($sInfo);
@@ -855,19 +781,15 @@ class LoginWebPage extends NiceWebPage
$oPerson->Set('name', $sLastName); $oPerson->Set('name', $sLastName);
$oPerson->Set('email', $sEmail); $oPerson->Set('email', $sEmail);
$oOrg = MetaModel::GetObjectByName('Organization', $sOrganization, false); $oOrg = MetaModel::GetObjectByName('Organization', $sOrganization, false);
if (is_null($oOrg)) if (is_null($oOrg)) {
{
throw new Exception(Dict::S('UI:Login:Error:WrongOrganizationName')); throw new Exception(Dict::S('UI:Login:Error:WrongOrganizationName'));
} }
$oPerson->Set('org_id', $oOrg->GetKey()); $oPerson->Set('org_id', $oOrg->GetKey());
foreach ($aAdditionalParams as $sAttCode => $sValue) foreach ($aAdditionalParams as $sAttCode => $sValue) {
{
$oPerson->Set($sAttCode, $sValue); $oPerson->Set($sAttCode, $sValue);
} }
$oPerson->DBInsert(); $oPerson->DBInsert();
} } catch (Exception $e) {
catch (Exception $e)
{
IssueLog::Error($e->getMessage()); IssueLog::Error($e->getMessage());
} }
return $oPerson; return $oPerson;
@@ -886,27 +808,23 @@ class LoginWebPage extends NiceWebPage
*/ */
public static function ProvisionUser($sAuthUser, $oPerson, $aRequestedProfiles) public static function ProvisionUser($sAuthUser, $oPerson, $aRequestedProfiles)
{ {
if (!MetaModel::IsValidClass('URP_Profiles')) if (!MetaModel::IsValidClass('URP_Profiles')) {
{
IssueLog::Error("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry."); IssueLog::Error("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
return null; return null;
} }
/** @var UserExternal $oUser */ /** @var UserExternal $oUser */
$oUser = null; $oUser = null;
try try {
{
CMDBObject::SetTrackOrigin('custom-extension'); CMDBObject::SetTrackOrigin('custom-extension');
$sInfo = 'External User provisioning'; $sInfo = 'External User provisioning';
if (Session::IsSet('login_mode')) if (Session::IsSet('login_mode')) {
{
$sInfo .= " (".Session::Get('login_mode').")"; $sInfo .= " (".Session::Get('login_mode').")";
} }
CMDBObject::SetTrackInfo($sInfo); CMDBObject::SetTrackInfo($sInfo);
$oUser = MetaModel::GetObjectByName('UserExternal', $sAuthUser, false); $oUser = MetaModel::GetObjectByName('UserExternal', $sAuthUser, false);
if (is_null($oUser)) if (is_null($oUser)) {
{
$oUser = MetaModel::NewObject('UserExternal'); $oUser = MetaModel::NewObject('UserExternal');
$oUser->Set('login', $sAuthUser); $oUser->Set('login', $sAuthUser);
$oUser->Set('contactid', $oPerson->GetKey()); $oUser->Set('contactid', $oPerson->GetKey());
@@ -916,41 +834,33 @@ class LoginWebPage extends NiceWebPage
// read all the existing profiles // read all the existing profiles
$oProfilesSearch = new DBObjectSearch('URP_Profiles'); $oProfilesSearch = new DBObjectSearch('URP_Profiles');
$oProfilesSet = new DBObjectSet($oProfilesSearch); $oProfilesSet = new DBObjectSet($oProfilesSearch);
$aAllProfiles = array(); $aAllProfiles = [];
while ($oProfile = $oProfilesSet->Fetch()) while ($oProfile = $oProfilesSet->Fetch()) {
{
$aAllProfiles[mb_strtolower($oProfile->GetName())] = $oProfile->GetKey(); $aAllProfiles[mb_strtolower($oProfile->GetName())] = $oProfile->GetKey();
} }
$aProfiles = array(); $aProfiles = [];
foreach ($aRequestedProfiles as $sRequestedProfile) foreach ($aRequestedProfiles as $sRequestedProfile) {
{
$sRequestedProfile = mb_strtolower($sRequestedProfile); $sRequestedProfile = mb_strtolower($sRequestedProfile);
if (isset($aAllProfiles[$sRequestedProfile])) if (isset($aAllProfiles[$sRequestedProfile])) {
{
$aProfiles[] = $aAllProfiles[$sRequestedProfile]; $aProfiles[] = $aAllProfiles[$sRequestedProfile];
} }
} }
if (empty($aProfiles)) if (empty($aProfiles)) {
{
throw new Exception(Dict::S('UI:Login:Error:NoValidProfiles')); throw new Exception(Dict::S('UI:Login:Error:NoValidProfiles'));
} }
// Now synchronize the profiles // Now synchronize the profiles
$sOrigin = 'External User provisioning'; $sOrigin = 'External User provisioning';
if (Session::IsSet('login_mode')) if (Session::IsSet('login_mode')) {
{
$sOrigin .= " (".Session::Get('login_mode').")"; $sOrigin .= " (".Session::Get('login_mode').")";
} }
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin); $aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
if ($oUser->IsModified()) if ($oUser->IsModified()) {
{
$oUser->DBWrite(); $oUser->DBWrite();
} }
} } catch (Exception $e) {
catch (Exception $e)
{
IssueLog::Error($e->getMessage()); IssueLog::Error($e->getMessage());
} }
@@ -961,26 +871,18 @@ class LoginWebPage extends NiceWebPage
* Overridable: depending on the user, head toward a dedicated portal * Overridable: depending on the user, head toward a dedicated portal
* @param string|null $sRequestedPortalId * @param string|null $sRequestedPortalId
* @param int $iOnExit How to complete the call: redirect or return a code * @param int $iOnExit How to complete the call: redirect or return a code
*/ */
protected static function ChangeLocation($sRequestedPortalId = null, $iOnExit = self::EXIT_PROMPT) protected static function ChangeLocation($sRequestedPortalId = null, $iOnExit = self::EXIT_PROMPT)
{ {
$ret = call_user_func(array(self::$sHandlerClass, 'Dispatch'), $sRequestedPortalId); $ret = call_user_func([self::$sHandlerClass, 'Dispatch'], $sRequestedPortalId);
if ($ret === true) if ($ret === true) {
{
return self::EXIT_CODE_OK; return self::EXIT_CODE_OK;
} } elseif ($ret === false) {
else if($ret === false)
{
throw new Exception('Nowhere to go: Your combination of user Profiles denies you access to any '.ITOP_APPLICATION_SHORT.' portal. Please contact your administrator'); throw new Exception('Nowhere to go: Your combination of user Profiles denies you access to any '.ITOP_APPLICATION_SHORT.' portal. Please contact your administrator');
} } else {
else if ($iOnExit == self::EXIT_RETURN) {
{
if ($iOnExit == self::EXIT_RETURN)
{
return self::EXIT_CODE_PORTALUSERNOTAUTHORIZED; return self::EXIT_CODE_PORTALUSERNOTAUTHORIZED;
} } else {
else
{
// No rights to be here, redirect to the portal // No rights to be here, redirect to the portal
header('Location: '.$ret); header('Location: '.$ret);
die(); die();
@@ -1002,7 +904,7 @@ class LoginWebPage extends NiceWebPage
* @return int|mixed|string * @return int|mixed|string
* @throws \Exception * @throws \Exception
*/ */
static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false, $iOnExit = self::EXIT_PROMPT) public static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false, $iOnExit = self::EXIT_PROMPT)
{ {
$sRequestedPortalId = $bIsAllowedToPortalUsers ? 'legacy_portal' : 'backoffice'; $sRequestedPortalId = $bIsAllowedToPortalUsers ? 'legacy_portal' : 'backoffice';
return self::DoLoginEx($sRequestedPortalId, $bMustBeAdmin, $iOnExit); return self::DoLoginEx($sRequestedPortalId, $bMustBeAdmin, $iOnExit);
@@ -1019,23 +921,18 @@ class LoginWebPage extends NiceWebPage
* @return int|mixed|string * @return int|mixed|string
* @throws \Exception * @throws \Exception
*/ */
static function DoLoginEx($sRequestedPortalId = null, $bMustBeAdmin = false, $iOnExit = self::EXIT_PROMPT) public static function DoLoginEx($sRequestedPortalId = null, $bMustBeAdmin = false, $iOnExit = self::EXIT_PROMPT)
{ {
$operation = utils::ReadParam('loginop', ''); $operation = utils::ReadParam('loginop', '');
$sMessage = self::HandleOperations($operation); // May exit directly $sMessage = self::HandleOperations($operation); // May exit directly
$iRet = self::Login($iOnExit); $iRet = self::Login($iOnExit);
if ($iRet == self::EXIT_CODE_OK) if ($iRet == self::EXIT_CODE_OK) {
{ if ($bMustBeAdmin && !UserRights::IsAdministrator()) {
if ($bMustBeAdmin && !UserRights::IsAdministrator()) if ($iOnExit == self::EXIT_RETURN) {
{
if ($iOnExit == self::EXIT_RETURN)
{
return self::EXIT_CODE_MUSTBEADMIN; return self::EXIT_CODE_MUSTBEADMIN;
} } else {
else
{
require_once(APPROOT.'/setup/setuppage.class.inc.php'); require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError')); $oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n"); $oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
@@ -1044,69 +941,52 @@ class LoginWebPage extends NiceWebPage
exit; exit;
} }
} }
$iRet = call_user_func(array(self::$sHandlerClass, 'ChangeLocation'), $sRequestedPortalId, $iOnExit); $iRet = call_user_func([self::$sHandlerClass, 'ChangeLocation'], $sRequestedPortalId, $iOnExit);
} }
if ($iOnExit == self::EXIT_RETURN) if ($iOnExit == self::EXIT_RETURN) {
{
return $iRet; return $iRet;
} } else {
else
{
return $sMessage; return $sMessage;
} }
} }
protected static function HandleOperations($operation) protected static function HandleOperations($operation)
{ {
$sMessage = ''; // most of the operations never return, but some can return a message to be displayed $sMessage = ''; // most of the operations never return, but some can return a message to be displayed
if ($operation == 'logoff') if ($operation == 'logoff') {
{
self::ResetSession(); self::ResetSession();
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DisplayLoginForm(false /* not a failed attempt */); $oPage->DisplayLoginForm(false /* not a failed attempt */);
$oPage->output(); $oPage->output();
exit; exit;
} } elseif ($operation == 'forgot_pwd') {
else if ($operation == 'forgot_pwd')
{
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DisplayForgotPwdForm(); $oPage->DisplayForgotPwdForm();
$oPage->output(); $oPage->output();
exit; exit;
} } elseif ($operation == 'forgot_pwd_go') {
else if ($operation == 'forgot_pwd_go')
{
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->ForgotPwdGo(); $oPage->ForgotPwdGo();
$oPage->output(); $oPage->output();
exit; exit;
} } elseif ($operation == 'reset_pwd') {
else if ($operation == 'reset_pwd')
{
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DisplayResetPwdForm(); $oPage->DisplayResetPwdForm();
$oPage->output(); $oPage->output();
exit; exit;
} } elseif ($operation == 'do_reset_pwd') {
else if ($operation == 'do_reset_pwd')
{
try { try {
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DoResetPassword(); $oPage->DoResetPassword();
} } catch (CoreCannotSaveObjectException $e) {
catch (CoreCannotSaveObjectException $e)
{
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DisplayResetPwdForm($e->getIssue()); $oPage->DisplayResetPwdForm($e->getIssue());
} }
$oPage->output(); $oPage->output();
exit; exit;
} } elseif ($operation == 'change_pwd') {
else if ($operation == 'change_pwd') if (Session::IsSet('auth_user')) {
{
if (Session::IsSet('auth_user'))
{
$sAuthUser = Session::Get('auth_user'); $sAuthUser = Session::Get('auth_user');
$sIssue = Session::Get('pwd_issue'); $sIssue = Session::Get('pwd_issue');
Session::Unset('pwd_issue'); Session::Unset('pwd_issue');
@@ -1118,16 +998,13 @@ class LoginWebPage extends NiceWebPage
$oPage->output(); $oPage->output();
exit; exit;
} }
} } elseif ($operation == 'check_pwd_policy') {
else if ($operation == 'check_pwd_policy')
{
$sAuthUser = Session::Get('auth_user'); $sAuthUser = Session::Get('auth_user');
UserRights::Login($sAuthUser); // Set the user's language UserRights::Login($sAuthUser); // Set the user's language
$aPwdMap = array(); $aPwdMap = [];
foreach (array('new_pwd', 'retype_new_pwd') as $postedPwd) foreach (['new_pwd', 'retype_new_pwd'] as $postedPwd) {
{
$oUser = new UserLocal(); $oUser = new UserLocal();
$oUser->ValidatePassword($_POST[$postedPwd]); $oUser->ValidatePassword($_POST[$postedPwd]);
@@ -1137,27 +1014,21 @@ class LoginWebPage extends NiceWebPage
echo json_encode($aPwdMap); echo json_encode($aPwdMap);
die(); die();
} }
if ($operation == 'do_change_pwd') if ($operation == 'do_change_pwd') {
{ if (Session::IsSet('auth_user')) {
if (Session::IsSet('auth_user'))
{
$sAuthUser = Session::Get('auth_user'); $sAuthUser = Session::Get('auth_user');
UserRights::Login($sAuthUser); // Set the user's language UserRights::Login($sAuthUser); // Set the user's language
$sOldPwd = utils::ReadPostedParam('old_pwd', '', 'raw_data'); $sOldPwd = utils::ReadPostedParam('old_pwd', '', 'raw_data');
$sNewPwd = utils::ReadPostedParam('new_pwd', '', 'raw_data'); $sNewPwd = utils::ReadPostedParam('new_pwd', '', 'raw_data');
try try {
{ if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd)))) {
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
{
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DisplayChangePwdForm(true); // old pwd was wrong $oPage->DisplayChangePwdForm(true); // old pwd was wrong
$oPage->output(); $oPage->output();
exit; exit;
} }
} } catch (CoreCannotSaveObjectException $e) {
catch (CoreCannotSaveObjectException $e)
{
$oPage = self::NewLoginWebPage(); $oPage = self::NewLoginWebPage();
$oPage->DisplayChangePwdForm(true, $e->getIssue()); // password policy was not met. $oPage->DisplayChangePwdForm(true, $e->getIssue()); // password policy was not met.
$oPage->output(); $oPage->output();
@@ -1168,26 +1039,27 @@ class LoginWebPage extends NiceWebPage
} }
return $sMessage; return $sMessage;
} }
protected static function Dispatch($sRequestedPortalId) protected static function Dispatch($sRequestedPortalId)
{ {
if ($sRequestedPortalId === null) return true; // allowed to any portal => return true if ($sRequestedPortalId === null) {
return true;
} // allowed to any portal => return true
$aPortalsConf = PortalDispatcherData::GetData(); $aPortalsConf = PortalDispatcherData::GetData();
$aDispatchers = array(); $aDispatchers = [];
foreach($aPortalsConf as $sPortalId => $aConf) foreach ($aPortalsConf as $sPortalId => $aConf) {
{
$sHandlerClass = $aConf['handler']; $sHandlerClass = $aConf['handler'];
$aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId); $aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId);
} }
if (array_key_exists($sRequestedPortalId, $aDispatchers) && $aDispatchers[$sRequestedPortalId]->IsUserAllowed()) if (array_key_exists($sRequestedPortalId, $aDispatchers) && $aDispatchers[$sRequestedPortalId]->IsUserAllowed()) {
{
return true; return true;
} }
foreach($aDispatchers as $sPortalId => $oDispatcher) foreach ($aDispatchers as $sPortalId => $oDispatcher) {
{ if ($oDispatcher->IsUserAllowed()) {
if ($oDispatcher->IsUserAllowed()) return $oDispatcher->GetUrl(); return $oDispatcher->GetUrl();
}
} }
return false; // nothing matched !! return false; // nothing matched !!
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -17,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
*/ */
// //
// Maintenance message display functions // Maintenance message display functions
// Only included by approot.inc.php // Only included by approot.inc.php
@@ -33,21 +33,17 @@ function _MaintenanceSetupPageMessage($sTitle, $sMessage)
{ {
// Web Page // Web Page
@include_once(APPROOT.'setup/setuppage.class.inc.php'); @include_once(APPROOT.'setup/setuppage.class.inc.php');
if (class_exists('SetupPage')) if (class_exists('SetupPage')) {
{
$oP = new ErrorPage($sTitle); $oP = new ErrorPage($sTitle);
$oP->p("<h2 class=\"center\">$sMessage</h2>"); $oP->p("<h2 class=\"center\">$sMessage</h2>");
$oP->add_ready_script( $oP->add_ready_script(
<<<JS <<<JS
// Reload in 30s to check if maintenance is over // Reload in 30s to check if maintenance is over
setTimeout(function(){ window.location.reload(); }, 30000); setTimeout(function(){ window.location.reload(); }, 30000);
JS JS
); );
$oP->output(); $oP->output();
} } else {
else
{
_MaintenanceTextMessage($sMessage); _MaintenanceTextMessage($sMessage);
} }
} }
@@ -78,14 +74,13 @@ function _MaintenanceHtmlMessage($sMessage)
*/ */
function _MaintenanceJsonMessage($sTitle, $sMessage) function _MaintenanceJsonMessage($sTitle, $sMessage)
{ {
if (class_exists('JsonPage')) if (class_exists('JsonPage')) {
{
$oP = new JsonPage($sTitle); $oP = new JsonPage($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *'); $oP->add_header('Access-Control-Allow-Origin: *');
$aMessage = [ $aMessage = [
'code' => 100, 'code' => 100,
'message' =>$sMessage 'message' => $sMessage,
]; ];
$oP->AddData($aMessage); $oP->AddData($aMessage);

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -34,44 +35,44 @@ interface iNewsroomProvider
* return bool * return bool
*/ */
public function IsApplicable(User $oUser = null); public function IsApplicable(User $oUser = null);
/** /**
* The human readable (localized) label for this provider * The human readable (localized) label for this provider
* @return string * @return string
*/ */
public function GetLabel(); public function GetLabel();
/** /**
* The URL to query (from the browser, using jsonp) to fetch all unread messages * The URL to query (from the browser, using jsonp) to fetch all unread messages
* @return string * @return string
*/ */
public function GetFetchURL(); public function GetFetchURL();
/** /**
* The URL to navigate to in order to display all messages * The URL to navigate to in order to display all messages
* @return string * @return string
*/ */
public function GetViewAllURL(); public function GetViewAllURL();
/** /**
* The URL to query(from the browser, using jsonp) to mark all unread messages as read * The URL to query(from the browser, using jsonp) to mark all unread messages as read
* @return string * @return string
*/ */
public function GetMarkAllAsReadURL(); public function GetMarkAllAsReadURL();
/** /**
* Return the URL to configure the preferences for this provider or null is there is nothing to configure * Return the URL to configure the preferences for this provider or null is there is nothing to configure
* @return string|null * @return string|null
*/ */
public function GetPreferencesUrl(); public function GetPreferencesUrl();
/** /**
* Return an array key => value to be replaced in URL of the messages * Return an array key => value to be replaced in URL of the messages
* Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot(); * Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot();
* @return string[] * @return string[]
*/ */
public function GetPlaceholders(); public function GetPlaceholders();
/** /**
* The duration between to refreshes of the cache (in seconds) * The duration between to refreshes of the cache (in seconds)
* @return int * @return int
@@ -90,19 +91,19 @@ abstract class NewsroomProviderBase implements iNewsroomProvider
* @var Config * @var Config
*/ */
protected $oConfig; protected $oConfig;
public function __construct() public function __construct()
{ {
$this->oConfig = null; $this->oConfig = null;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see iNewsroomProvider::SetConfig() * @see iNewsroomProvider::SetConfig()
*/ */
public function SetConfig(Config $oConfig) public function SetConfig(Config $oConfig)
{ {
$this->oConfig = $oConfig; $this->oConfig = $oConfig;
} }
/** /**
@@ -118,42 +119,42 @@ abstract class NewsroomProviderBase implements iNewsroomProvider
* {@inheritDoc} * {@inheritDoc}
* @see iNewsroomProvider::GetLabel() * @see iNewsroomProvider::GetLabel()
*/ */
public abstract function GetLabel(); abstract public function GetLabel();
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see iNewsroomProvider::GetFetchURL() * @see iNewsroomProvider::GetFetchURL()
*/ */
public abstract function GetFetchURL(); abstract public function GetFetchURL();
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see iNewsroomProvider::GetMarkAllURL() * @see iNewsroomProvider::GetMarkAllURL()
*/ */
public abstract function GetMarkAllAsReadURL(); abstract public function GetMarkAllAsReadURL();
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see iNewsroomProvider::GetViewAllURL() * @see iNewsroomProvider::GetViewAllURL()
*/ */
public abstract function GetViewAllURL(); abstract public function GetViewAllURL();
public function IsApplicable(User $oUser = null) public function IsApplicable(User $oUser = null)
{ {
return false; return false;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see iNewsroomProvider::GetPlaceholders() * @see iNewsroomProvider::GetPlaceholders()
*/ */
public function GetPlaceholders() public function GetPlaceholders()
{ {
return array(); // By default, empty set of placeholders return []; // By default, empty set of placeholders
} }
public function GetTTL() public function GetTTL()
{ {
return 10*60; // Refresh every 10 minutes return 10 * 60; // Refresh every 10 minutes
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
class PortalDispatcher class PortalDispatcher
{ {
protected $sPortalid; protected $sPortalid;
protected $aData; protected $aData;
public function __construct($sPortalId) public function __construct($sPortalId)
{ {
$this->sPortalid = $sPortalId; $this->sPortalid = $sPortalId;
@@ -20,53 +21,45 @@ class PortalDispatcher
{ {
$bRet = true; $bRet = true;
$aProfiles = UserRights::ListProfiles($oUser); $aProfiles = UserRights::ListProfiles($oUser);
foreach($this->aData['deny'] as $sDeniedProfile) foreach ($this->aData['deny'] as $sDeniedProfile) {
{
// If one denied profile is present, it's enough => return false // If one denied profile is present, it's enough => return false
if (in_array($sDeniedProfile, $aProfiles)) if (in_array($sDeniedProfile, $aProfiles)) {
{
return false; return false;
} }
} }
// If there are some "allow" profiles, then by default the result is false // If there are some "allow" profiles, then by default the result is false
// since the user must have at least one of the profiles to be allowed // since the user must have at least one of the profiles to be allowed
if (count($this->aData['allow']) > 0) if (count($this->aData['allow']) > 0) {
{
$bRet = false; $bRet = false;
} }
foreach($this->aData['allow'] as $sAllowProfile) foreach ($this->aData['allow'] as $sAllowProfile) {
{
// If one "allow" profile is present, it's enough => return true // If one "allow" profile is present, it's enough => return true
if (in_array($sAllowProfile, $aProfiles)) if (in_array($sAllowProfile, $aProfiles)) {
{
return true; return true;
} }
} }
return $bRet; return $bRet;
} }
public function GetURL() public function GetURL()
{ {
$aOverloads = MetaModel::GetConfig()->Get('portal_dispatch_urls'); $aOverloads = MetaModel::GetConfig()->Get('portal_dispatch_urls');
if (array_key_exists($this->sPortalid, $aOverloads)) if (array_key_exists($this->sPortalid, $aOverloads)) {
{
$sRet = $aOverloads[$this->sPortalid]; $sRet = $aOverloads[$this->sPortalid];
} } else {
else
{
$sRet = utils::GetAbsoluteUrlAppRoot().$this->aData['url']; $sRet = utils::GetAbsoluteUrlAppRoot().$this->aData['url'];
} }
return $sRet; return $sRet;
} }
public function GetLabel() public function GetLabel()
{ {
return Dict::S('portal:'.$this->sPortalid); return Dict::S('portal:'.$this->sPortalid);
} }
public function GetRank() public function GetRank()
{ {
return $this->aData['rank']; return $this->aData['rank'];
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -18,7 +19,6 @@
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings; use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\WebPage\WebPage; use Combodo\iTop\Application\WebPage\WebPage;
/** /**
* Persistent class Shortcut and derived * Persistent class Shortcut and derived
* Shortcuts of any kind * Shortcuts of any kind
@@ -31,32 +31,32 @@ abstract class Shortcut extends DBObject implements iDisplay
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "gui,view_in_gui", "category" => "gui,view_in_gui",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_shortcut", "db_table" => "priv_shortcut",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", ["targetclass" => "User", "allowed_values" => null, "sql" => "user_id", "is_null_allowed" => true, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("context", ["allowed_values" => null, "sql" => "context", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', ['name', 'context']); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', ['name']); // Attributes to be displayed for a list
// Search criteria // Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array()); abstract public function RenderContent(WebPage $oPage, $aExtraParams = []);
protected function OnInsert() protected function OnInsert()
{ {
@@ -74,14 +74,14 @@ abstract class Shortcut extends DBObject implements iDisplay
$oForm->AddField($oField); $oForm->AddField($oField);
$oForm->Render($oPage); $oForm->Render($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title'); $sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok'); $sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$iShortcut = $this->GetKey(); $iShortcut = $this->GetKey();
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
function ShortcutRenameOK() function ShortcutRenameOK()
{ {
var oForm = $(this).find('form'); var oForm = $(this).find('form');
@@ -137,13 +137,13 @@ EOF
return ''; return '';
} }
function DisplayDetails(WebPage $oPage, $bEditMode = false) public function DisplayDetails(WebPage $oPage, $bEditMode = false)
{ {
} }
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array()) public function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = [])
{ {
return array(); return [];
} }
// End of the minimal implementation of iDisplay // End of the minimal implementation of iDisplay
} }
@@ -152,61 +152,56 @@ class ShortcutOQL extends Shortcut
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "gui,view_in_gui", "category" => "gui,view_in_gui",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_shortcut_oql", "db_table" => "priv_shortcut_oql",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeOQL("oql", ["allowed_values" => null, "sql" => "oql", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", ["allowed_values" => new ValueSetEnum('none,custom'), "sql" => "auto_reload", "default_value" => "none", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", ["allowed_values" => null, "sql" => "auto_reload_sec", "default_value" => 60, "is_null_allowed" => false, "depends_on" => []]));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', ['name', 'context', 'oql']); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', ['name']); // Attributes to be displayed for a list
// Search criteria // Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
public function RenderContent(WebPage $oPage, $aExtraParams = array()) public function RenderContent(WebPage $oPage, $aExtraParams = [])
{ {
$oPage->set_title($this->Get('name')); $oPage->set_title($this->Get('name'));
switch($this->Get('auto_reload')) switch ($this->Get('auto_reload')) {
{ case 'custom':
case 'custom': $iRate = (int)$this->Get('auto_reload_sec');
$iRate = (int)$this->Get('auto_reload_sec'); if ($iRate > 0) {
if ($iRate > 0) // Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
{ $aExtraParams['auto_reload'] = (string)$iRate;
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate! }
$aExtraParams['auto_reload'] = (string)$iRate; break;
}
break;
default: default:
case 'none': case 'none':
} }
$bSearchPane = true; $bSearchPane = true;
$bSearchOpen = true; $bSearchOpen = true;
try try {
{
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true); OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true);
} } catch (Exception $e) {
catch (Exception $e)
{
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage()); throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
} }
} }
public function CloneTableSettings($sTableSettings) public function CloneTableSettings($sTableSettings)
@@ -226,17 +221,14 @@ class ShortcutOQL extends Shortcut
// Find a unique default name // Find a unique default name
// -> The class of the query + an index if necessary // -> The class of the query + an index if necessary
if ($sOQL == null) if ($sOQL == null) {
{
$sDefault = ''; $sDefault = '';
} } else {
else
{
$oBMSearch = new DBObjectSearch('Shortcut'); $oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '='); $oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oBMSet = new DBObjectSet($oBMSearch); $oBMSet = new DBObjectSet($oBMSearch);
$aNames = $oBMSet->GetColumnAsArray('name'); $aNames = $oBMSet->GetColumnAsArray('name');
$oSearch = DBObjectSearch::FromOQL($sOQL); $oSearch = DBObjectSearch::FromOQL($sOQL);
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames); $sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
} }
@@ -276,18 +268,18 @@ class ShortcutOQL extends Shortcut
$oForm->Render($oPage); $oForm->Render($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title'); $sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok'); $sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(); $sContext = $oAppContext->GetForLink();
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval'))); $sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<JS
// Note: the title gets deleted by the validation mechanism // Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle'); $("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec")); CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -23,7 +24,6 @@ require_once(APPROOT.'core/contexttag.class.inc.php');
require_once(APPROOT.'core/kpi.class.inc.php'); require_once(APPROOT.'core/kpi.class.inc.php');
require_once(APPROOT.'setup/setuputils.class.inc.php'); require_once(APPROOT.'setup/setuputils.class.inc.php');
/** /**
* File to include to initialize the datamodel in memory * File to include to initialize the datamodel in memory
* *
@@ -36,12 +36,10 @@ ExecutionKPI::EnableMemory(1);
// This storage is freed on error (case of allowed memory exhausted) // This storage is freed on error (case of allowed memory exhausted)
$sReservedMemory = str_repeat('*', 1024 * 1024); $sReservedMemory = str_repeat('*', 1024 * 1024);
register_shutdown_function(function() register_shutdown_function(function () {
{
global $sReservedMemory; global $sReservedMemory;
$sReservedMemory = null; $sReservedMemory = null;
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR)) if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR)) {
{
// Remove stack trace from MySQLException (since 2.7.2 see N°3174) // Remove stack trace from MySQLException (since 2.7.2 see N°3174)
$sMessage = $err['message']; $sMessage = $err['message'];
if (strpos($sMessage, 'MySQLException') !== false) { if (strpos($sMessage, 'MySQLException') !== false) {
@@ -71,38 +69,30 @@ $oKPI->ComputeAndReport("Session Start");
$sSwitchEnv = utils::ReadParam('switch_env', null); $sSwitchEnv = utils::ReadParam('switch_env', null);
$bAllowCache = true; $bAllowCache = true;
if (($sSwitchEnv != null) && file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE) &&( Session::Get('itop_env') !== $sSwitchEnv)) if (($sSwitchEnv != null) && file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE) && (Session::Get('itop_env') !== $sSwitchEnv)) {
{
Session::Set('itop_env', $sSwitchEnv); Session::Set('itop_env', $sSwitchEnv);
$sEnv = $sSwitchEnv; $sEnv = $sSwitchEnv;
$bAllowCache = false; $bAllowCache = false;
// Reset the opcache since otherwise the PHP "model" files may still be cached !! // Reset the opcache since otherwise the PHP "model" files may still be cached !!
if (function_exists('opcache_reset')) if (function_exists('opcache_reset')) {
{ // Zend opcode cache
// Zend opcode cache opcache_reset();
opcache_reset(); }
} if (function_exists('apc_clear_cache')) {
if (function_exists('apc_clear_cache')) // APC(u) cache
{ apc_clear_cache();
// APC(u) cache }
apc_clear_cache();
}
// TODO: reset the credentials as well ?? // TODO: reset the credentials as well ??
} } elseif (Session::IsSet('itop_env')) {
else if (Session::IsSet('itop_env'))
{
$sEnv = Session::Get('itop_env'); $sEnv = Session::Get('itop_env');
} } else {
else
{
$sEnv = ITOP_DEFAULT_ENV; $sEnv = ITOP_DEFAULT_ENV;
Session::Set('itop_env', ITOP_DEFAULT_ENV); Session::Set('itop_env', ITOP_DEFAULT_ENV);
} }
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE; $sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
try { try {
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv); MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
} catch (MySQLException $e) {
IssueLog::Debug($e->getMessage());
throw new MySQLException('Could not connect to the DB server', []);
} }
catch (MySQLException $e) {
IssueLog::Debug($e->getMessage());
throw new MySQLException('Could not connect to the DB server', []);
}

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -25,7 +26,7 @@
*/ */
class ThemeHandler class ThemeHandler
{ {
const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg']; public const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
/** @var \CompileCSSService */ /** @var \CompileCSSService */
private static $oCompileCSSService; private static $oCompileCSSService;
@@ -50,7 +51,7 @@ class ThemeHandler
'imports' => [], 'imports' => [],
'stylesheets' => [ 'stylesheets' => [
'main' => '../css/backoffice/main.scss', 'main' => '../css/backoffice/main.scss',
] ],
], ],
]; ];
} }
@@ -63,8 +64,7 @@ class ThemeHandler
{ {
try { try {
$sThemeId = utils::GetConfig()->Get('backoffice_default_theme'); $sThemeId = utils::GetConfig()->Get('backoffice_default_theme');
} } catch (CoreException $oCompileException) {
catch (CoreException $oCompileException) {
// Fallback on our default theme in case the config. is not available yet // Fallback on our default theme in case the config. is not available yet
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation(); $aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
$sThemeId = $aDefaultTheme['name']; $sThemeId = $aDefaultTheme['name'];
@@ -85,8 +85,7 @@ class ThemeHandler
if (true === utils::GetConfig()->Get('user_preferences.allow_backoffice_theme_override')) { if (true === utils::GetConfig()->Get('user_preferences.allow_backoffice_theme_override')) {
$sThemeId = appUserPreferences::GetPref('backoffice_theme', null); $sThemeId = appUserPreferences::GetPref('backoffice_theme', null);
} }
} } catch (Exception $oException) {
catch (Exception $oException) {
// Do nothing, already handled by $sThemeId null by default // Do nothing, already handled by $sThemeId null by default
} }
@@ -201,8 +200,7 @@ class ThemeHandler
if (static::ShouldThemeSignatureCheckBeForced($sThemeId)) { if (static::ShouldThemeSignatureCheckBeForced($sThemeId)) {
static::CompileTheme($sThemeId); static::CompileTheme($sThemeId);
} }
} } catch (CoreException $oCompileException) {
catch (CoreException $oCompileException) {
// Fallback on our default theme (should always be compilable) in case the previous theme doesn't exists // Fallback on our default theme (should always be compilable) in case the previous theme doesn't exists
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation(); $aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
$sThemeId = $aDefaultTheme['name']; $sThemeId = $aDefaultTheme['name'];
@@ -258,13 +256,16 @@ class ThemeHandler
* @throws \CoreException * @throws \CoreException
* @return boolean: indicate whether theme compilation occured * @return boolean: indicate whether theme compilation occured
*/ */
public static function CompileTheme($sThemeId, $bSetup=false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null) { public static function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
{
if ($sSetupCompilationTimestamp === "") { if ($sSetupCompilationTimestamp === "") {
$sSetupCompilationTimestamp = microtime(true); $sSetupCompilationTimestamp = microtime(true);
} }
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !== false) ? explode('.', $sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !== false) ? explode(
$sSetupCompilationTimestamp)[0] : $sSetupCompilationTimestamp; '.',
$sSetupCompilationTimestamp
)[0] : $sSetupCompilationTimestamp;
$sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/'; $sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
@@ -317,7 +318,7 @@ class ThemeHandler
} }
} }
foreach ($oFindStylesheetObject->GetStylesheetFileURIs() as $sStylesheet){ foreach ($oFindStylesheetObject->GetStylesheetFileURIs() as $sStylesheet) {
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n"; $sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
} }
@@ -329,11 +330,9 @@ class ThemeHandler
$iStyleLastModified = $oFindStylesheetObject->GetLastModified(); $iStyleLastModified = $oFindStylesheetObject->GetLastModified();
$aIncludedImages=static::GetIncludedImages($aThemeParametersWithVersion, $oFindStylesheetObject->GetAllStylesheetPaths(), $sThemeId); $aIncludedImages = static::GetIncludedImages($aThemeParametersWithVersion, $oFindStylesheetObject->GetAllStylesheetPaths(), $sThemeId);
foreach ($aIncludedImages as $sImage) foreach ($aIncludedImages as $sImage) {
{ if (is_file($sImage)) {
if (is_file($sImage))
{
$iStylesheetLastModified = @filemtime($sImage); $iStylesheetLastModified = @filemtime($sImage);
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified; $iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
} }
@@ -342,34 +341,28 @@ class ThemeHandler
// Checking if our compiled css is outdated // Checking if our compiled css is outdated
$iFilemetime = @filemtime($sThemeCssPath); $iFilemetime = @filemtime($sThemeCssPath);
$bFileExists = file_exists($sThemeCssPath); $bFileExists = file_exists($sThemeCssPath);
$bVarSignatureChanged=false; $bVarSignatureChanged = false;
if ($bFileExists && $bSetup) if ($bFileExists && $bSetup) {
{
$sPrecompiledSignature = static::GetSignature($sThemeCssPath); $sPrecompiledSignature = static::GetSignature($sThemeCssPath);
//check variable signature has changed which is independant from any file modification //check variable signature has changed which is independant from any file modification
if (!empty($sPrecompiledSignature)){ if (!empty($sPrecompiledSignature)) {
$sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature); $sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature);
$sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables'])); $sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables']));
$bVarSignatureChanged= ($sPreviousVariableSignature!==$sCurrentVariableSignature); $bVarSignatureChanged = ($sPreviousVariableSignature !== $sCurrentVariableSignature);
} }
} }
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified))) if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified))) {
{
// Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature // Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature
$sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages); $sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages);
if ($bFileExists && !$bSetup) if ($bFileExists && !$bSetup) {
{
$sPrecompiledSignature = static::GetSignature($sThemeCssPath); $sPrecompiledSignature = static::GetSignature($sThemeCssPath);
} }
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature) if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature) {
{
touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time
} } else {
else
{
// Alas, we really need to recompile // Alas, we really need to recompile
// Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed // Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed
$sSignatureComment = $sSignatureComment =
@@ -381,14 +374,16 @@ $sActualSignature
*/ */
CSS; CSS;
if (!static::$oCompileCSSService) if (!static::$oCompileCSSService) {
{
static::$oCompileCSSService = new CompileCSSService(); static::$oCompileCSSService = new CompileCSSService();
} }
//store it again to change $version with latest compiled time //store it again to change $version with latest compiled time
SetupLog::Info("Compiling theme $sThemeId..."); SetupLog::Info("Compiling theme $sThemeId...");
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS(
$aThemeParametersWithVersion); $sTmpThemeScssContent,
$aImportsPaths,
$aThemeParametersWithVersion
);
SetupLog::Info("$sThemeId theme compilation done."); SetupLog::Info("$sThemeId theme compilation done.");
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters)); file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent); file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent);
@@ -413,13 +408,14 @@ CSS;
* @return string * @return string
* @throws \Exception * @throws \Exception
*/ */
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages) { public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages)
{
$aSignature = [ $aSignature = [
'variables' => md5(json_encode($aThemeParameters['variables'])), 'variables' => md5(json_encode($aThemeParameters['variables'])),
'stylesheets' => [], 'stylesheets' => [],
'variable_imports' => [], 'variable_imports' => [],
'images' => [], 'images' => [],
'utility_imports' => [] 'utility_imports' => [],
]; ];
$oFindStylesheetObject = new FindStylesheetObject(); $oFindStylesheetObject = new FindStylesheetObject();
@@ -461,8 +457,7 @@ CSS;
} }
} }
foreach ($aIncludedImages as $sImage) foreach ($aIncludedImages as $sImage) {
{
if (is_file($sImage)) { if (is_file($sImage)) {
$sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage); $sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage);
$aSignature['images'][$sUri] = md5_file($sImage); $aSignature['images'][$sUri] = md5_file($sImage);
@@ -489,7 +484,7 @@ CSS;
$aCompleteUrls = []; $aCompleteUrls = [];
$aToCompleteUrls = []; $aToCompleteUrls = [];
$aMissingVariables = []; $aMissingVariables = [];
$aFoundVariables = ['version'=>'']; $aFoundVariables = ['version' => ''];
$aMap = [ $aMap = [
'aCompleteUrls' => $aCompleteUrls, 'aCompleteUrls' => $aCompleteUrls,
'aToCompleteUrls' => $aToCompleteUrls, 'aToCompleteUrls' => $aToCompleteUrls,
@@ -497,14 +492,11 @@ CSS;
'aFoundVariables' => $aFoundVariables, 'aFoundVariables' => $aFoundVariables,
]; ];
foreach ($aStylesheetFiles as $sStylesheetFile) foreach ($aStylesheetFiles as $sStylesheetFile) {
{
$aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile); $aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile);
/** @var array $aVal */ /** @var array $aVal */
foreach($aMap as $key => $aVal) foreach ($aMap as $key => $aVal) {
{ if (array_key_exists($key, $aMap)) {
if (array_key_exists($key, $aMap))
{
$aMap[$key] = array_merge($aVal, $aRes[$key]); $aMap[$key] = array_merge($aVal, $aRes[$key]);
} }
} }
@@ -513,17 +505,14 @@ CSS;
$aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles); $aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles);
$aImages = []; $aImages = [];
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl) foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl) {
{
$sImg = $sUrl; $sImg = $sUrl;
if (preg_match("/(.*)\?/", $sUrl, $aMatches)) if (preg_match("/(.*)\?/", $sUrl, $aMatches)) {
{ $sImg = $aMatches[1];
$sImg=$aMatches[1];
} }
if (static::HasImageExtension($sImg) if (static::HasImageExtension($sImg)
&& ! array_key_exists($sImg, $aImages)) && ! array_key_exists($sImg, $aImages)) {
{
$sFilePath = utils::RealPath($sImg, APPROOT); $sFilePath = utils::RealPath($sImg, APPROOT);
if ($sFilePath !== false) { if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath); $sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
@@ -554,8 +543,8 @@ CSS;
*/ */
public static function CanonicalizePath($path) public static function CanonicalizePath($path)
{ {
$path = explode('/', str_replace('//','/', $path)); $path = explode('/', str_replace('//', '/', $path));
$stack = array(); $stack = [];
foreach ($path as $seg) { foreach ($path as $seg) {
if ($seg == '..') { if ($seg == '..') {
// Ignore this segment, remove last segment from stack // Ignore this segment, remove last segment from stack
@@ -585,25 +574,23 @@ CSS;
*/ */
public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile) public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile)
{ {
$sContent=""; $sContent = "";
foreach ($aStylesheetFile as $sStylesheetFile) foreach ($aStylesheetFile as $sStylesheetFile) {
{ if (is_file($sStylesheetFile)) {
if (is_file($sStylesheetFile)) $sContent .= '\n'.file_get_contents($sStylesheetFile);
{
$sContent .= '\n' . file_get_contents($sStylesheetFile);
} }
} }
$aMissingVariables=$aMap['aMissingVariables']; $aMissingVariables = $aMap['aMissingVariables'];
$aFoundVariables=$aMap['aFoundVariables']; $aFoundVariables = $aMap['aFoundVariables'];
$aToCompleteUrls=$aMap['aToCompleteUrls']; $aToCompleteUrls = $aMap['aToCompleteUrls'];
$aCompleteUrls=$aMap['aCompleteUrls']; $aCompleteUrls = $aMap['aCompleteUrls'];
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true); list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true);
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls); list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
$aMap['aMissingVariables']=$aMissingVariables; $aMap['aMissingVariables'] = $aMissingVariables;
$aMap['aFoundVariables']=$aFoundVariables; $aMap['aFoundVariables'] = $aFoundVariables;
$aMap['aToCompleteUrls']=$aToCompleteUrls; $aMap['aToCompleteUrls'] = $aToCompleteUrls;
$aMap['aCompleteUrls']=$aCompleteUrls; $aMap['aCompleteUrls'] = $aCompleteUrls;
return $aMap; return $aMap;
} }
@@ -619,43 +606,29 @@ CSS;
* *
* @return array * @return array
*/ */
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound=false) public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound = false)
{ {
$aNewMissingVars = []; $aNewMissingVars = [];
if (!empty($aMissingVariables)) if (!empty($aMissingVariables)) {
{ foreach ($aMissingVariables as $var) {
foreach ($aMissingVariables as $var) if (array_key_exists($var, $aThemeParametersVariables)) {
{
if (array_key_exists($var, $aThemeParametersVariables))
{
$aFoundVariables[$var] = $aThemeParametersVariables[$var]; $aFoundVariables[$var] = $aThemeParametersVariables[$var];
} } else {
else if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues)) {
{
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues))
{
$sValue = $aValues[1][0]; $sValue = $aValues[1][0];
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues)) if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues)) {
{
$sValue = trim($aSubValues[1][0], ' "\''); $sValue = trim($aSubValues[1][0], ' "\'');
} }
if (strpos($sValue, '$') === false) if (strpos($sValue, '$') === false) {
{
$aFoundVariables[$var] = $sValue; $aFoundVariables[$var] = $sValue;
} } else {
else{
$aNewMissingVars[] = $var; $aNewMissingVars[] = $var;
} }
} } else {
else if ($bForceEmptyValueWhenNotFound) {
{
if ($bForceEmptyValueWhenNotFound)
{
$aFoundVariables[$var] = ''; $aFoundVariables[$var] = '';
} } else {
else
{
$aNewMissingVars[] = $var; $aNewMissingVars[] = $var;
} }
} }
@@ -676,32 +649,23 @@ CSS;
*/ */
public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls) public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls)
{ {
if (!empty($aFoundVariables)) if (!empty($aFoundVariables)) {
{
$aFoundVariablesWithEmptyValue = []; $aFoundVariablesWithEmptyValue = [];
foreach ($aFoundVariables as $aFoundVariable => $sValue) foreach ($aFoundVariables as $aFoundVariable => $sValue) {
{
$aFoundVariablesWithEmptyValue[$aFoundVariable] = ''; $aFoundVariablesWithEmptyValue[$aFoundVariable] = '';
} }
foreach ($aToCompleteUrls as $sUrlTemplate) foreach ($aToCompleteUrls as $sUrlTemplate) {
{
unset($aToCompleteUrls[$sUrlTemplate]); unset($aToCompleteUrls[$sUrlTemplate]);
$sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables); $sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables);
if ($sResolvedUrl == false) if ($sResolvedUrl == false) {
{
$aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate; $aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate;
} } else {
else
{
$sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue); $sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue);
$aExplodedUri = explode('?', $sUri); $aExplodedUri = explode('?', $sUri);
if (empty($aExplodedUri)) if (empty($aExplodedUri)) {
{
$aCompleteUrls[$sUri] = $sResolvedUrl; $aCompleteUrls[$sUri] = $sResolvedUrl;
} } else {
else
{
$aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl; $aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl;
} }
} }
@@ -726,41 +690,31 @@ CSS;
$aMissingVariables = []; $aMissingVariables = [];
$aFoundVariables = []; $aFoundVariables = [];
if (is_file($sStylesheetFile)) if (is_file($sStylesheetFile)) {
{
$sContent = file_get_contents($sStylesheetFile); $sContent = file_get_contents($sStylesheetFile);
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches)) if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches)) {
{ foreach ($aMatches[1] as $path) {
foreach ($aMatches[1] as $path)
{
$iRemainingClosingParenthesisPos = strpos($path, ')'); $iRemainingClosingParenthesisPos = strpos($path, ')');
if ($iRemainingClosingParenthesisPos !== false){ if ($iRemainingClosingParenthesisPos !== false) {
$path = substr($path, 0, $iRemainingClosingParenthesisPos); $path = substr($path, 0, $iRemainingClosingParenthesisPos);
} }
if (!array_key_exists($path, $aCompleteUrls) if (!array_key_exists($path, $aCompleteUrls)
&& !array_key_exists($path, $aToCompleteUrls)) && !array_key_exists($path, $aToCompleteUrls)) {
{ if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars)) {
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars))
{
/** @var string $aCurrentVars */ /** @var string $aCurrentVars */
foreach ($aCurrentVars[1] as $var) foreach ($aCurrentVars[1] as $var) {
{ if (!array_key_exists($var, $aMissingVariables)) {
if (!array_key_exists($var, $aMissingVariables))
{
$aMissingVariables[$var] = $var; $aMissingVariables[$var] = $var;
} }
} }
$aToCompleteUrls[$path] = $path; $aToCompleteUrls[$path] = $path;
} } else {
else
{
$aCompleteUrls[$path] = trim($path, "\"'"); $aCompleteUrls[$path] = trim($path, "\"'");
} }
} }
} }
} }
if (!empty($aMissingVariables)) if (!empty($aMissingVariables)) {
{
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent); list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent);
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls); list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
} }
@@ -770,7 +724,7 @@ CSS;
'aCompleteUrls' => $aCompleteUrls, 'aCompleteUrls' => $aCompleteUrls,
'aToCompleteUrls' => $aToCompleteUrls, 'aToCompleteUrls' => $aToCompleteUrls,
'aMissingVariables' => $aMissingVariables, 'aMissingVariables' => $aMissingVariables,
'aFoundVariables' => $aFoundVariables 'aFoundVariables' => $aFoundVariables,
]; ];
} }
@@ -784,23 +738,21 @@ CSS;
*/ */
public static function ResolveUrl($sUrlTemplate, $aFoundVariables) public static function ResolveUrl($sUrlTemplate, $aFoundVariables)
{ {
$aPattern= []; $aPattern = [];
$aReplacement= []; $aReplacement = [];
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue) foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue) {
{
//XX + $key + YY //XX + $key + YY
$aPattern[]="/['\"]\s*\+\s*\\\$" . $aFoundVariable . "[\s\+]+\s*['\"]/"; $aPattern[] = "/['\"]\s*\+\s*\\\$".$aFoundVariable."[\s\+]+\s*['\"]/";
$aReplacement[]=$aFoundVariableValue; $aReplacement[] = $aFoundVariableValue;
//$key + YY //$key + YY
$aPattern[]="/\\\$" . $aFoundVariable. "[\s\+]+\s*['\"]/"; $aPattern[] = "/\\\$".$aFoundVariable."[\s\+]+\s*['\"]/";
$aReplacement[]=$aFoundVariableValue; $aReplacement[] = $aFoundVariableValue;
//XX + $key //XX + $key
$aPattern[]="/['\"]\s*[\+\s]+\\\$" . $aFoundVariable . "$/"; $aPattern[] = "/['\"]\s*[\+\s]+\\\$".$aFoundVariable."$/";
$aReplacement[]=$aFoundVariableValue; $aReplacement[] = $aFoundVariableValue;
} }
$sResolvedUrl=preg_replace($aPattern, $aReplacement, $sUrlTemplate); $sResolvedUrl = preg_replace($aPattern, $aReplacement, $sUrlTemplate);
if (strpos($sResolvedUrl, "+")!==false) if (strpos($sResolvedUrl, "+") !== false) {
{
return false; return false;
} }
return trim($sResolvedUrl, "\"'"); return trim($sResolvedUrl, "\"'");
@@ -814,17 +766,14 @@ CSS;
*/ */
private static function HasImageExtension($path) private static function HasImageExtension($path)
{ {
foreach (static::IMAGE_EXTENSIONS as $sExt) foreach (static::IMAGE_EXTENSIONS as $sExt) {
{ if (endsWith($path, $sExt)) {
if (endsWith($path, $sExt))
{
return true; return true;
} }
} }
return false; return false;
} }
/** /**
* @since 3.0.0 N°2982 * @since 3.0.0 N°2982
* Extract the signature for a generated CSS file. * Extract the signature for a generated CSS file.
@@ -843,16 +792,13 @@ CSS;
$iCount = 0; $iCount = 0;
$sPreviousLine = ''; $sPreviousLine = '';
$hFile = @fopen($sFilepath, "r"); $hFile = @fopen($sFilepath, "r");
if ($hFile !== false) if ($hFile !== false) {
{
$sLine = ''; $sLine = '';
do do {
{
$iCount++; $iCount++;
$sPreviousLine = $sLine; $sPreviousLine = $sLine;
$sLine = rtrim(fgets($hFile)); // Remove the trailing \n $sLine = rtrim(fgets($hFile)); // Remove the trailing \n
} } while (($sLine !== false) && ($sLine != '=== SIGNATURE END ===') && ($iCount <= 100));
while (($sLine !== false) && ($sLine != '=== SIGNATURE END ===') && ($iCount <= 100));
fclose($hFile); fclose($hFile);
} }
return $sPreviousLine; return $sPreviousLine;
@@ -867,8 +813,7 @@ CSS;
public static function GetVarSignature($JsonSignature) public static function GetVarSignature($JsonSignature)
{ {
$aJsonArray = json_decode($JsonSignature, true); $aJsonArray = json_decode($JsonSignature, true);
if (array_key_exists('variables', $aJsonArray)) if (array_key_exists('variables', $aJsonArray)) {
{
return $aJsonArray['variables']; return $aJsonArray['variables'];
} }
return false; return false;
@@ -892,23 +837,22 @@ CSS;
$oFindStylesheetObject->ResetLastStyleSheet(); $oFindStylesheetObject->ResetLastStyleSheet();
} }
foreach($aImportsPaths as $sPath) foreach ($aImportsPaths as $sPath) {
{
$sAlterableFileURI = $sFileURI; $sAlterableFileURI = $sFileURI;
$sFilePath = $sPath.'/'.$sAlterableFileURI; $sFilePath = $sPath.'/'.$sAlterableFileURI;
$sImportedFile = realpath($sFilePath); $sImportedFile = realpath($sFilePath);
if ($sImportedFile === false){ if ($sImportedFile === false) {
// Handle shortcut syntax : @import "typo" ; // Handle shortcut syntax : @import "typo" ;
// file matched: typo.scss // file matched: typo.scss
$sFilePath2 = "$sFilePath.scss"; $sFilePath2 = "$sFilePath.scss";
$sImportedFile = realpath($sFilePath2); $sImportedFile = realpath($sFilePath2);
if ($sImportedFile){ if ($sImportedFile) {
self::FindStylesheetFile("$sAlterableFileURI.scss", [ $sPath ], $oFindStylesheetObject, $bImports); self::FindStylesheetFile("$sAlterableFileURI.scss", [ $sPath ], $oFindStylesheetObject, $bImports);
$sImportedFile = false; $sImportedFile = false;
} }
} }
if ($sImportedFile === false){ if ($sImportedFile === false) {
// Handle shortcut syntax : @import "typo" ; // Handle shortcut syntax : @import "typo" ;
// file matched: _typo.scss // file matched: _typo.scss
$sShortCut = substr($sFilePath, strrpos($sFilePath, '/') + 1); $sShortCut = substr($sFilePath, strrpos($sFilePath, '/') + 1);
@@ -918,11 +862,10 @@ CSS;
} }
if ((file_exists($sImportedFile)) if ((file_exists($sImportedFile))
&& (!$oFindStylesheetObject->AlreadyFetched($sImportedFile))) && (!$oFindStylesheetObject->AlreadyFetched($sImportedFile))) {
{ if ($bImports) {
if ($bImports){
$oFindStylesheetObject->AddImport($sAlterableFileURI, $sImportedFile); $oFindStylesheetObject->AddImport($sAlterableFileURI, $sImportedFile);
}else{ } else {
$oFindStylesheetObject->AddStylesheet($sAlterableFileURI, $sImportedFile); $oFindStylesheetObject->AddStylesheet($sAlterableFileURI, $sImportedFile);
} }
$oFindStylesheetObject->UpdateLastModified($sImportedFile); $oFindStylesheetObject->UpdateLastModified($sImportedFile);
@@ -930,8 +873,8 @@ CSS;
//Regexp matching on all included scss files : @import 'XXX.scss'; //Regexp matching on all included scss files : @import 'XXX.scss';
$sDirUri = dirname($sAlterableFileURI); $sDirUri = dirname($sAlterableFileURI);
preg_match_all('/@import \s*[\"\']([^\"\']*)\s*[\"\']\s*;/', file_get_contents($sImportedFile), $aMatches); preg_match_all('/@import \s*[\"\']([^\"\']*)\s*[\"\']\s*;/', file_get_contents($sImportedFile), $aMatches);
if ( (is_array($aMatches)) && (count($aMatches)!==0) ){ if ((is_array($aMatches)) && (count($aMatches) !== 0)) {
foreach ($aMatches[1] as $sImportedFile){ foreach ($aMatches[1] as $sImportedFile) {
self::FindStylesheetFile("$sDirUri/$sImportedFile", [ $sPath ], $oFindStylesheetObject, true); self::FindStylesheetFile("$sDirUri/$sImportedFile", [ $sPath ], $oFindStylesheetObject, true);
} }
} }
@@ -952,8 +895,7 @@ CSS;
{ {
$iPos = strrpos($sSubject, $sSearch); $iPos = strrpos($sSubject, $sSearch);
if($iPos !== false) if ($iPos !== false) {
{
$sSubject = substr_replace($sSubject, $sReplace, $iPos, strlen($sSearch)); $sSubject = substr_replace($sSubject, $sReplace, $iPos, strlen($sSearch));
} }
@@ -982,18 +924,14 @@ CSS;
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp, $aImportsPaths) public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp, $aImportsPaths)
{ {
$aThemeParametersVariable = []; $aThemeParametersVariable = [];
if (array_key_exists('variables', $aThemeParameters)) if (array_key_exists('variables', $aThemeParameters)) {
{ if (is_array($aThemeParameters['variables'])) {
if (is_array($aThemeParameters['variables']))
{
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']); $aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
} }
} }
if (array_key_exists('variable_imports', $aThemeParameters)) if (array_key_exists('variable_imports', $aThemeParameters)) {
{ if (is_array($aThemeParameters['variable_imports'])) {
if (is_array($aThemeParameters['variable_imports']))
{
$aThemeParametersVariable = array_merge($aThemeParametersVariable, static::GetVariablesFromFile($aThemeParameters['variable_imports'], $aImportsPaths)); $aThemeParametersVariable = array_merge($aThemeParametersVariable, static::GetVariablesFromFile($aThemeParameters['variable_imports'], $aImportsPaths));
} }
} }
@@ -1009,11 +947,11 @@ CSS;
* @return array * @return array
* @since 3.0.0 N°3593 * @since 3.0.0 N°3593
*/ */
public static function GetVariablesFromFile($aVariableFiles, $aImportsPaths){ public static function GetVariablesFromFile($aVariableFiles, $aImportsPaths)
{
$aVariablesResults = []; $aVariablesResults = [];
foreach ($aVariableFiles as $sVariableFile) foreach ($aVariableFiles as $sVariableFile) {
{ foreach ($aImportsPaths as $sPath) {
foreach($aImportsPaths as $sPath) {
$sFilePath = $sPath.'/'.$sVariableFile; $sFilePath = $sPath.'/'.$sVariableFile;
$sImportedFile = realpath($sFilePath); $sImportedFile = realpath($sFilePath);
if ($sImportedFile !== false) { if ($sImportedFile !== false) {
@@ -1029,9 +967,8 @@ CSS;
} }
} }
} }
array_map( function($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults ); array_map(function ($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults);
return $aVariablesResults; return $aVariablesResults;
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -29,7 +30,8 @@ class ThemeHandlerService
{ {
} }
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){ public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
{
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp, $aThemeParameters, $aImportsPaths, $sWorkingPath); return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp, $aThemeParameters, $aImportsPaths, $sWorkingPath);
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -54,8 +55,8 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
*/ */
class UIExtKeyWidget class UIExtKeyWidget
{ {
const ENUM_OUTPUT_FORMAT_CSV = 'csv'; public const ENUM_OUTPUT_FORMAT_CSV = 'csv';
const ENUM_OUTPUT_FORMAT_JSON = 'json'; public const ENUM_OUTPUT_FORMAT_JSON = 'json';
protected $iId; protected $iId;
protected $sTargetClass; protected $sTargetClass;
@@ -87,10 +88,20 @@ class UIExtKeyWidget
* @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat * @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat
*/ */
public static function DisplayFromAttCode( public static function DisplayFromAttCode(
$oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $oPage,
$aArgs = [], $bSearchMode = false, &$sInputType = '' $sAttCode,
) $sClass,
{ $sTitle,
$oAllowedValues,
$value,
$iInputId,
$bMandatory,
$sFieldName = '',
$sFormPrefix = '',
$aArgs = [],
$bSearchMode = false,
&$sInputType = ''
) {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sTargetClass = $oAttDef->GetTargetClass(); $sTargetClass = $oAttDef->GetTargetClass();
$iMaxComboLength = $oAttDef->GetMaximumComboLength(); $iMaxComboLength = $oAttDef->GetMaximumComboLength();
@@ -102,8 +113,7 @@ class UIExtKeyWidget
} }
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode); $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
if (!$bSearchMode) { if (!$bSearchMode) {
switch ($sDisplayStyle) switch ($sDisplayStyle) {
{
case 'radio': case 'radio':
case 'radio_horizontal': case 'radio_horizontal':
case 'radio_vertical': case 'radio_vertical':
@@ -114,12 +124,38 @@ class UIExtKeyWidget
case 'select': case 'select':
case 'list': case 'list':
default: default:
return $oWidget->DisplaySelect($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, return $oWidget->DisplaySelect(
$bMandatory, $sFieldName, $sFormPrefix, $aArgs, $sInputType); $oPage,
$iMaxComboLength,
$bAllowTargetCreation,
$sTitle,
$oAllowedValues,
$value,
$bMandatory,
$sFieldName,
$sFormPrefix,
$aArgs,
$sInputType
);
} }
} else { } else {
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, return $oWidget->Display(
$bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle, true, $sInputType); $oPage,
$iMaxComboLength,
$bAllowTargetCreation,
$sTitle,
$oAllowedValues,
$value,
$iInputId,
$bMandatory,
$sFieldName,
$sFormPrefix,
$aArgs,
null,
$sDisplayStyle,
true,
$sInputType
);
} }
} }
@@ -158,7 +194,7 @@ class UIExtKeyWidget
* @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete * @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete
* @since 3.0.0 N°3750 new $sInputType parameter * @since 3.0.0 N°3750 new $sInputType parameter
*/ */
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), &$sInputType = '') public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = [], &$sInputType = '')
{ {
$sTitle = addslashes($sTitle); $sTitle = addslashes($sTitle);
$oPage->LinkScriptFromAppRoot('js/extkeywidget.js'); $oPage->LinkScriptFromAppRoot('js/extkeywidget.js');
@@ -194,7 +230,7 @@ class UIExtKeyWidget
$bIsAutocomplete = $oAllowedValues->CountExceeds($iMaxComboLength); $bIsAutocomplete = $oAllowedValues->CountExceeds($iMaxComboLength);
$sWrapperCssClass = $bIsAutocomplete ? 'ibo-input-select-autocomplete-wrapper' : 'ibo-input-select-wrapper'; $sWrapperCssClass = $bIsAutocomplete ? 'ibo-input-select-autocomplete-wrapper' : 'ibo-input-select-wrapper';
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey ibo-input-wrapper ibo-input-select-wrapper--with-buttons $sWrapperCssClass\" data-attcode=\"".$this->sAttCode."\" data-validation=\"untouched\" data-accessibility-selectize-label=\"$sTitle\">"; $sHTMLValue = "<div class=\"field_input_zone field_input_extkey ibo-input-wrapper ibo-input-select-wrapper--with-buttons $sWrapperCssClass\" data-attcode=\"".$this->sAttCode."\" data-validation=\"untouched\" data-accessibility-selectize-label=\"$sTitle\">";
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count. // We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$bIsAutocomplete) { if (!$bIsAutocomplete) {
// Discrete list of values, use a SELECT or RADIO buttons depending on the config // Discrete list of values, use a SELECT or RADIO buttons depending on the config
@@ -281,21 +317,17 @@ EOF
$oPage->add_ready_script("$('#$this->iId').one('validate', function() { $(this).trigger('change'); } );"); $oPage->add_ready_script("$('#$this->iId').one('validate', function() { $(this).trigger('change'); } );");
} }
$sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\">"; $sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\">";
} } else {
else
{
// Too many choices, use an autocomplete // Too many choices, use an autocomplete
// Check that the given value is allowed // Check that the given value is allowed
$oSearch = $oAllowedValues->GetFilter(); $oSearch = $oAllowedValues->GetFilter();
$oSearch->AddCondition('id', $value); $oSearch->AddCondition('id', $value);
$oSet = new DBObjectSet($oSearch); $oSet = new DBObjectSet($oSearch);
if ($oSet->Count() == 0) if ($oSet->Count() == 0) {
{
$value = null; $value = null;
} }
if (is_null($value) || ($value == 0)) // Null values are displayed as '' if (is_null($value) || ($value == 0)) { // Null values are displayed as ''
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : ''; $sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
} else { } else {
$sDisplayValue = $this->GetObjectName($value); $sDisplayValue = $this->GetObjectName($value);
@@ -376,36 +408,30 @@ JS
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">"; $sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">";
if (is_null($oAllowedValues)) if (is_null($oAllowedValues)) {
{
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData()); $oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count. // We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$oAllowedValues->CountExceeds($iMaxComboLength)) if (!$oAllowedValues->CountExceeds($iMaxComboLength)) {
{
// Discrete list of values, use a SELECT or RADIO buttons depending on the config // Discrete list of values, use a SELECT or RADIO buttons depending on the config
$sValidationField = null; $sValidationField = null;
$bVertical = ($sDisplayStyle != 'radio_horizontal'); $bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false; $bExtensions = false;
$oAllowedValues->Rewind(); $oAllowedValues->Rewind();
$aAllowedValues = array(); $aAllowedValues = [];
while($oObj = $oAllowedValues->Fetch()) while ($oObj = $oAllowedValues->Fetch()) {
{
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName(); $aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
} }
$sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField); $sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField);
$aEventsList[] ='change'; $aEventsList[] = 'change';
} } else {
else
{
$sHTMLValue .= "unable to display. Too much values"; $sHTMLValue .= "unable to display. Too much values";
} }
$sHTMLValue .= '<div class="ibo-input-select--action-buttons">'; $sHTMLValue .= '<div class="ibo-input-select--action-buttons">';
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) {
{
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>"; $sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<JS
@@ -416,8 +442,7 @@ JS
JS JS
); );
} }
if ($bCreate && $bExtensions) if ($bCreate && $bExtensions) {
{
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject'; $sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>"; $sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
@@ -471,7 +496,7 @@ JS
* *
* @since 3.0.0 N°3750 new $sInputType parameter * @since 3.0.0 N°3750 new $sInputType parameter
*/ */
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true, &$sInputType = '') public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = [], $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true, &$sInputType = '')
{ {
if (!is_null($bSearchMode)) { if (!is_null($bSearchMode)) {
$this->bSearchMode = $bSearchMode; $this->bSearchMode = $bSearchMode;
@@ -521,7 +546,7 @@ JS
$bVertical = ($sDisplayStyle != 'radio_horizontal'); $bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false; $bExtensions = false;
$oAllowedValues->Rewind(); $oAllowedValues->Rewind();
$aAllowedValues = array(); $aAllowedValues = [];
while ($oObj = $oAllowedValues->Fetch()) { while ($oObj = $oAllowedValues->Fetch()) {
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName(); $aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
} }
@@ -568,22 +593,22 @@ EOF
} }
$sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n"; $sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n";
} }
$sHTMLValue .= "</select>\n"; $sHTMLValue .= "</select>\n";
$sHTMLValue .= "</div>\n"; $sHTMLValue .= "</div>\n";
$sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_RAW; $sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_RAW;
if (($this->bSearchMode) && $bSearchMultiple) { if (($this->bSearchMode) && $bSearchMultiple) {
$sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_MULTIPLE_CHOICES; $sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_MULTIPLE_CHOICES;
$aOptions = array( $aOptions = [
'header' => true, 'header' => true,
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'), 'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'), 'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
'noneSelectedText' => Dict::S('UI:SearchValue:Any'), 'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
'selectedText' => Dict::S('UI:SearchValue:NbSelected'), 'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
'selectedList' => 1, 'selectedList' => 1,
); ];
$sJSOptions = json_encode($aOptions); $sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);"); $oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
} }
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
@@ -606,8 +631,7 @@ EOF
$value = null; $value = null;
} }
if (is_null($value) || ($value == 0)) // Null values are displayed as '' if (is_null($value) || ($value == 0)) { // Null values are displayed as ''
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : ''; $sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
} else { } else {
$sDisplayValue = $this->GetObjectName($value); $sDisplayValue = $this->GetObjectName($value);
@@ -673,20 +697,22 @@ JS
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
/** @var \DBObject $oCurrObject */ /** @var \DBObject $oCurrObject */
$aArgs = $oCurrObject->ToArgsForQuery(); $aArgs = $oCurrObject->ToArgsForQuery();
$aParams = array('query_params' => $aArgs); $aParams = ['query_params' => $aArgs];
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs); $oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
$oFilter = $oSet->GetFilter(); $oFilter = $oSet->GetFilter();
} else if (!empty($this->sFilter)) { } elseif (!empty($this->sFilter)) {
$aParams = array(); $aParams = [];
$oFilter = DBObjectSearch::FromOQL($this->sFilter); $oFilter = DBObjectSearch::FromOQL($this->sFilter);
} else { } else {
$aParams = array(); $aParams = [];
$oFilter = new DBObjectSearch($this->sTargetClass); $oFilter = new DBObjectSearch($this->sTargetClass);
} }
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams); $oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, 'dtc_'.$this->iId, $oPage->AddUiBlock($oBlock->GetDisplay(
array( $oPage,
'dtc_'.$this->iId,
[
'menu' => false, 'menu' => false,
'currentId' => $this->iId, 'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}", 'table_id' => "dr_{$this->iId}",
@@ -694,12 +720,13 @@ JS
'selection_mode' => true, 'selection_mode' => true,
'selection_type' => 'single', 'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId.'_results', 'cssCount' => '#count_'.$this->iId.'_results',
) ]
)); ));
$sCancel = Dict::S('UI:Button:Cancel'); $sCancel = Dict::S('UI:Button:Cancel');
$sOK = Dict::S('UI:Button:Ok'); $sOK = Dict::S('UI:Button:Ok');
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm'); $sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$oPage->add(<<<HTML $oPage->add(
<<<HTML
<form id="fr_{$this->iId}" OnSubmit="return oACWidget_{$this->iId}.DoOk();"> <form id="fr_{$this->iId}" OnSubmit="return oACWidget_{$this->iId}.DoOk();">
<div id="dr_{$this->iId}"> <div id="dr_{$this->iId}">
<div><p>{$sEmptyList}</p></div> <div><p>{$sEmptyList}</p></div>
@@ -711,7 +738,8 @@ HTML
); );
$sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle)); $sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle));
$oPage->add_ready_script(<<<JS $oPage->add_ready_script(
<<<JS
$('#ac_dlg_{$this->iId}').dialog({ $('#ac_dlg_{$this->iId}').dialog({
width: $(window).width()*0.8, width: $(window).width()*0.8,
height: $(window).height()*0.8, height: $(window).height()*0.8,
@@ -751,14 +779,12 @@ JS
*/ */
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null) public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
{ {
if (is_null($sFilter)) if (is_null($sFilter)) {
{
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$oFilter = DBObjectSearch::FromOQL($sFilter); $oFilter = DBObjectSearch::FromOQL($sFilter);
if (strlen($sRemoteClass) > 0) if (strlen($sRemoteClass) > 0) {
{
$oFilter->ChangeClass($sRemoteClass); $oFilter->ChangeClass($sRemoteClass);
} }
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
@@ -766,26 +792,26 @@ JS
// Current extkey value, so we can display event if it is not available anymore (eg. archived). // Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode); $iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId))); $oBlock = new DisplayBlock($oFilter, 'list_search', false, ['query_params' => ['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId]]);
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId.'_results', 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results $oBlock->Display($oP, $this->iId.'_results', ['this' => $oObj, 'cssCount' => '#count_'.$this->iId.'_results', 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode]); // Don't display the 'Actions' menu on the results
} }
/** /**
* Search for objects to be selected * Search for objects to be selected
* *
* @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values * @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
* @param DBObject $oObj The current object for the OQL context * @param DBObject $oObj The current object for the OQL context
* @param string $sContains The text of the autocomplete to filter the results * @param string $sContains The text of the autocomplete to filter the results
* @param string $sOutputFormat * @param string $sOutputFormat
* @param null $sOperation for the values @see ValueSetObjects->LoadValues() not used since 3.0.0 * @param null $sOperation for the values @see ValueSetObjects->LoadValues() not used since 3.0.0
* *
* @throws CoreException * @throws CoreException
* @throws OQLException * @throws OQLException
* *
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility * @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
*/ */
public function AutoComplete(WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null ) public function AutoComplete(WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
{ {
if (is_null($sFilter)) { if (is_null($sFilter)) {
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
@@ -799,38 +825,32 @@ JS
$oValuesSet->SetSort(false); $oValuesSet->SetSort(false);
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oValuesSet->SetLimit($iMax); $oValuesSet->SetLimit($iMax);
$aValuesStartWith = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'start_with'); $aValuesStartWith = $oValuesSet->GetValuesForAutocomplete(['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId], $sContains, 'start_with');
asort($aValuesStartWith); asort($aValuesStartWith);
$aValues = $aValuesStartWith; $aValues = $aValuesStartWith;
if (sizeof($aValues) < $iMax) { if (sizeof($aValues) < $iMax) {
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains'); $aValuesContains = $oValuesSet->GetValuesForAutocomplete(['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId], $sContains, 'contains');
asort($aValuesContains); asort($aValuesContains);
$iSize = sizeof($aValues); $iSize = sizeof($aValues);
foreach ($aValuesContains as $sKey => $sFriendlyName) foreach ($aValuesContains as $sKey => $sFriendlyName) {
{ if (!isset($aValues[$sKey])) {
if (!isset($aValues[$sKey]))
{
$aValues[$sKey] = $sFriendlyName; $aValues[$sKey] = $sFriendlyName;
if (++$iSize >= $iMax) if (++$iSize >= $iMax) {
{
break; break;
} }
} }
} }
} } elseif (!in_array($sContains, $aValues)) {
elseif (!in_array($sContains, $aValues)) $aValuesEquals = $oValuesSet->GetValuesForAutocomplete(['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId], $sContains, 'equals');
{
$aValuesEquals = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals');
// Note: Here we cannot use array_merge as it would reindex the numeric keys starting from 0 when keys are actually the objects ID. // Note: Here we cannot use array_merge as it would reindex the numeric keys starting from 0 when keys are actually the objects ID.
// As a workaround we use array_replace as it does preserve numeric keys. It's ok if some values from $aValuesEquals are replaced with values from $aValues as they contain the same data. // As a workaround we use array_replace as it does preserve numeric keys. It's ok if some values from $aValuesEquals are replaced with values from $aValues as they contain the same data.
$aValues = array_replace($aValuesEquals, $aValues); $aValues = array_replace($aValuesEquals, $aValues);
} }
switch($sOutputFormat) switch ($sOutputFormat) {
{
case static::ENUM_OUTPUT_FORMAT_JSON: case static::ENUM_OUTPUT_FORMAT_JSON:
$aJsonMap = array(); $aJsonMap = [];
foreach ($aValues as $sKey => $aValue) { foreach ($aValues as $sKey => $aValue) {
$aElt = ['value' => $sKey, 'label' => utils::EscapeHtml($aValue['label']), 'obsolescence_flag' => $aValue['obsolescence_flag']]; $aElt = ['value' => $sKey, 'label' => utils::EscapeHtml($aValue['label']), 'obsolescence_flag' => $aValue['obsolescence_flag']];
if ($aValue['additional_field'] != '') { if ($aValue['additional_field'] != '') {
@@ -851,8 +871,7 @@ JS
break; break;
case static::ENUM_OUTPUT_FORMAT_CSV: case static::ENUM_OUTPUT_FORMAT_CSV:
foreach($aValues as $sKey => $aValue) foreach ($aValues as $sKey => $aValue) {
{
$oP->add(trim($aValue['label'])."\t".$sKey."\n"); $oP->add(trim($aValue['label'])."\t".$sKey."\n");
} }
break; break;
@@ -874,7 +893,7 @@ JS
*/ */
public function GetObjectName($iObjId, $sFormAttCode = null) public function GetObjectName($iObjId, $sFormAttCode = null)
{ {
$aModifierProps = array(); $aModifierProps = [];
$aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode; $aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode;
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps); $oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps);
@@ -884,9 +903,7 @@ JS
} else { } else {
return $oObj->Get($sFormAttCode); return $oObj->Get($sFormAttCode);
} }
} } else {
else
{
return ''; return '';
} }
} }
@@ -902,30 +919,29 @@ JS
*/ */
public function GetClassSelectionForm(WebPage $oPage) public function GetClassSelectionForm(WebPage $oPage)
{ {
// For security reasons: check that the "proposed" class is actually a subclass of the linked class // For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class // and that the current user is allowed to create objects of this class
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass, ENUM_CHILD_CLASSES_ALL); $aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass, ENUM_CHILD_CLASSES_ALL);
$aPossibleClasses = array(); $aPossibleClasses = [];
foreach($aSubClasses as $sCandidateClass) foreach ($aSubClasses as $sCandidateClass) {
{ if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) $aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
{ }
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass); }
}
}
$sClassLabel = MetaModel::GetName($this->sTargetClass); $sClassLabel = MetaModel::GetName($this->sTargetClass);
$sDialogTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);; $sDialogTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
$oBlock = UIContentBlockUIBlockFactory::MakeStandard('ac_create_'.$this->iId,['ibo-is-visible']); ;
$oBlock = UIContentBlockUIBlockFactory::MakeStandard('ac_create_'.$this->iId, ['ibo-is-visible']);
$oPage->AddSubBlock($oBlock); $oPage->AddSubBlock($oBlock);
$oClassForm = FormUIBlockFactory::MakeStandard(); $oClassForm = FormUIBlockFactory::MakeStandard();
$oBlock->AddSubBlock($oClassForm); $oBlock->AddSubBlock($oClassForm);
$oClassForm->AddSubBlock(cmdbAbstractObject::DisplayBlockSelectClassToCreate( $sClassLabel, $this->sTargetClass, $aPossibleClasses)); $oClassForm->AddSubBlock(cmdbAbstractObject::DisplayBlockSelectClassToCreate($sClassLabel, $this->sTargetClass, $aPossibleClasses));
$sDialogTitleEscaped = addslashes($sDialogTitle); $sDialogTitleEscaped = addslashes($sDialogTitle);
$oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitleEscaped'});\n"); $oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitleEscaped'});\n");
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').removeAttr('onsubmit');"); $oPage->add_ready_script("$('#ac_create_{$this->iId} form').removeAttr('onsubmit');");
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').find('select').attr('id', 'ac_create_{$this->iId}_select');"); $oPage->add_ready_script("$('#ac_create_{$this->iId} form').find('select').attr('id', 'ac_create_{$this->iId}_select');");
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);"); $oPage->add_ready_script("$('#ac_create_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
} }
/** /**
@@ -941,16 +957,14 @@ JS
$oAppContext->InitObjectFromContext($oNewObj); $oAppContext->InitObjectFromContext($oNewObj);
$oNewObj->PrefillForm('creation_from_extkey', $aPrefillFormParam); $oNewObj->PrefillForm('creation_from_extkey', $aPrefillFormParam);
// 2nd set the default values from the constraint on the external key... if any // 2nd set the default values from the constraint on the external key... if any
if ( ($oCurrObject != null) && ($this->sAttCode != '')) if (($oCurrObject != null) && ($this->sAttCode != '')) {
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
$aParams = array('this' => $oCurrObject); $aParams = ['this' => $oCurrObject];
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams); $oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
$aConsts = $oSet->ListConstantFields(); $aConsts = $oSet->ListConstantFields();
$sClassAlias = $oSet->GetFilter()->GetClassAlias(); $sClassAlias = $oSet->GetFilter()->GetClassAlias();
if (isset($aConsts[$sClassAlias])) if (isset($aConsts[$sClassAlias])) {
{ foreach ($aConsts[$sClassAlias] as $sAttCode => $value) {
foreach($aConsts[$sClassAlias] as $sAttCode => $value) {
$oNewObj->Set($sAttCode, $value); $oNewObj->Set($sAttCode, $value);
} }
} }
@@ -962,32 +976,35 @@ JS
$sClassLabel = MetaModel::GetName($this->sTargetClass); $sClassLabel = MetaModel::GetName($this->sTargetClass);
$sHeaderTitleEscaped = utils::EscapeHtml(Dict::Format('UI:CreationTitle_Class', $sClassLabel)); $sHeaderTitleEscaped = utils::EscapeHtml(Dict::Format('UI:CreationTitle_Class', $sClassLabel));
$oPage->add(<<<HTML $oPage->add(
<<<HTML
<div id="ac_create_{$this->iId}" title="{$sHeaderTitleEscaped}"> <div id="ac_create_{$this->iId}" title="{$sHeaderTitleEscaped}">
<div id="dcr_{$this->iId}"> <div id="dcr_{$this->iId}">
HTML HTML
); );
$aFormExtraParams = array( $aFormExtraParams = [
'formPrefix' => $this->iId, 'formPrefix' => $this->iId,
'noRelations' => true, 'noRelations' => true,
); ];
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context // Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
FormHelper::DisableAttributeBlobInputs($this->sTargetClass, $aFormExtraParams); FormHelper::DisableAttributeBlobInputs($this->sTargetClass, $aFormExtraParams);
if(FormHelper::HasMandatoryAttributeBlobInputs($oNewObj)){ if (FormHelper::HasMandatoryAttributeBlobInputs($oNewObj)) {
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE)); $oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
} }
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), $aFormExtraParams); cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, [], $aFormExtraParams);
$oPage->add(<<<HTML $oPage->add(
<<<HTML
</div> </div>
</div> </div>
HTML HTML
); );
$oPage->add_ready_script(<<<JS $oPage->add_ready_script(
<<<JS
$('#ac_create_{$this->iId}').dialog({ width: $(window).width() * 0.6, height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true}); $('#ac_create_{$this->iId}').dialog({ width: $(window).width() * 0.6, height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true});
$('#dcr_{$this->iId} form').removeAttr('onsubmit'); $('#dcr_{$this->iId} form').removeAttr('onsubmit');
$('#dcr_{$this->iId} form').find('button[type="submit"]').on('click', oACWidget_{$this->iId}.DoCreateObject); $('#dcr_{$this->iId} form').find('button[type="submit"]').on('click', oACWidget_{$this->iId}.DoCreateObject);
@@ -1003,14 +1020,13 @@ JS
$sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass))); $sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass)));
$oPage->add('<div id="dlg_tree_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div style="margin-bottom:5px;" id="tree_'.$this->iId.'">'); $oPage->add('<div id="dlg_tree_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div style="margin-bottom:5px;" id="tree_'.$this->iId.'">');
$oPage->add('<table style="width:100%"><tr><td>'); $oPage->add('<table style="width:100%"><tr><td>');
if (is_null($sFilter)) if (is_null($sFilter)) {
{
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$oFilter = DBObjectSearch::FromOQL($sFilter); $oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue)); $oSet = new DBObjectSet($oFilter, [], ['this' => $oObj, 'current_extkey_id' => $currValue]);
$oSet->SetShowObsoleteData(utils::ShowObsoleteData()); $oSet->SetShowObsoleteData(utils::ShowObsoleteData());
@@ -1020,17 +1036,17 @@ JS
$oPage->add('</td></tr></table>'); $oPage->add('</td></tr></table>');
$oPage->add('</div>'); $oPage->add('</div>');
if ($bHasChildLeafs) if ($bHasChildLeafs) {
{
$oPage->add('<span class="treecontrol ibo-button-group" id="treecontrolid"><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></span>'); $oPage->add('<span class="treecontrol ibo-button-group" id="treecontrolid"><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></span>');
} }
$oPage->add('</div></div>'); $oPage->add('</div></div>');
$sOkButtonLabel = Dict::S('UI:Button:Ok'); $sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\n"); $oPage->add_ready_script("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\n");
$oPage->add_ready_script(<<<JS $oPage->add_ready_script(
<<<JS
$('#dlg_tree_$this->iId').dialog({ $('#dlg_tree_$this->iId').dialog({
width: 'auto', width: 'auto',
height: 'auto', height: 'auto',
@@ -1069,8 +1085,7 @@ JS
*/ */
public function DoCreateObject($oPage) public function DoCreateObject($oPage)
{ {
try try {
{
$oObj = MetaModel::NewObject($this->sTargetClass); $oObj = MetaModel::NewObject($this->sTargetClass);
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId); $aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0) { if (count($aErrors) == 0) {
@@ -1088,13 +1103,12 @@ JS
]); ]);
$oObj->DBInsertNoReload(); $oObj->DBInsertNoReload();
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey()); return ['name' => $oObj->GetName(), 'id' => $oObj->GetKey()];
} else { } else {
return array('error' => implode(' ', $aErrors), 'id' => 0); return ['error' => implode(' ', $aErrors), 'id' => 0];
} }
} } catch (Exception $e) {
catch (Exception $e) { return ['error' => $e->getMessage(), 'id' => 0];
return array('error' => $e->getMessage(), 'id' => 0);
} }
} }
@@ -1110,32 +1124,27 @@ JS
* @throws \CoreUnexpectedValue * @throws \CoreUnexpectedValue
* @throws \MySQLException * @throws \MySQLException
*/ */
function DumpTree($oP, $oSet, $sParentAttCode, $currValue) public function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
{ {
$aTree = array(); $aTree = [];
$aNodes = array(); $aNodes = [];
while($oObj = $oSet->Fetch()) while ($oObj = $oSet->Fetch()) {
{
$iParentId = $oObj->Get($sParentAttCode); $iParentId = $oObj->Get($sParentAttCode);
if (!isset($aTree[$iParentId])) if (!isset($aTree[$iParentId])) {
{ $aTree[$iParentId] = [];
$aTree[$iParentId] = array();
} }
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName(); $aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
$aNodes[$oObj->GetKey()] = $oObj; $aNodes[$oObj->GetKey()] = $oObj;
} }
$aParents = array_keys($aTree); $aParents = array_keys($aTree);
$aRoots = array(); $aRoots = [];
foreach($aParents as $id) foreach ($aParents as $id) {
{ if (!array_key_exists($id, $aNodes)) {
if (!array_key_exists($id, $aNodes))
{
$aRoots[] = $id; $aRoots[] = $id;
} }
} }
foreach($aRoots as $iRootId) foreach ($aRoots as $iRootId) {
{
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue); $this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
} }
@@ -1143,28 +1152,22 @@ JS
return !$bHasOnlyRootNodes; return !$bHasOnlyRootNodes;
} }
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue) public function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
{ {
$bSelect = true; $bSelect = true;
$bMultiple = false; $bMultiple = false;
$sSelect = ''; $sSelect = '';
if (array_key_exists($iRootId, $aTree)) if (array_key_exists($iRootId, $aTree)) {
{
$aSortedRoots = $aTree[$iRootId]; $aSortedRoots = $aTree[$iRootId];
asort($aSortedRoots); asort($aSortedRoots);
$oP->add("<ul>\n"); $oP->add("<ul>\n");
$fUniqueId = microtime(true); $fUniqueId = microtime(true);
foreach($aSortedRoots as $id => $sName) foreach ($aSortedRoots as $id => $sName) {
{ if ($bSelect) {
if ($bSelect)
{
$sChecked = ($aNodes[$id]->GetKey() == $currValue) ? 'checked' : ''; $sChecked = ($aNodes[$id]->GetKey() == $currValue) ? 'checked' : '';
if ($bMultiple) if ($bMultiple) {
{
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="checkbox" value="'.$aNodes[$id]->GetKey().'" name="selectObject[]" '.$sChecked.'>&nbsp;'; $sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="checkbox" value="'.$aNodes[$id]->GetKey().'" name="selectObject[]" '.$sChecked.'>&nbsp;';
} } else {
else
{
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'>&nbsp;'; $sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'>&nbsp;';
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -30,7 +31,7 @@ use Combodo\iTop\Renderer\BlockRenderer;
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class UIHTMLEditorWidget class UIHTMLEditorWidget
{ {
protected $m_iId; protected $m_iId;
protected $m_oAttDef; protected $m_oAttDef;
@@ -41,7 +42,7 @@ class UIHTMLEditorWidget
protected $m_sValidationField; protected $m_sValidationField;
protected $m_sValue; protected $m_sValue;
protected $m_sMandatory; protected $m_sMandatory;
public function __construct($iInputId, $oAttDef, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $sValue, $sMandatory) public function __construct($iInputId, $oAttDef, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $sValue, $sMandatory)
{ {
$this->m_iId = $iInputId; $this->m_iId = $iInputId;
@@ -54,7 +55,7 @@ class UIHTMLEditorWidget
$this->m_sMandatory = $sMandatory; $this->m_sMandatory = $sMandatory;
$this->m_sFieldPrefix = $sFieldPrefix; $this->m_sFieldPrefix = $sFieldPrefix;
} }
/** /**
* Get the HTML fragment corresponding to the HTML editor widget * Get the HTML fragment corresponding to the HTML editor widget
* *
@@ -63,7 +64,7 @@ class UIHTMLEditorWidget
* *
* @return string The HTML fragment to be inserted into the page * @return string The HTML fragment to be inserted into the page
*/ */
public function Display(WebPage $oPage, array $aArgs = array()) : string public function Display(WebPage $oPage, array $aArgs = []): string
{ {
$iId = $this->m_iId; $iId = $this->m_iId;
$sCode = $this->m_sAttCode.$this->m_sNameSuffix; $sCode = $this->m_sAttCode.$this->m_sNameSuffix;

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -38,39 +39,35 @@ class UILinksWidgetDirect
$this->sAttCode = $sAttCode; $this->sAttCode = $sAttCode;
$this->sInputid = $sInputId; $this->sInputid = $sInputId;
$this->sNameSuffix = $sNameSuffix; $this->sNameSuffix = $sNameSuffix;
$this->aZlist = array(); $this->aZlist = [];
$this->sLinkedClass = ''; $this->sLinkedClass = '';
// Compute the list of attributes visible from the given objet: // Compute the list of attributes visible from the given objet:
// All the attributes from the "list" Zlist of the Link class except // All the attributes from the "list" Zlist of the Link class except
// the ExternalKey that points to the current object and its related external fields // the ExternalKey that points to the current object and its related external fields
$oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$this->sLinkedClass = $oLinksetDef->GetLinkedClass(); $this->sLinkedClass = $oLinksetDef->GetLinkedClass();
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe(); $sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
switch($oLinksetDef->GetEditMode()) switch ($oLinksetDef->GetEditMode()) {
{
case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place' case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'details')); $aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'details'));
break; break;
default: default:
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list')); $aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list'));
array_unshift($aZList, 'friendlyname'); array_unshift($aZList, 'friendlyname');
} }
foreach($aZList as $sLinkedAttCode) foreach ($aZList as $sLinkedAttCode) {
{ if ($sLinkedAttCode != $sExtKeyToMe) {
if ($sLinkedAttCode != $sExtKeyToMe)
{
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode); $oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
if ((!$oAttDef->IsExternalField() || ($oAttDef->GetKeyAttCode() != $sExtKeyToMe)) && if ((!$oAttDef->IsExternalField() || ($oAttDef->GetKeyAttCode() != $sExtKeyToMe)) &&
(!$oAttDef->IsLinkSet()) ) (!$oAttDef->IsLinkSet())) {
{
$this->aZlist[] = $sLinkedAttCode; $this->aZlist[] = $sLinkedAttCode;
} }
} }
} }
} }
/** /**
@@ -101,21 +98,17 @@ class UILinksWidgetDirect
$sRealClass = ''; $sRealClass = '';
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>'); //$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself $aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$aPossibleClasses = array(); $aPossibleClasses = [];
foreach($aSubClasses as $sCandidateClass) foreach ($aSubClasses as $sCandidateClass) {
{ if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) if ($sCandidateClass == $sProposedRealClass) {
{
if ($sCandidateClass == $sProposedRealClass)
{
$sRealClass = $sProposedRealClass; $sRealClass = $sProposedRealClass;
} }
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass); $aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
} }
} }
// Only one of the subclasses can be instantiated... // Only one of the subclasses can be instantiated...
if (count($aPossibleClasses) == 1) if (count($aPossibleClasses) == 1) {
{
$aKeys = array_keys($aPossibleClasses); $aKeys = array_keys($aPossibleClasses);
$sRealClass = $aKeys[0]; $sRealClass = $aKeys[0];
} }
@@ -123,11 +116,11 @@ class UILinksWidgetDirect
if ($sRealClass != '') { if ($sRealClass != '') {
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe(); $sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$aFieldsFlags = array($sExtKeyToMe => OPT_ATT_HIDDEN); $aFieldsFlags = [$sExtKeyToMe => OPT_ATT_HIDDEN];
$oObj = DBObject::MakeDefaultInstance($sRealClass); $oObj = DBObject::MakeDefaultInstance($sRealClass);
$aPrefillParam = array('source_obj' => $oSourceObj); $aPrefillParam = ['source_obj' => $oSourceObj];
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam); $oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
$aFormExtraParams = array( $aFormExtraParams = [
'formPrefix' => $this->sInputid, 'formPrefix' => $this->sInputid,
'noRelations' => true, 'noRelations' => true,
'fieldsFlags' => $aFieldsFlags, 'fieldsFlags' => $aFieldsFlags,
@@ -140,25 +133,22 @@ class UILinksWidgetDirect
JS JS
, ,
], ],
); ];
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context // Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
FormHelper::DisableAttributeBlobInputs($sRealClass, $aFormExtraParams); FormHelper::DisableAttributeBlobInputs($sRealClass, $aFormExtraParams);
if(FormHelper::HasMandatoryAttributeBlobInputs($oObj)){ if (FormHelper::HasMandatoryAttributeBlobInputs($oObj)) {
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE)); $oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
} }
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), $aFormExtraParams); cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, [], $aFormExtraParams);
} } else {
else
{
$sClassLabel = MetaModel::GetName($this->sLinkedClass); $sClassLabel = MetaModel::GetName($this->sLinkedClass);
$oPage->add('<p>'.Dict::Format('UI:SelectTheTypeOf_Class_ToCreate', $sClassLabel)); $oPage->add('<p>'.Dict::Format('UI:SelectTheTypeOf_Class_ToCreate', $sClassLabel));
$oPage->add('<nobr><select name="class">'); $oPage->add('<nobr><select name="class">');
asort($aPossibleClasses); asort($aPossibleClasses);
foreach($aPossibleClasses as $sClassName => $sClassLabel) foreach ($aPossibleClasses as $sClassName => $sClassLabel) {
{
$oPage->add("<option value=\"$sClassName\">$sClassLabel</option>"); $oPage->add("<option value=\"$sClassName\">$sClassLabel</option>");
} }
$oPage->add('</select>'); $oPage->add('</select>');
@@ -178,7 +168,7 @@ JS
* @throws \MissingQueryArgument * @throws \MissingQueryArgument
* @throws \OQLException * @throws \OQLException
*/ */
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array()) public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = [])
{ {
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n"); //$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
@@ -199,8 +189,7 @@ JS
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinkSetDef->GetValuesDef(); $valuesDef = $oLinkSetDef->GetValuesDef();
if ($valuesDef === null) if ($valuesDef === null) {
{
$oFilter = new DBObjectSearch($this->sLinkedClass); $oFilter = new DBObjectSearch($this->sLinkedClass);
} else { } else {
if (!$valuesDef instanceof ValueSetObjects) { if (!$valuesDef instanceof ValueSetObjects) {
@@ -218,8 +207,10 @@ JS
$oCurrentObj->PrefillForm('search', $aPrefillFormParam); $oCurrentObj->PrefillForm('search', $aPrefillFormParam);
} }
$oBlock = new DisplayBlock($oFilter, 'search', false); $oBlock = new DisplayBlock($oFilter, 'search', false);
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", $oPage->AddUiBlock($oBlock->GetDisplay(
array( $oPage,
"SearchFormToAdd_{$this->sInputid}",
[
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}", 'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}", 'table_id' => "add_{$this->sInputid}",
'table_inner_id' => "ResultsToAdd_{$this->sInputid}", 'table_inner_id' => "ResultsToAdd_{$this->sInputid}",
@@ -227,13 +218,14 @@ JS
'cssCount' => "#count_{$this->sInputid}", 'cssCount' => "#count_{$this->sInputid}",
'query_params' => $oFilter->GetInternalParams(), 'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria, 'hidden_criteria' => $sHiddenCriteria,
) ]
)); ));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm'); $sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel'); $sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add'); $sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML $oPage->add(
<<<HTML
<form id="ObjectsAddForm_{$this->sInputid}"> <form id="ObjectsAddForm_{$this->sInputid}">
<div id="SearchResultsToAdd_{$this->sInputid}"> <div id="SearchResultsToAdd_{$this->sInputid}">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div> <div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
@@ -256,52 +248,43 @@ HTML
* @throws \CoreException * @throws \CoreException
* @throws \OQLException * @throws \OQLException
*/ */
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null, $aPrefillFormParam = array()) public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = [], $oCurrentObj = null, $aPrefillFormParam = [])
{ {
if ($sRemoteClass == '') if ($sRemoteClass == '') {
{
$sRemoteClass = $this->sLinkedClass; $sRemoteClass = $this->sLinkedClass;
} }
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinkSetDef->GetValuesDef(); $valuesDef = $oLinkSetDef->GetValuesDef();
if ($valuesDef === null) if ($valuesDef === null) {
{
$oFilter = new DBObjectSearch($sRemoteClass); $oFilter = new DBObjectSearch($sRemoteClass);
} } else {
else if (!$valuesDef instanceof ValueSetObjects) {
{
if (!$valuesDef instanceof ValueSetObjects)
{
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').'); throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
} }
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression()); $oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
} }
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass)) if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass)) {
{
// Prevent linking to self if the linked object is of the same family // Prevent linking to self if the linked object is of the same family
// and already present in the database // and already present in the database
if (!$oCurrentObj->IsNew()) if (!$oCurrentObj->IsNew()) {
{
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!='); $oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
} }
} }
if ($oCurrentObj != null) if ($oCurrentObj != null) {
{
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter); $this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams()); $aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
$oFilter->SetInternalParams($aArgs); $oFilter->SetInternalParams($aArgs);
$aPrefillFormParam['filter'] = $oFilter; $aPrefillFormParam['filter'] = $oFilter;
$oCurrentObj->PrefillForm('search', $aPrefillFormParam); $oCurrentObj->PrefillForm('search', $aPrefillFormParam);
} }
if (count($aAlreadyLinked) > 0) if (count($aAlreadyLinked) > 0) {
{
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN'); $oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
} }
$oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results $oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", ['menu' => false, 'cssCount' => '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid]); // Don't display the 'Actions' menu on the results
} }
/** /**
@@ -311,29 +294,28 @@ HTML
public function DoAddObjects(WebPage $oP, $oFullSetFilter) public function DoAddObjects(WebPage $oP, $oFullSetFilter)
{ {
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter); $aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
foreach($aLinkedObjectIds as $iObjectId) foreach ($aLinkedObjectIds as $iObjectId) {
{
$oLinkObj = MetaModel::GetObject($this->sLinkedClass, $iObjectId); $oLinkObj = MetaModel::GetObject($this->sLinkedClass, $iObjectId);
$oP->add($this->GetObjectRow($oP, $oLinkObj, $oLinkObj->GetKey())); $oP->add($this->GetObjectRow($oP, $oLinkObj, $oLinkObj->GetKey()));
} }
} }
public function GetObjectModificationDlg() public function GetObjectModificationDlg()
{ {
} }
public function GetTableConfig() public function GetTableConfig()
{ {
$aAttribs = array(); $aAttribs = [];
$aAttribs['form::select'] = array( $aAttribs['form::select'] = [
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->sInputid}:not(:disabled)', this.checked);oWidget".$this->sInputid.".directlinks('instance')._onSelectChange();\" class=\"checkAll\"></input>", 'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->sInputid}:not(:disabled)', this.checked);oWidget".$this->sInputid.".directlinks('instance')._onSelectChange();\" class=\"checkAll\"></input>",
'description' => Dict::S('UI:SelectAllToggle+'), 'description' => Dict::S('UI:SelectAllToggle+'),
); ];
foreach ($this->aZlist as $sLinkedAttCode) { foreach ($this->aZlist as $sLinkedAttCode) {
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode); $oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
$aAttribs[$sLinkedAttCode] = array('label' => MetaModel::GetLabel($this->sLinkedClass, $sLinkedAttCode), 'description' => $oAttDef->GetOrderByHint()); $aAttribs[$sLinkedAttCode] = ['label' => MetaModel::GetLabel($this->sLinkedClass, $sLinkedAttCode), 'description' => $oAttDef->GetOrderByHint()];
} }
return $aAttribs; return $aAttribs;
@@ -348,13 +330,12 @@ HTML
*/ */
public function GetRow($oPage, $sRealClass, $aValues, $iTempId) public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
{ {
if ($sRealClass == '') if ($sRealClass == '') {
{
$sRealClass = $this->sLinkedClass; $sRealClass = $this->sLinkedClass;
} }
$oLinkObj = new $sRealClass(); $oLinkObj = new $sRealClass();
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid); $oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId); return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
} }
@@ -367,13 +348,12 @@ HTML
protected function GetObjectRow($oPage, $oLinkObj, $iTempId) protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
{ {
$aAttribs = $this->GetTableConfig(); $aAttribs = $this->GetTableConfig();
$aRow = array(); $aRow = [];
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>'; $aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>';
foreach($this->aZlist as $sLinkedAttCode) foreach ($this->aZlist as $sLinkedAttCode) {
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode); $aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
} }
return $oPage->GetTableRow($aRow, $aAttribs); return $oPage->GetTableRow($aRow, $aAttribs);
} }
/** /**
@@ -386,23 +366,21 @@ HTML
*/ */
public function GetFormRow($oPage, $sRealClass, $aValues, $iTempId) public function GetFormRow($oPage, $sRealClass, $aValues, $iTempId)
{ {
if ($sRealClass == '') if ($sRealClass == '') {
{
$sRealClass = $this->sLinkedClass; $sRealClass = $this->sLinkedClass;
} }
$oLinkObj = new $sRealClass(); $oLinkObj = new $sRealClass();
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid); $oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
$aAttribs = $this->GetTableConfig(); $aAttribs = $this->GetTableConfig();
$aRow = array(); $aRow = [];
$aRow[] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>'; $aRow[] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>';
foreach($this->aZlist as $sLinkedAttCode) foreach ($this->aZlist as $sLinkedAttCode) {
{
$aRow[] = $oLinkObj->GetAsHTML($sLinkedAttCode); $aRow[] = $oLinkObj->GetAsHTML($sLinkedAttCode);
} }
return $aRow; return $aRow;
} }
/** /**
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context * Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
* @param DBObject $oSourceObj * @param DBObject $oSourceObj
@@ -413,27 +391,23 @@ HTML
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sSrcClass = get_class($oSourceObj); $sSrcClass = get_class($oSourceObj);
$sDestClass = $oSearch->GetClass(); $sDestClass = $oSearch->GetClass();
foreach($oAppContext->GetNames() as $key) foreach ($oAppContext->GetNames() as $key) {
{
// Find the value of the object corresponding to each 'context' parameter // Find the value of the object corresponding to each 'context' parameter
$aCallSpec = array($sSrcClass, 'MapContextParam'); $aCallSpec = [$sSrcClass, 'MapContextParam'];
$sAttCode = ''; $sAttCode = '';
if (is_callable($aCallSpec)) if (is_callable($aCallSpec)) {
{ $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
} }
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) {
{
$defaultValue = $oSourceObj->Get($sAttCode); $defaultValue = $oSourceObj->Get($sAttCode);
// Find the attcode for the same 'context' parameter in the destination class // Find the attcode for the same 'context' parameter in the destination class
// and sets its value as the default value for the search condition // and sets its value as the default value for the search condition
$aCallSpec = array($sDestClass, 'MapContextParam'); $aCallSpec = [$sDestClass, 'MapContextParam'];
$sAttCode = ''; $sAttCode = '';
if (is_callable($aCallSpec)) if (is_callable($aCallSpec)) {
{ $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
} }
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) { if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) {
@@ -443,7 +417,6 @@ HTML
} }
} }
public function GetClass(): string public function GetClass(): string
{ {
return $this->sClass; return $this->sClass;

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -54,7 +55,7 @@ class UILinksWidget
$this->m_sNameSuffix = $sNameSuffix; $this->m_sNameSuffix = $sNameSuffix;
$this->m_bDuplicatesAllowed = $bDuplicatesAllowed; $this->m_bDuplicatesAllowed = $bDuplicatesAllowed;
$this->m_aEditableFields = array(); $this->m_aEditableFields = [];
/** @var AttributeLinkedSetIndirect $oAttDef */ /** @var AttributeLinkedSetIndirect $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode);
@@ -67,34 +68,33 @@ class UILinksWidget
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote); $oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass(); $this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
$this->m_aEditableFields = array(); $this->m_aEditableFields = [];
$this->m_aTableConfig = array(); $this->m_aTableConfig = [];
$this->m_aTableConfig['form::checkbox'] = array( $this->m_aTableConfig['form::checkbox'] = [
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_sInputId.".OnSelectChange();\">", 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_sInputId.".OnSelectChange();\">",
'description' => Dict::S('UI:SelectAllToggle+'), 'description' => Dict::S('UI:SelectAllToggle+'),
); ];
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode); $aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef) foreach ($aLnkAttDefsToDisplay as $oLnkAttDef) {
{
$sLnkAttCode = $oLnkAttDef->GetCode(); $sLnkAttCode = $oLnkAttDef->GetCode();
$this->m_aEditableFields[] = $sLnkAttCode; $this->m_aEditableFields[] = $sLnkAttCode;
$this->m_aTableConfig[$sLnkAttCode] = array('label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription()); $this->m_aTableConfig[$sLnkAttCode] = ['label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription()];
} }
$this->m_aTableConfig['static::key'] = array( $this->m_aTableConfig['static::key'] = [
'label' => MetaModel::GetName($this->m_sRemoteClass), 'label' => MetaModel::GetName($this->m_sRemoteClass),
'description' => MetaModel::GetClassDescription($this->m_sRemoteClass), 'description' => MetaModel::GetClassDescription($this->m_sRemoteClass),
); ];
$this->m_aEditableFields[] = $this->m_sExtKeyToRemote; $this->m_aEditableFields[] = $this->m_sExtKeyToRemote;
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass); $aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef) { foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef) {
$sRemoteAttCode = $oRemoteAttDef->GetCode(); $sRemoteAttCode = $oRemoteAttDef->GetCode();
$this->m_aTableConfig['static::'.$sRemoteAttCode] = array( $this->m_aTableConfig['static::'.$sRemoteAttCode] = [
'label' => $oRemoteAttDef->GetLabel(), 'label' => $oRemoteAttDef->GetLabel(),
'description' => $oRemoteAttDef->GetDescription(), 'description' => $oRemoteAttDef->GetDescription(),
); ];
} }
} }
@@ -105,7 +105,6 @@ class UILinksWidget
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId; return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
} }
/** /**
* Display the table with the form for editing all the links at once * Display the table with the form for editing all the links at once
* *
@@ -119,7 +118,6 @@ class UILinksWidget
return DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aData); return DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aData);
} }
/** /**
* Get the HTML fragment corresponding to the linkset editing widget * Get the HTML fragment corresponding to the linkset editing widget
* *
@@ -157,7 +155,7 @@ class UILinksWidget
* @throws DictExceptionMissingString * @throws DictExceptionMissingString
* @throws Exception * @throws Exception
*/ */
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array()) public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = [], $aPrefillFormParam = [])
{ {
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass); $oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) { if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
@@ -183,7 +181,9 @@ class UILinksWidget
$sLinkedSetId = $oBlock->oUILinksWidget->GetLinkedSetId(); $sLinkedSetId = $oBlock->oUILinksWidget->GetLinkedSetId();
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false); $oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}", $oBlock->AddSubBlock($oDisplayBlock->GetDisplay(
$oPage,
"SearchFormToAdd_{$sLinkedSetId}",
[ [
'menu' => false, 'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}", 'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
@@ -195,7 +195,8 @@ class UILinksWidget
'query_params' => $oFilter->GetInternalParams(), 'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sAlreadyLinkedExpression, 'hidden_criteria' => $sAlreadyLinkedExpression,
'submit_on_load' => false, 'submit_on_load' => false,
])); ]
));
$oBlock->AddForm(); $oBlock->AddForm();
} }
@@ -212,25 +213,21 @@ class UILinksWidget
* @throws \CoreException * @throws \CoreException
* @throws \Exception * @throws \Exception
*/ */
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinkedIds = array(), $oCurrentObj = null) public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinkedIds = [], $oCurrentObj = null)
{ {
if ($sRemoteClass != '') if ($sRemoteClass != '') {
{
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass)); // assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
$oFilter = new DBObjectSearch($sRemoteClass); $oFilter = new DBObjectSearch($sRemoteClass);
} } else {
else
{
// No remote class specified use the one defined in the linkedset // No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->m_sRemoteClass); $oFilter = new DBObjectSearch($this->m_sRemoteClass);
} }
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
{
$oFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN'); $oFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
} }
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter); $this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode)); // Don't display the 'Actions' menu on the results $oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", ['menu' => false, 'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode]); // Don't display the 'Actions' menu on the results
} }
/** /**
@@ -251,7 +248,7 @@ class UILinksWidget
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false); $oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
if (is_object($oLinkedObj)) { if (is_object($oLinkedObj)) {
$oBlock = new BlockIndirectLinkSetEditTable($this); $oBlock = new BlockIndirectLinkSetEditTable($this);
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids $aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, [], $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId); $oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
$oP->AddUiBlock($oRow); $oP->AddUiBlock($oRow);
$iAdditionId++; $iAdditionId++;
@@ -280,7 +277,7 @@ class UILinksWidget
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false); $oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
if (is_object($oLinkedObj)) { if (is_object($oLinkedObj)) {
$oBlock = new BlockIndirectLinkSetEditTable($this); $oBlock = new BlockIndirectLinkSetEditTable($this);
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId, false /* Default value */, $bAllowRemoteExtKeyEdit); // Not yet created link get negative Ids $aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, [], $oCurrentObj, $iAdditionId, false /* Default value */, $bAllowRemoteExtKeyEdit); // Not yet created link get negative Ids
$aData = []; $aData = [];
foreach ($aRow as $item) { foreach ($aRow as $item) {
$aData[] = $item; $aData[] = $item;
@@ -307,37 +304,30 @@ class UILinksWidget
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sSrcClass = get_class($oSourceObj); $sSrcClass = get_class($oSourceObj);
$sDestClass = $oSearch->GetClass(); $sDestClass = $oSearch->GetClass();
foreach($oAppContext->GetNames() as $key) foreach ($oAppContext->GetNames() as $key) {
{
// Find the value of the object corresponding to each 'context' parameter // Find the value of the object corresponding to each 'context' parameter
$aCallSpec = array($sSrcClass, 'MapContextParam'); $aCallSpec = [$sSrcClass, 'MapContextParam'];
$sAttCode = ''; $sAttCode = '';
if (is_callable($aCallSpec)) if (is_callable($aCallSpec)) {
{ $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
} }
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) {
{
$defaultValue = $oSourceObj->Get($sAttCode); $defaultValue = $oSourceObj->Get($sAttCode);
// Find the attcode for the same 'context' parameter in the destination class // Find the attcode for the same 'context' parameter in the destination class
// and sets its value as the default value for the search condition // and sets its value as the default value for the search condition
$aCallSpec = array($sDestClass, 'MapContextParam'); $aCallSpec = [$sDestClass, 'MapContextParam'];
$sAttCode = ''; $sAttCode = '';
if (is_callable($aCallSpec)) if (is_callable($aCallSpec)) {
{ $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
} }
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) {
{
// Add Hierarchical condition if hierarchical key // Add Hierarchical condition if hierarchical key
$oAttDef = MetaModel::GetAttributeDef($sDestClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sDestClass, $sAttCode);
if (isset($oAttDef) && ($oAttDef->IsExternalKey())) if (isset($oAttDef) && ($oAttDef->IsExternalKey())) {
{ try {
try
{
/** @var AttributeExternalKey $oAttDef */ /** @var AttributeExternalKey $oAttDef */
$sTargetClass = $oAttDef->GetTargetClass(); $sTargetClass = $oAttDef->GetTargetClass();
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass); $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
@@ -348,8 +338,7 @@ class UILinksWidget
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); $oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode); $oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
} }
} } catch (Exception $e) {
catch (Exception $e) {
} }
} else { } else {
$oSearch->AddCondition($sAttCode, $defaultValue); $oSearch->AddCondition($sAttCode, $defaultValue);

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -28,13 +29,13 @@ use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/displayblock.class.inc.php'); require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIPasswordWidget class UIPasswordWidget
{ {
protected static $iWidgetIndex = 0; protected static $iWidgetIndex = 0;
protected $sAttCode; protected $sAttCode;
protected $sNameSuffix; protected $sNameSuffix;
protected $iId; protected $iId;
public function __construct($sAttCode, $iInputId, $sNameSuffix = '') public function __construct($sAttCode, $iInputId, $sNameSuffix = '')
{ {
self::$iWidgetIndex++; self::$iWidgetIndex++;
@@ -42,14 +43,14 @@ class UIPasswordWidget
$this->sNameSuffix = $sNameSuffix; $this->sNameSuffix = $sNameSuffix;
$this->iId = $iInputId; $this->iId = $iInputId;
} }
/** /**
* Get the HTML fragment corresponding to the linkset editing widget * Get the HTML fragment corresponding to the linkset editing widget
* @param WebPage $oP The web page used for all the output * @param WebPage $oP The web page used for all the output
* @param Hash $aArgs Extra context arguments * @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page * @return string The HTML fragment to be inserted into the page
*/ */
public function Display(WebPage $oPage, $aArgs = array()) public function Display(WebPage $oPage, $aArgs = [])
{ {
$oPage->add_dict_entry('UI:Component:Input:Password:DoesNotMatch'); $oPage->add_dict_entry('UI:Component:Input:Password:DoesNotMatch');
@@ -94,4 +95,3 @@ class UIPasswordWidget
return $sHtmlValue; return $sHtmlValue;
} }
} }
?>

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* *
* Copyright (C) 2010-2024 Combodo SAS * Copyright (C) 2010-2024 Combodo SAS
@@ -20,7 +21,6 @@
* *
*/ */
use Combodo\iTop\Application\WebPage\WebPage; use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/displayblock.class.inc.php'); require_once(APPROOT.'/application/displayblock.class.inc.php');
@@ -46,8 +46,10 @@ class UISearchFormForeignKeys
$oFilter = new DBObjectSearch($this->m_sRemoteClass); $oFilter = new DBObjectSearch($this->m_sRemoteClass);
$oBlock = new DisplayBlock($oFilter, 'search', false); $oBlock = new DisplayBlock($oFilter, 'search', false);
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}", $oPage->AddUiBlock($oBlock->GetDisplay(
array( $oPage,
"SearchFormToAdd_{$this->m_iInputId}",
[
'menu' => false, 'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}", 'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
'table_id' => "add_{$this->m_iInputId}", 'table_id' => "add_{$this->m_iInputId}",
@@ -55,12 +57,14 @@ class UISearchFormForeignKeys
'selection_mode' => true, 'selection_mode' => true,
'cssCount' => "#count_{$this->m_iInputId}", 'cssCount' => "#count_{$this->m_iInputId}",
'query_params' => $oFilter->GetInternalParams(), 'query_params' => $oFilter->GetInternalParams(),
))); ]
));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm'); $sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel'); $sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add'); $sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML $oPage->add(
<<<HTML
<form id="ObjectsAddForm_{$this->m_iInputId}"> <form id="ObjectsAddForm_{$this->m_iInputId}">
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;height:100%;overflow:auto;padding:0;border:0;"> <div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div> <div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
@@ -101,20 +105,17 @@ $('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});
$('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd); $('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);
$('#SearchFormToAdd_{$this->m_iInputId}').on('resize', oForeignKeysWidget{$this->m_iInputId}.UpdateSizes); $('#SearchFormToAdd_{$this->m_iInputId}').on('resize', oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);
JS JS
); );
} }
public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter) public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter)
{ {
try try {
{
$aLinkedObjects = utils::ReadMultipleSelectionWithFriendlyname($oFullSetFilter); $aLinkedObjects = utils::ReadMultipleSelectionWithFriendlyname($oFullSetFilter);
$oPage->add(json_encode($aLinkedObjects)); $oPage->add(json_encode($aLinkedObjects));
} } catch (CoreException $e) {
catch (CoreException $e)
{
http_response_code(500); http_response_code(500);
$oPage->add(json_encode(array('error' => $e->GetMessage()))); $oPage->add(json_encode(['error' => $e->GetMessage()]));
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString()); IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString());
} }
} }
@@ -129,20 +130,20 @@ JS
*/ */
public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '') public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '')
{ {
if ($sRemoteClass != '') if ($sRemoteClass != '') {
{
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass)); // assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
$oFilter = new DBObjectSearch($sRemoteClass); $oFilter = new DBObjectSearch($sRemoteClass);
} } else {
else
{
// No remote class specified use the one defined in the linkedset // No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->m_sRemoteClass); $oFilter = new DBObjectSearch($this->m_sRemoteClass);
} }
$oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->m_iInputId}", $oBlock->Display(
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}")); $oP,
"ResultsToAdd_{$this->m_iInputId}",
['menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"]
);
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -17,7 +18,6 @@
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\WebPage\iTopWebPage; use Combodo\iTop\Application\WebPage\iTopWebPage;
/** /**
* Class UIWizard * Class UIWizard
* *
@@ -31,74 +31,73 @@ class UIWizard
protected $m_sClass; protected $m_sClass;
protected $m_sTargetState; protected $m_sTargetState;
protected $m_aWizardSteps; protected $m_aWizardSteps;
public function __construct($oPage, $sClass, $sTargetState = '') public function __construct($oPage, $sClass, $sTargetState = '')
{ {
$this->m_oPage = $oPage; $this->m_oPage = $oPage;
$this->m_sClass = $sClass; $this->m_sClass = $sClass;
if (empty($sTargetState)) if (empty($sTargetState)) {
{
$sTargetState = MetaModel::GetDefaultState($sClass); $sTargetState = MetaModel::GetDefaultState($sClass);
} }
$this->m_sTargetState = $sTargetState; $this->m_sTargetState = $sTargetState;
$this->m_aWizardSteps = $this->ComputeWizardStructure(); $this->m_aWizardSteps = $this->ComputeWizardStructure();
} }
public function GetObjectClass() { return $this->m_sClass; } public function GetObjectClass()
public function GetTargetState() { return $this->m_sTargetState; } {
public function GetWizardStructure() { return $this->m_aWizardSteps; } return $this->m_sClass;
}
public function GetTargetState()
{
return $this->m_sTargetState;
}
public function GetWizardStructure()
{
return $this->m_aWizardSteps;
}
/** /**
* Displays one step of the wizard * Displays one step of the wizard
*/ */
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array()) public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = [])
{ {
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too if ($iStepIndex == 1) { // one big form that contains everything, to make sure that the uploaded files are posted too
{
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n"); $this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
} }
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n"); $this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n"); $this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$aStates = MetaModel::EnumStates($this->m_sClass); $aStates = MetaModel::EnumStates($this->m_sClass);
$aDetails = array(); $aDetails = [];
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered $sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
foreach($aStep as $sAttCode) foreach ($aStep as $sAttCode) {
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef->IsWritable()) if ($oAttDef->IsWritable()) {
{
$sAttLabel = $oAttDef->GetLabel(); $sAttLabel = $oAttDef->GetLabel();
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0; $iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) {
{ $aFields[$sAttCode] = [];
$aFields[$sAttCode] = array(); foreach ($aPrerequisites as $sCode) {
foreach($aPrerequisites as $sCode)
{
$aFields[$sAttCode][$sCode] = ''; $aFields[$sAttCode][$sCode] = '';
} }
} }
if (count($aPrerequisites) > 0) if (count($aPrerequisites) > 0) {
{
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites); $aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
} }
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : ''; $sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed())) ? ' <span class="hilite">*</span>' : '';
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists $oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs); $sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
$aFieldsMap["att_$iMaxInputId"] = $sAttCode; $aFieldsMap["att_$iMaxInputId"] = $sAttCode;
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>"); $aDetails[] = ['label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>"];
if ($oAttDef->GetValuesDef() != null) if ($oAttDef->GetValuesDef() != null) {
{
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n"; $sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
} }
if ($oAttDef->GetDefaultValue() != null) if ($oAttDef->GetDefaultValue() != null) {
{
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n"; $sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
} }
if ($oAttDef->IsLinkSet()) if ($oAttDef->IsLinkSet()) {
{
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();"; $sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
} }
$iMaxInputId++; $iMaxInputId++;
@@ -126,11 +125,11 @@ $sJSHandlerCode
} }
"); ");
$this->m_oPage->add("</div>\n\n"); $this->m_oPage->add("</div>\n\n");
} }
/** /**
* Display the final step of the wizard: a confirmation screen * Display the final step of the wizard: a confirmation screen
*/ */
public function DisplayFinalStep($iStepIndex, $aFieldsMap) public function DisplayFinalStep($iStepIndex, $aFieldsMap)
{ {
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
@@ -141,136 +140,116 @@ $sJSHandlerCode
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n"); $this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n"); $this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
$sScript = "function OnEnterStep$iStepIndex() {\n"; $sScript = "function OnEnterStep$iStepIndex() {\n";
foreach($aFieldsMap as $iInputId => $sAttCode) foreach ($aFieldsMap as $iInputId => $sAttCode) {
{ $sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
} }
$sScript .= "\toWizardHelper.Preview('object_preview');\n"; $sScript .= "\toWizardHelper.Preview('object_preview');\n";
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n"; $sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
$sScript .= "}\n"; $sScript .= "}\n";
$this->m_oPage->add_script($sScript); $this->m_oPage->add_script($sScript);
$this->m_oPage->add("<div id=\"object_preview\">\n"); $this->m_oPage->add("<div id=\"object_preview\">\n");
$this->m_oPage->add("</div>\n"); $this->m_oPage->add("</div>\n");
$this->m_oPage->add($oAppContext->GetForForm()); $this->m_oPage->add($oAppContext->GetForForm());
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />"); $this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n"); $this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
$this->m_oPage->add("</div>\n"); $this->m_oPage->add("</div>\n");
$this->m_oPage->add("</form>\n"); $this->m_oPage->add("</form>\n");
} }
/** /**
* Compute the order of the fields & pages in the wizard * Compute the order of the fields & pages in the wizard
* @param $oPage iTopWebPage The current page (used to display error messages) * @param $oPage iTopWebPage The current page (used to display error messages)
* @param $sClass string Name of the class * @param $sClass string Name of the class
* @param $sStateCode string Code of the target state of the object * @param $sStateCode string Code of the target state of the object
* @return hash Two dimensional array: each element represents the list of fields for a given page * @return hash Two dimensional array: each element represents the list of fields for a given page
*/ */
protected function ComputeWizardStructure() protected function ComputeWizardStructure()
{ {
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array()); $aWizardSteps = [ 'mandatory' => [], 'optional' => []];
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard $aFieldsDone = []; // Store all the fields that are already covered by a previous step of the wizard
$aStates = MetaModel::EnumStates($this->m_sClass); $aStates = MetaModel::EnumStates($this->m_sClass);
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass); $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
$aMandatoryAttributes = array();
// Some attributes are always mandatory independently of the state machine (if any)
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
{
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
}
}
// Now check the attributes that are mandatory in the specified state $aMandatoryAttributes = [];
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) ) // Some attributes are always mandatory independently of the state machine (if any)
{ foreach (MetaModel::GetAttributesList($this->m_sClass) as $sAttCode) {
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode)) {
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
}
}
// Now check the attributes that are mandatory in the specified state
if ((!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0)) {
// Check all the fields that *must* be included in the wizard for this // Check all the fields that *must* be included in the wizard for this
// particular target state // particular target state
$aFields = array(); $aFields = [];
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) foreach ($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) {
{ if ((isset($aMandatoryAttributes[$sAttCode])) &&
if ( (isset($aMandatoryAttributes[$sAttCode])) && ($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))) {
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
{
$aMandatoryAttributes[$sAttCode] |= $iOptions; $aMandatoryAttributes[$sAttCode] |= $iOptions;
} } else {
else
{
$aMandatoryAttributes[$sAttCode] = $iOptions; $aMandatoryAttributes[$sAttCode] = $iOptions;
} }
} }
} }
// Check all the fields that *must* be included in the wizard // Check all the fields that *must* be included in the wizard
// i.e. all mandatory, must-change or must-prompt fields that are // i.e. all mandatory, must-change or must-prompt fields that are
// not also read-only or hidden. // not also read-only or hidden.
// Some fields may be required (null not allowed) from the database // Some fields may be required (null not allowed) from the database
// perspective, but hidden or read-only from the user interface perspective // perspective, but hidden or read-only from the user interface perspective
$aFields = array(); $aFields = [];
foreach($aMandatoryAttributes as $sAttCode => $iOptions) foreach ($aMandatoryAttributes as $sAttCode => $iOptions) {
{ if (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) && !($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN))) {
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array(); $aFields[$sAttCode] = [];
foreach($aPrerequisites as $sCode) foreach ($aPrerequisites as $sCode) {
{
$aFields[$sAttCode][$sCode] = ''; $aFields[$sAttCode][$sCode] = '';
} }
} }
} }
// Now use the dependencies between the fields to order them // Now use the dependencies between the fields to order them
// Start from the order of the 'details' // Start from the order of the 'details'
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details')); $aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
$index = 0; $index = 0;
$aOrder = array(); $aOrder = [];
foreach($aFields as $sAttCode => $void) foreach ($aFields as $sAttCode => $void) {
{ $aOrder[$sAttCode] = 999; // At the end of the list...
$aOrder[$sAttCode] = 999; // At the end of the list...
} }
foreach($aList as $sAttCode) foreach ($aList as $sAttCode) {
{ if (array_key_exists($sAttCode, $aFields)) {
if (array_key_exists($sAttCode, $aFields))
{
$aOrder[$sAttCode] = $index; $aOrder[$sAttCode] = $index;
} }
$index++; $index++;
} }
foreach($aFields as $sAttCode => $aDependencies) foreach ($aFields as $sAttCode => $aDependencies) {
{
// All fields with no remaining dependencies can be entered at this // All fields with no remaining dependencies can be entered at this
// step of the wizard // step of the wizard
if (count($aDependencies) > 0) if (count($aDependencies) > 0) {
{
$iMaxPos = 0; $iMaxPos = 0;
// Remove this field from the dependencies of the other fields // Remove this field from the dependencies of the other fields
foreach($aDependencies as $sDependentAttCode => $void) foreach ($aDependencies as $sDependentAttCode => $void) {
{
// position the current field after the ones it depends on // position the current field after the ones it depends on
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]); $iMaxPos = max($iMaxPos, 1 + $aOrder[$sDependentAttCode]);
} }
} }
} }
asort($aOrder); asort($aOrder);
$aCurrentStep = array(); $aCurrentStep = [];
foreach($aOrder as $sAttCode => $rank) foreach ($aOrder as $sAttCode => $rank) {
{
$aCurrentStep[] = $sAttCode; $aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = ''; $aFieldsDone[$sAttCode] = '';
} }
$aWizardSteps['mandatory'][] = $aCurrentStep; $aWizardSteps['mandatory'][] = $aCurrentStep;
// Now computes the steps to fill the optional fields // Now computes the steps to fill the optional fields
$aFields = array(); // reset $aFields = []; // reset
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef) foreach (MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode => $oAttDef) {
{
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0; $iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
if (($sStateAttCode != $sAttCode) && if (($sStateAttCode != $sAttCode) &&
(!$oAttDef->IsExternalField()) && (!$oAttDef->IsExternalField()) &&
@@ -282,7 +261,7 @@ $sJSHandlerCode
// are removed from the 'optional' part of the wizard // are removed from the 'optional' part of the wizard
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array(); $aFields[$sAttCode] = [];
foreach ($aPrerequisites as $sCode) { foreach ($aPrerequisites as $sCode) {
if (!isset($aFieldsDone[$sCode])) { if (!isset($aFieldsDone[$sCode])) {
// retain only the dependencies that were not covered // retain only the dependencies that were not covered
@@ -293,28 +272,23 @@ $sJSHandlerCode
} }
} }
// Now use the dependencies between the fields to order them // Now use the dependencies between the fields to order them
while(count($aFields) > 0) while (count($aFields) > 0) {
{ $aCurrentStep = [];
$aCurrentStep = array(); foreach ($aFields as $sAttCode => $aDependencies) {
foreach($aFields as $sAttCode => $aDependencies)
{
// All fields with no remaining dependencies can be entered at this // All fields with no remaining dependencies can be entered at this
// step of the wizard // step of the wizard
if (count($aDependencies) == 0) if (count($aDependencies) == 0) {
{
$aCurrentStep[] = $sAttCode; $aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = ''; $aFieldsDone[$sAttCode] = '';
unset($aFields[$sAttCode]); unset($aFields[$sAttCode]);
// Remove this field from the dependencies of the other fields // Remove this field from the dependencies of the other fields
foreach($aFields as $sUpdatedCode => $aDummy) foreach ($aFields as $sUpdatedCode => $aDummy) {
{
// remove the dependency // remove the dependency
unset($aFields[$sUpdatedCode][$sAttCode]); unset($aFields[$sUpdatedCode][$sAttCode]);
} }
} }
} }
if (count($aCurrentStep) == 0) if (count($aCurrentStep) == 0) {
{
// This step of the wizard would contain NO field ! // This step of the wizard would contain NO field !
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies')); $this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
print_r($aFields); print_r($aFields);
@@ -323,7 +297,6 @@ $sJSHandlerCode
$aWizardSteps['optional'][] = $aCurrentStep; $aWizardSteps['optional'][] = $aCurrentStep;
} }
return $aWizardSteps; return $aWizardSteps;
} }
} }
?>

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -31,40 +32,39 @@ class UserDashboard extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "gui", "category" => "gui",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => array('user_id', 'menu_code'), "name_attcode" => ['user_id', 'menu_code'],
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_app_dashboards", "db_table" => "priv_app_dashboards",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("menu_code", array("allowed_values"=>null, "sql"=>"menu_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("contents", array("allowed_values"=>null, "sql"=>"contents", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_SetZListItems('default_search', array ( MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", ["targetclass" => "User", "allowed_values" => null, "sql" => "user_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("menu_code", ["allowed_values" => null, "sql" => "menu_code", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("contents", ["allowed_values" => null, "sql" => "contents", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_SetZListItems('default_search', [
0 => 'user_id', 0 => 'user_id',
1 => 'menu_code', 1 => 'menu_code',
)); ]);
MetaModel::Init_SetZListItems('list', array ( MetaModel::Init_SetZListItems('list', [
0 => 'user_id', 0 => 'user_id',
1 => 'menu_code', 1 => 'menu_code',
)); ]);
} }
/** /**
* Overloading this function here to secure a fix done right before the release * Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject * The real fix should be to implement this verb in DBObject
*/ */
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null) public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{ {
$this->DBDelete($oDeletionPlan); $this->DBDelete($oDeletionPlan);
} }
} }
?>

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -227,13 +228,12 @@ class appUserPreferences extends DBObject
// No prefs (yet) for this user, create the object // No prefs (yet) for this user, create the object
$oObj = new appUserPreferences(); $oObj = new appUserPreferences();
$oObj->Set('userid', $sUserId); $oObj->Set('userid', $sUserId);
$oObj->Set('preferences', array()); // Default preferences: an empty array $oObj->Set('preferences', []); // Default preferences: an empty array
try { try {
utils::PushArchiveMode(false); utils::PushArchiveMode(false);
$oObj->DBInsert(); $oObj->DBInsert();
utils::PopArchiveMode(); utils::PopArchiveMode();
} } catch (Exception $e) {
catch (Exception $e) {
// Ignore errors // Ignore errors
} }
} }
@@ -245,25 +245,25 @@ class appUserPreferences extends DBObject
*/ */
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "gui", "category" => "gui",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "login", "name_attcode" => "login",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array("userid","login"), "reconc_keys" => ["userid","login"],
"db_table" => "priv_app_preferences", "db_table" => "priv_app_preferences",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributePropertySet("preferences", array("allowed_values"=>null, "sql"=>"preferences", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributePropertySet("preferences", ["allowed_values" => null, "sql" => "preferences", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalField("org_id", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "org_id"))); MetaModel::Init_AddAttribute(new AttributeExternalField("org_id", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "org_id"]));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"))); MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
MetaModel::Init_SetZListItems('list', array('org_id','preferences')); MetaModel::Init_SetZListItems('list', ['org_id','preferences']);
MetaModel::Init_SetZListItems('default_search', array('userid','login','org_id')); MetaModel::Init_SetZListItems('default_search', ['userid','login','org_id']);
} }
/** /**

View File

@@ -1,43 +1,51 @@
<?php <?php
/* @author Mark Jones /* @author Mark Jones
* @license MIT License * @license MIT License
* */ * */
if (!class_exists('ZipArchive')) { throw new Exception('ZipArchive not found'); } if (!class_exists('ZipArchive')) {
throw new Exception('ZipArchive not found');
}
Class XLSXWriter class XLSXWriter
{ {
//------------------------------------------------------------------ //------------------------------------------------------------------
protected $author ='Doc Author'; protected $author = 'Doc Author';
protected $sheets_meta = array(); protected $sheets_meta = [];
protected $shared_strings = array();//unique set protected $shared_strings = [];//unique set
protected $shared_string_count = 0;//count of non-unique references to the unique set protected $shared_string_count = 0;//count of non-unique references to the unique set
protected $temp_files = array(); protected $temp_files = [];
protected $date_format = 'YYYY-MM-DD'; protected $date_format = 'YYYY-MM-DD';
protected $date_time_format = 'YYYY-MM-DD\ HH:MM:SS'; protected $date_time_format = 'YYYY-MM-DD\ HH:MM:SS';
public function __construct(){} public function __construct()
public function setAuthor($author='') { $this->author=$author; } {
}
public function setAuthor($author = '')
{
$this->author = $author;
}
public function __destruct() public function __destruct()
{ {
if (!empty($this->temp_files)) { if (!empty($this->temp_files)) {
foreach($this->temp_files as $temp_file) { foreach ($this->temp_files as $temp_file) {
@unlink($temp_file); @unlink($temp_file);
} }
} }
} }
public function setDateFormat($date_format) public function setDateFormat($date_format)
{ {
$this->date_format = $date_format; $this->date_format = $date_format;
} }
public function setDateTimeFormat($date_time_format) public function setDateTimeFormat($date_time_format)
{ {
$this->date_time_format = $date_time_format; $this->date_time_format = $date_time_format;
} }
protected function tempFilename() protected function tempFilename()
{ {
$filename = tempnam(SetupUtils::GettmpDir(), 'xlsx_writer_'); $filename = tempnam(SetupUtils::GettmpDir(), 'xlsx_writer_');
@@ -64,120 +72,123 @@ Class XLSXWriter
{ {
@unlink($filename);//if the zip already exists, overwrite it @unlink($filename);//if the zip already exists, overwrite it
$zip = new ZipArchive(); $zip = new ZipArchive();
if (empty($this->sheets_meta)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", no worksheets defined."); return; } if (empty($this->sheets_meta)) {
if (!$zip->open($filename, ZipArchive::CREATE)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", unable to create zip."); return; } self::log("Error in ".__CLASS__."::".__FUNCTION__.", no worksheets defined.");
return;
}
if (!$zip->open($filename, ZipArchive::CREATE)) {
self::log("Error in ".__CLASS__."::".__FUNCTION__.", unable to create zip.");
return;
}
$zip->addEmptyDir("docProps/"); $zip->addEmptyDir("docProps/");
$zip->addFromString("docProps/app.xml" , self::buildAppXML() ); $zip->addFromString("docProps/app.xml", self::buildAppXML());
$zip->addFromString("docProps/core.xml", self::buildCoreXML()); $zip->addFromString("docProps/core.xml", self::buildCoreXML());
$zip->addEmptyDir("_rels/"); $zip->addEmptyDir("_rels/");
$zip->addFromString("_rels/.rels", self::buildRelationshipsXML()); $zip->addFromString("_rels/.rels", self::buildRelationshipsXML());
$zip->addEmptyDir("xl/worksheets/"); $zip->addEmptyDir("xl/worksheets/");
foreach($this->sheets_meta as $sheet_meta) { foreach ($this->sheets_meta as $sheet_meta) {
$zip->addFile($sheet_meta['filename'], "xl/worksheets/".$sheet_meta['xmlname'] ); $zip->addFile($sheet_meta['filename'], "xl/worksheets/".$sheet_meta['xmlname']);
} }
if (!empty($this->shared_strings)) { if (!empty($this->shared_strings)) {
$zip->addFile($this->writeSharedStringsXML(), "xl/sharedStrings.xml" ); //$zip->addFromString("xl/sharedStrings.xml", self::buildSharedStringsXML() ); $zip->addFile($this->writeSharedStringsXML(), "xl/sharedStrings.xml"); //$zip->addFromString("xl/sharedStrings.xml", self::buildSharedStringsXML() );
} }
$zip->addFromString("xl/workbook.xml" , self::buildWorkbookXML() ); $zip->addFromString("xl/workbook.xml", self::buildWorkbookXML());
$zip->addFile($this->writeStylesXML(), "xl/styles.xml" ); //$zip->addFromString("xl/styles.xml" , self::buildStylesXML() ); $zip->addFile($this->writeStylesXML(), "xl/styles.xml"); //$zip->addFromString("xl/styles.xml" , self::buildStylesXML() );
$zip->addFromString("[Content_Types].xml" , self::buildContentTypesXML() ); $zip->addFromString("[Content_Types].xml", self::buildContentTypesXML());
$zip->addEmptyDir("xl/_rels/"); $zip->addEmptyDir("xl/_rels/");
$zip->addFromString("xl/_rels/workbook.xml.rels", self::buildWorkbookRelsXML() ); $zip->addFromString("xl/_rels/workbook.xml.rels", self::buildWorkbookRelsXML());
$zip->close(); $zip->close();
} }
public function writeSheet(array $data, $sheet_name = '', array $header_types = [], array $header_row = [])
public function writeSheet(array $data, $sheet_name='', array $header_types=array(), array $header_row=array() )
{ {
$data = empty($data) ? array( array('') ) : $data; $data = empty($data) ? [ [''] ] : $data;
$sheet_filename = $this->tempFilename(); $sheet_filename = $this->tempFilename();
$sheet_default = 'Sheet'.(count($this->sheets_meta)+1); $sheet_default = 'Sheet'.(count($this->sheets_meta) + 1);
$sheet_name = !empty($sheet_name) ? $sheet_name : $sheet_default; $sheet_name = !empty($sheet_name) ? $sheet_name : $sheet_default;
$this->sheets_meta[] = array('filename'=>$sheet_filename, 'sheetname'=>$sheet_name ,'xmlname'=>strtolower($sheet_default).".xml" ); $this->sheets_meta[] = ['filename' => $sheet_filename, 'sheetname' => $sheet_name ,'xmlname' => strtolower($sheet_default).".xml" ];
$header_offset = empty($header_types) ? 0 : 1; $header_offset = empty($header_types) ? 0 : 1;
$row_count = count($data) + $header_offset; $row_count = count($data) + $header_offset;
$column_count = count($data[self::array_first_key($data)]); $column_count = count($data[self::array_first_key($data)]);
$max_cell = self::xlsCell( $row_count-1, $column_count-1 ); $max_cell = self::xlsCell($row_count - 1, $column_count - 1);
$tabselected = count($this->sheets_meta)==1 ? 'true' : 'false';//only first sheet is selected $tabselected = count($this->sheets_meta) == 1 ? 'true' : 'false';//only first sheet is selected
$cell_formats_arr = empty($header_types) ? array_fill(0, $column_count, 'string') : array_values($header_types); $cell_formats_arr = empty($header_types) ? array_fill(0, $column_count, 'string') : array_values($header_types);
if (empty($header_row) && !empty($header_types)) if (empty($header_row) && !empty($header_types)) {
{ $header_row = empty($header_types) ? [] : array_keys($header_types);
$header_row = empty($header_types) ? array() : array_keys($header_types);
} }
$fd = fopen($sheet_filename, "w+"); $fd = fopen($sheet_filename, "w+");
if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; } if ($fd === false) {
self::log("write failed in ".__CLASS__."::".__FUNCTION__.".");
fwrite($fd,'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n"); return;
fwrite($fd,'<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'); }
fwrite($fd, '<sheetPr filterMode="false">');
fwrite($fd, '<pageSetUpPr fitToPage="false"/>'); fwrite($fd, '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
fwrite($fd, '</sheetPr>'); fwrite($fd, '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
fwrite($fd, '<dimension ref="A1:'.$max_cell.'"/>'); fwrite($fd, '<sheetPr filterMode="false">');
fwrite($fd, '<sheetViews>'); fwrite($fd, '<pageSetUpPr fitToPage="false"/>');
fwrite($fd, '<sheetView colorId="64" defaultGridColor="true" rightToLeft="false" showFormulas="false" showGridLines="true" showOutlineSymbols="true" showRowColHeaders="true" showZeros="true" tabSelected="'.$tabselected.'" topLeftCell="A1" view="normal" windowProtection="false" workbookViewId="0" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100">'); fwrite($fd, '</sheetPr>');
fwrite($fd, '<selection activeCell="A1" activeCellId="0" pane="topLeft" sqref="A1"/>'); fwrite($fd, '<dimension ref="A1:'.$max_cell.'"/>');
fwrite($fd, '</sheetView>'); fwrite($fd, '<sheetViews>');
fwrite($fd, '</sheetViews>'); fwrite($fd, '<sheetView colorId="64" defaultGridColor="true" rightToLeft="false" showFormulas="false" showGridLines="true" showOutlineSymbols="true" showRowColHeaders="true" showZeros="true" tabSelected="'.$tabselected.'" topLeftCell="A1" view="normal" windowProtection="false" workbookViewId="0" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100">');
fwrite($fd, '<cols>'); fwrite($fd, '<selection activeCell="A1" activeCellId="0" pane="topLeft" sqref="A1"/>');
fwrite($fd, '<col collapsed="false" hidden="false" max="1025" min="1" style="0" width="19"/>'); fwrite($fd, '</sheetView>');
fwrite($fd, '</cols>'); fwrite($fd, '</sheetViews>');
fwrite($fd, '<sheetData>'); fwrite($fd, '<cols>');
if (!empty($header_row)) fwrite($fd, '<col collapsed="false" hidden="false" max="1025" min="1" style="0" width="19"/>');
{ fwrite($fd, '</cols>');
fwrite($fd, '<sheetData>');
if (!empty($header_row)) {
fwrite($fd, '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="'.(1).'">'); fwrite($fd, '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="'.(1).'">');
foreach($header_row as $k=>$v) foreach ($header_row as $k => $v) {
{ $this->writeCell($fd, 0, $k, $v, $cell_format = 'string');
$this->writeCell($fd, 0, $k, $v, $cell_format='string');
} }
fwrite($fd, '</row>'); fwrite($fd, '</row>');
} }
foreach($data as $i=>$row) foreach ($data as $i => $row) {
{ fwrite($fd, '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="'.($i + $header_offset + 1).'">');
fwrite($fd, '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="'.($i+$header_offset+1).'">'); foreach ($row as $k => $v) {
foreach($row as $k=>$v) $this->writeCell($fd, $i + $header_offset, $k, $v, $cell_formats_arr[$k]);
{
$this->writeCell($fd, $i+$header_offset, $k, $v, $cell_formats_arr[$k]);
} }
fwrite($fd, '</row>'); fwrite($fd, '</row>');
} }
fwrite($fd, '</sheetData>'); fwrite($fd, '</sheetData>');
fwrite($fd, '<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>'); fwrite($fd, '<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>');
fwrite($fd, '<pageMargins left="0.5" right="0.5" top="1.0" bottom="1.0" header="0.5" footer="0.5"/>'); fwrite($fd, '<pageMargins left="0.5" right="0.5" top="1.0" bottom="1.0" header="0.5" footer="0.5"/>');
fwrite($fd, '<pageSetup blackAndWhite="false" cellComments="none" copies="1" draft="false" firstPageNumber="1" fitToHeight="1" fitToWidth="1" horizontalDpi="300" orientation="portrait" pageOrder="downThenOver" paperSize="1" scale="100" useFirstPageNumber="true" usePrinterDefaults="false" verticalDpi="300"/>'); fwrite($fd, '<pageSetup blackAndWhite="false" cellComments="none" copies="1" draft="false" firstPageNumber="1" fitToHeight="1" fitToWidth="1" horizontalDpi="300" orientation="portrait" pageOrder="downThenOver" paperSize="1" scale="100" useFirstPageNumber="true" usePrinterDefaults="false" verticalDpi="300"/>');
fwrite($fd, '<headerFooter differentFirst="false" differentOddEven="false">'); fwrite($fd, '<headerFooter differentFirst="false" differentOddEven="false">');
fwrite($fd, '<oddHeader>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12&amp;A</oddHeader>'); fwrite($fd, '<oddHeader>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12&amp;A</oddHeader>');
fwrite($fd, '<oddFooter>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12Page &amp;P</oddFooter>'); fwrite($fd, '<oddFooter>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12Page &amp;P</oddFooter>');
fwrite($fd, '</headerFooter>'); fwrite($fd, '</headerFooter>');
fwrite($fd,'</worksheet>'); fwrite($fd, '</worksheet>');
fclose($fd); fclose($fd);
} }
protected function writeCell($fd, $row_number, $column_number, $value, $cell_format) protected function writeCell($fd, $row_number, $column_number, $value, $cell_format)
{ {
static $styles = array('money'=>1,'dollar'=>1,'datetime'=>2,'date'=>3,'string'=>0); static $styles = ['money' => 1,'dollar' => 1,'datetime' => 2,'date' => 3,'string' => 0];
$cell = self::xlsCell($row_number, $column_number); $cell = self::xlsCell($row_number, $column_number);
$s = isset($styles[$cell_format]) && ($value !== '') ? $styles[$cell_format] : '0'; $s = isset($styles[$cell_format]) && ($value !== '') ? $styles[$cell_format] : '0';
if (is_int($value) || is_float($value)) { if (is_int($value) || is_float($value)) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.($value*1).'</v></c>');//int,float, etc fwrite($fd, '<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.($value * 1).'</v></c>');//int,float, etc
} else if (($cell_format=='date') && ($value != '')) { } elseif (($cell_format == 'date') && ($value != '')) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.intval(self::convert_date_time($value)).'</v></c>'); fwrite($fd, '<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.intval(self::convert_date_time($value)).'</v></c>');
} else if (($cell_format=='datetime') && ($value != '')) { } elseif (($cell_format == 'datetime') && ($value != '')) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>'); fwrite($fd, '<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
} else if ($value==''){ } elseif ($value == '') {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'"/>'); fwrite($fd, '<c r="'.$cell.'" s="'.$s.'"/>');
} else if ($value[0]=='='){ } elseif ($value[0] == '=') {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><f>'.self::xmlspecialchars($value).'</f></c>'); fwrite($fd, '<c r="'.$cell.'" s="'.$s.'" t="s"><f>'.self::xmlspecialchars($value).'</f></c>');
} else if ($value!==''){ } elseif ($value !== '') {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><v>'.self::xmlspecialchars($this->setSharedString($value)).'</v></c>'); fwrite($fd, '<c r="'.$cell.'" s="'.$s.'" t="s"><v>'.self::xmlspecialchars($this->setSharedString($value)).'</v></c>');
} }
} }
@@ -185,62 +196,65 @@ Class XLSXWriter
{ {
$tempfile = $this->tempFilename(); $tempfile = $this->tempFilename();
$fd = fopen($tempfile, "w+"); $fd = fopen($tempfile, "w+");
if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; } if ($fd === false) {
self::log("write failed in ".__CLASS__."::".__FUNCTION__.".");
return;
}
fwrite($fd, '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n"); fwrite($fd, '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
fwrite($fd, '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'); fwrite($fd, '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">');
fwrite($fd, '<numFmts count="4">'); fwrite($fd, '<numFmts count="4">');
fwrite($fd, '<numFmt formatCode="GENERAL" numFmtId="164"/>'); fwrite($fd, '<numFmt formatCode="GENERAL" numFmtId="164"/>');
fwrite($fd, '<numFmt formatCode="[$$-1009]#,##0.00;[RED]\-[$$-1009]#,##0.00" numFmtId="165"/>'); fwrite($fd, '<numFmt formatCode="[$$-1009]#,##0.00;[RED]\-[$$-1009]#,##0.00" numFmtId="165"/>');
fwrite($fd, '<numFmt formatCode="'.$this->date_time_format.'" numFmtId="166"/>'); fwrite($fd, '<numFmt formatCode="'.$this->date_time_format.'" numFmtId="166"/>');
fwrite($fd, '<numFmt formatCode="'.$this->date_format.'" numFmtId="167"/>'); fwrite($fd, '<numFmt formatCode="'.$this->date_format.'" numFmtId="167"/>');
fwrite($fd, '</numFmts>'); fwrite($fd, '</numFmts>');
fwrite($fd, '<fonts count="4">'); fwrite($fd, '<fonts count="4">');
fwrite($fd, '<font><name val="Arial"/><charset val="1"/><family val="2"/><sz val="10"/></font>'); fwrite($fd, '<font><name val="Arial"/><charset val="1"/><family val="2"/><sz val="10"/></font>');
fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>'); fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>'); fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>'); fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
fwrite($fd, '</fonts>'); fwrite($fd, '</fonts>');
fwrite($fd, '<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>'); fwrite($fd, '<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
fwrite($fd, '<borders count="1"><border diagonalDown="false" diagonalUp="false"><left/><right/><top/><bottom/><diagonal/></border></borders>'); fwrite($fd, '<borders count="1"><border diagonalDown="false" diagonalUp="false"><left/><right/><top/><bottom/><diagonal/></border></borders>');
fwrite($fd, '<cellStyleXfs count="15">'); fwrite($fd, '<cellStyleXfs count="15">');
fwrite($fd, '<xf applyAlignment="true" applyBorder="true" applyFont="true" applyProtection="true" borderId="0" fillId="0" fontId="0" numFmtId="164">'); fwrite($fd, '<xf applyAlignment="true" applyBorder="true" applyFont="true" applyProtection="true" borderId="0" fillId="0" fontId="0" numFmtId="164">');
fwrite($fd, '<alignment horizontal="general" indent="0" shrinkToFit="false" textRotation="0" vertical="bottom" wrapText="false"/>'); fwrite($fd, '<alignment horizontal="general" indent="0" shrinkToFit="false" textRotation="0" vertical="bottom" wrapText="false"/>');
fwrite($fd, '<protection hidden="false" locked="true"/>'); fwrite($fd, '<protection hidden="false" locked="true"/>');
fwrite($fd, '</xf>'); fwrite($fd, '</xf>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="43"/>'); //fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="43"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="41"/>'); //fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="41"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="44"/>'); //fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="44"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="42"/>'); //fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="42"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="9"/>'); //fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="9"/>');
fwrite($fd, '</cellStyleXfs>'); fwrite($fd, '</cellStyleXfs>');
fwrite($fd, '<cellXfs count="4">'); fwrite($fd, '<cellXfs count="4">');
fwrite($fd, '<xf applyAlignment="1" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="164" xfId="0"><alignment wrapText="1"/></xf>'); fwrite($fd, '<xf applyAlignment="1" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="164" xfId="0"><alignment wrapText="1"/></xf>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="165" xfId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="165" xfId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="166" xfId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="166" xfId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="167" xfId="0"/>'); fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="167" xfId="0"/>');
fwrite($fd, '</cellXfs>'); fwrite($fd, '</cellXfs>');
fwrite($fd, '<cellStyles count="1">'); fwrite($fd, '<cellStyles count="1">');
fwrite($fd, '<cellStyle builtinId="0" customBuiltin="false" name="Normal" xfId="0"/>'); fwrite($fd, '<cellStyle builtinId="0" customBuiltin="false" name="Normal" xfId="0"/>');
//fwrite($fd, '<cellStyle builtinId="3" customBuiltin="false" name="Comma" xfId="15"/>'); //fwrite($fd, '<cellStyle builtinId="3" customBuiltin="false" name="Comma" xfId="15"/>');
//fwrite($fd, '<cellStyle builtinId="6" customBuiltin="false" name="Comma [0]" xfId="16"/>'); //fwrite($fd, '<cellStyle builtinId="6" customBuiltin="false" name="Comma [0]" xfId="16"/>');
//fwrite($fd, '<cellStyle builtinId="4" customBuiltin="false" name="Currency" xfId="17"/>'); //fwrite($fd, '<cellStyle builtinId="4" customBuiltin="false" name="Currency" xfId="17"/>');
//fwrite($fd, '<cellStyle builtinId="7" customBuiltin="false" name="Currency [0]" xfId="18"/>'); //fwrite($fd, '<cellStyle builtinId="7" customBuiltin="false" name="Currency [0]" xfId="18"/>');
//fwrite($fd, '<cellStyle builtinId="5" customBuiltin="false" name="Percent" xfId="19"/>'); //fwrite($fd, '<cellStyle builtinId="5" customBuiltin="false" name="Percent" xfId="19"/>');
fwrite($fd, '</cellStyles>'); fwrite($fd, '</cellStyles>');
fwrite($fd, '</styleSheet>'); fwrite($fd, '</styleSheet>');
fclose($fd); fclose($fd);
return $tempfile; return $tempfile;
@@ -250,12 +264,9 @@ Class XLSXWriter
{ {
// Strip control characters which Excel does not seem to like... // Strip control characters which Excel does not seem to like...
$v = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F]/u', '', $v); $v = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F]/u', '', $v);
if (isset($this->shared_strings[$v])) if (isset($this->shared_strings[$v])) {
{
$string_value = $this->shared_strings[$v]; $string_value = $this->shared_strings[$v];
} } else {
else
{
$string_value = count($this->shared_strings); $string_value = count($this->shared_strings);
$this->shared_strings[$v] = $string_value; $this->shared_strings[$v] = $string_value;
} }
@@ -267,13 +278,15 @@ Class XLSXWriter
{ {
$tempfile = $this->tempFilename(); $tempfile = $this->tempFilename();
$fd = fopen($tempfile, "w+"); $fd = fopen($tempfile, "w+");
if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; } if ($fd === false) {
self::log("write failed in ".__CLASS__."::".__FUNCTION__.".");
fwrite($fd,'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n"); return;
fwrite($fd,'<sst count="'.($this->shared_string_count).'" uniqueCount="'.count($this->shared_strings).'" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'); }
foreach($this->shared_strings as $s=>$c)
{ fwrite($fd, '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
fwrite($fd,'<si><t>'.self::xmlspecialchars($s).'</t></si>'); fwrite($fd, '<sst count="'.($this->shared_string_count).'" uniqueCount="'.count($this->shared_strings).'" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">');
foreach ($this->shared_strings as $s => $c) {
fwrite($fd, '<si><t>'.self::xmlspecialchars($s).'</t></si>');
} }
fwrite($fd, '</sst>'); fwrite($fd, '</sst>');
fclose($fd); fclose($fd);
@@ -282,89 +295,89 @@ Class XLSXWriter
protected function buildAppXML() protected function buildAppXML()
{ {
$app_xml=""; $app_xml = "";
$app_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n"; $app_xml .= '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
$app_xml.='<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime></Properties>'; $app_xml .= '<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime></Properties>';
return $app_xml; return $app_xml;
} }
protected function buildCoreXML() protected function buildCoreXML()
{ {
$core_xml=""; $core_xml = "";
$core_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n"; $core_xml .= '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
$core_xml.='<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'; $core_xml .= '<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
$core_xml.='<dcterms:created xsi:type="dcterms:W3CDTF">'.date("Y-m-d\TH:i:s.00\Z").'</dcterms:created>';//$date_time = '2013-07-25T15:54:37.00Z'; $core_xml .= '<dcterms:created xsi:type="dcterms:W3CDTF">'.date("Y-m-d\TH:i:s.00\Z").'</dcterms:created>';//$date_time = '2013-07-25T15:54:37.00Z';
$core_xml.='<dc:creator>'.self::xmlspecialchars($this->author).'</dc:creator>'; $core_xml .= '<dc:creator>'.self::xmlspecialchars($this->author).'</dc:creator>';
$core_xml.='<cp:revision>0</cp:revision>'; $core_xml .= '<cp:revision>0</cp:revision>';
$core_xml.='</cp:coreProperties>'; $core_xml .= '</cp:coreProperties>';
return $core_xml; return $core_xml;
} }
protected function buildRelationshipsXML() protected function buildRelationshipsXML()
{ {
$rels_xml=""; $rels_xml = "";
$rels_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n"; $rels_xml .= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
$rels_xml.='<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'; $rels_xml .= '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
$rels_xml.='<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'; $rels_xml .= '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>';
$rels_xml.='<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>'; $rels_xml .= '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>';
$rels_xml.='<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>'; $rels_xml .= '<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>';
$rels_xml.="\n"; $rels_xml .= "\n";
$rels_xml.='</Relationships>'; $rels_xml .= '</Relationships>';
return $rels_xml; return $rels_xml;
} }
protected function buildWorkbookXML() protected function buildWorkbookXML()
{ {
$workbook_xml=""; $workbook_xml = "";
$workbook_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n"; $workbook_xml .= '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
$workbook_xml.='<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'; $workbook_xml .= '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">';
$workbook_xml.='<fileVersion appName="Calc"/><workbookPr backupFile="false" showObjects="all" date1904="false"/><workbookProtection/>'; $workbook_xml .= '<fileVersion appName="Calc"/><workbookPr backupFile="false" showObjects="all" date1904="false"/><workbookProtection/>';
$workbook_xml.='<bookViews><workbookView activeTab="0" firstSheet="0" showHorizontalScroll="true" showSheetTabs="true" showVerticalScroll="true" tabRatio="212" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/></bookViews>'; $workbook_xml .= '<bookViews><workbookView activeTab="0" firstSheet="0" showHorizontalScroll="true" showSheetTabs="true" showVerticalScroll="true" tabRatio="212" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/></bookViews>';
$workbook_xml.='<sheets>'; $workbook_xml .= '<sheets>';
foreach($this->sheets_meta as $i=>$sheet_meta) { foreach ($this->sheets_meta as $i => $sheet_meta) {
$workbook_xml.='<sheet name="'.self::xmlspecialchars($sheet_meta['sheetname']).'" sheetId="'.($i+1).'" state="visible" r:id="rId'.($i+2).'"/>'; $workbook_xml .= '<sheet name="'.self::xmlspecialchars($sheet_meta['sheetname']).'" sheetId="'.($i + 1).'" state="visible" r:id="rId'.($i + 2).'"/>';
} }
$workbook_xml.='</sheets>'; $workbook_xml .= '</sheets>';
$workbook_xml.='<calcPr iterateCount="100" refMode="A1" iterate="false" iterateDelta="0.001"/></workbook>'; $workbook_xml .= '<calcPr iterateCount="100" refMode="A1" iterate="false" iterateDelta="0.001"/></workbook>';
return $workbook_xml; return $workbook_xml;
} }
protected function buildWorkbookRelsXML() protected function buildWorkbookRelsXML()
{ {
$wkbkrels_xml=""; $wkbkrels_xml = "";
$wkbkrels_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n"; $wkbkrels_xml .= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
$wkbkrels_xml.='<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'; $wkbkrels_xml .= '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
$wkbkrels_xml.='<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'; $wkbkrels_xml .= '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>';
foreach($this->sheets_meta as $i=>$sheet_meta) { foreach ($this->sheets_meta as $i => $sheet_meta) {
$wkbkrels_xml.='<Relationship Id="rId'.($i+2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/'.($sheet_meta['xmlname']).'"/>'; $wkbkrels_xml .= '<Relationship Id="rId'.($i + 2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/'.($sheet_meta['xmlname']).'"/>';
} }
if (!empty($this->shared_strings)) { if (!empty($this->shared_strings)) {
$wkbkrels_xml.='<Relationship Id="rId'.(count($this->sheets_meta)+2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>'; $wkbkrels_xml .= '<Relationship Id="rId'.(count($this->sheets_meta) + 2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>';
} }
$wkbkrels_xml.="\n"; $wkbkrels_xml .= "\n";
$wkbkrels_xml.='</Relationships>'; $wkbkrels_xml .= '</Relationships>';
return $wkbkrels_xml; return $wkbkrels_xml;
} }
protected function buildContentTypesXML() protected function buildContentTypesXML()
{ {
$content_types_xml=""; $content_types_xml = "";
$content_types_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n"; $content_types_xml .= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
$content_types_xml.='<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'; $content_types_xml .= '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
$content_types_xml.='<Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'; $content_types_xml .= '<Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>';
$content_types_xml.='<Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'; $content_types_xml .= '<Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>';
foreach($this->sheets_meta as $i=>$sheet_meta) { foreach ($this->sheets_meta as $i => $sheet_meta) {
$content_types_xml.='<Override PartName="/xl/worksheets/'.($sheet_meta['xmlname']).'" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>'; $content_types_xml .= '<Override PartName="/xl/worksheets/'.($sheet_meta['xmlname']).'" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>';
} }
if (!empty($this->shared_strings)) { if (!empty($this->shared_strings)) {
$content_types_xml.='<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>'; $content_types_xml .= '<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>';
} }
$content_types_xml.='<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'; $content_types_xml .= '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>';
$content_types_xml.='<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>'; $content_types_xml .= '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>';
$content_types_xml.='<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>'; $content_types_xml .= '<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>';
$content_types_xml.='<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>'; $content_types_xml .= '<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>';
$content_types_xml.="\n"; $content_types_xml .= "\n";
$content_types_xml.='</Types>'; $content_types_xml .= '</Types>';
return $content_types_xml; return $content_types_xml;
} }
@@ -377,10 +390,10 @@ Class XLSXWriter
public static function xlsCell($row_number, $column_number) public static function xlsCell($row_number, $column_number)
{ {
$n = $column_number; $n = $column_number;
for($r = ""; $n >= 0; $n = intval($n / 26) - 1) { for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
$r = chr($n%26 + 0x41) . $r; $r = chr($n % 26 + 0x41).$r;
} }
return $r . ($row_number+1); return $r.($row_number + 1);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
public static function log($string) public static function log($string)
@@ -404,26 +417,30 @@ Class XLSXWriter
{ {
$days = 0; # Number of days since epoch $days = 0; # Number of days since epoch
$seconds = 0; # Time expressed as fraction of 24h hours in seconds $seconds = 0; # Time expressed as fraction of 24h hours in seconds
$year=$month=$day=0; $year = $month = $day = 0;
$hour=$min =$sec=0; $hour = $min = $sec = 0;
$date_time = $date_input; $date_time = $date_input;
if (preg_match("/(\d{4})\-(\d{2})\-(\d{2})/", $date_time, $matches)) if (preg_match("/(\d{4})\-(\d{2})\-(\d{2})/", $date_time, $matches)) {
{ list($junk, $year, $month, $day) = $matches;
list($junk,$year,$month,$day) = $matches;
} }
if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $date_time, $matches)) if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $date_time, $matches)) {
{ list($junk, $hour, $min, $sec) = $matches;
list($junk,$hour,$min,$sec) = $matches; $seconds = ($hour * 60 * 60 + $min * 60 + $sec) / (24 * 60 * 60);
$seconds = ( $hour * 60 * 60 + $min * 60 + $sec ) / ( 24 * 60 * 60 );
} }
//using 1900 as epoch, not 1904, ignoring 1904 special case //using 1900 as epoch, not 1904, ignoring 1904 special case
# Special cases for Excel. # Special cases for Excel.
if ("$year-$month-$day"=='1899-12-31') return $seconds ; # Excel 1900 epoch if ("$year-$month-$day" == '1899-12-31') {
if ("$year-$month-$day"=='1900-01-00') return $seconds ; # Excel 1900 epoch return $seconds ;
if ("$year-$month-$day"=='1900-02-29') return 60 + $seconds ; # Excel false leapday } # Excel 1900 epoch
if ("$year-$month-$day" == '1900-01-00') {
return $seconds ;
} # Excel 1900 epoch
if ("$year-$month-$day" == '1900-02-29') {
return 60 + $seconds ;
} # Excel false leapday
# We calculate the date by calculating the number of days since the epoch # We calculate the date by calculating the number of days since the epoch
# and adjust for the number of leap days. We calculate the number of leap # and adjust for the number of leap days. We calculate the number of leap
@@ -435,33 +452,35 @@ Class XLSXWriter
$range = $year - $epoch; $range = $year - $epoch;
# Set month days and check for leap year. # Set month days and check for leap year.
$leap = (($year % 400 == 0) || (($year % 4 == 0) && ($year % 100)) ) ? 1 : 0; $leap = (($year % 400 == 0) || (($year % 4 == 0) && ($year % 100))) ? 1 : 0;
$mdays = array( 31, ($leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); $mdays = [ 31, ($leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
# Some boundary checks # Some boundary checks
if($year < $epoch || $year > 9999) return 0; if ($year < $epoch || $year > 9999) {
if($month < 1 || $month > 12) return 0; return 0;
if($day < 1 || $day > $mdays[ $month - 1 ]) return 0; }
if ($month < 1 || $month > 12) {
return 0;
}
if ($day < 1 || $day > $mdays[ $month - 1 ]) {
return 0;
}
# Accumulate the number of days since the epoch. # Accumulate the number of days since the epoch.
$days = $day; # Add days for current month $days = $day; # Add days for current month
$days += array_sum( array_slice($mdays, 0, $month-1 ) ); # Add days for past months $days += array_sum(array_slice($mdays, 0, $month - 1)); # Add days for past months
$days += $range * 365; # Add days for past years $days += $range * 365; # Add days for past years
$days += intval( ( $range ) / 4 ); # Add leapdays $days += intval(($range) / 4); # Add leapdays
$days -= intval( ( $range + $offset ) / 100 ); # Subtract 100 year leapdays $days -= intval(($range + $offset) / 100); # Subtract 100 year leapdays
$days += intval( ( $range + $offset + $norm ) / 400 ); # Add 400 year leapdays $days += intval(($range + $offset + $norm) / 400); # Add 400 year leapdays
$days -= $leap; # Already counted above $days -= $leap; # Already counted above
# Adjust for Excel erroneously treating 1900 as a leap year. # Adjust for Excel erroneously treating 1900 as a leap year.
if ($days > 59) { $days++;} if ($days > 59) {
$days++;
}
return $days + $seconds; return $days + $seconds;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
} }

View File

@@ -18,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
*/ */
/** /**
* Checks PHP version * Checks PHP version
* *
@@ -39,7 +38,6 @@ if (PHP_MAJOR_VERSION >= 7) {
exit(-1); exit(-1);
} }
define('ITOP_DEFAULT_ENV', 'production'); define('ITOP_DEFAULT_ENV', 'production');
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance'); define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
define('READONLY_MODE_FILE', APPROOT.'data/.readonly'); define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
@@ -60,8 +58,7 @@ if (!isset($bBypassMaintenance)) {
$bBypassMaintenance = isset($_REQUEST['maintenance']) ? boolval($_REQUEST['maintenance']) : false; $bBypassMaintenance = isset($_REQUEST['maintenance']) ? boolval($_REQUEST['maintenance']) : false;
} }
if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance) if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance) {
{
$sTitle = 'Maintenance'; $sTitle = 'Maintenance';
$sMessage = 'This application is currently under maintenance.'; $sMessage = 'This application is currently under maintenance.';
@@ -70,8 +67,7 @@ if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance)
include(APPROOT.'application/maintenancemsg.php'); include(APPROOT.'application/maintenancemsg.php');
$sSAPIName = strtoupper(trim(PHP_SAPI)); $sSAPIName = strtoupper(trim(PHP_SAPI));
switch (true) switch (true) {
{
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/pages/ajax.searchform.php'): case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/pages/ajax.searchform.php'):
_MaintenanceHtmlMessage($sMessage); _MaintenanceHtmlMessage($sMessage);
break; break;
@@ -102,6 +98,7 @@ if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance)
* *
* @return bool * @return bool
*/ */
function EndsWith($haystack, $needle) { function EndsWith($haystack, $needle)
{
return substr_compare($haystack, $needle, -strlen($needle)) === 0; return substr_compare($haystack, $needle, -strlen($needle)) === 0;
} }

View File

@@ -1,2 +1,3 @@
<?php <?php
echo 'Access denied'; echo 'Access denied';

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -67,9 +68,8 @@ class DbConnectionWrapper
if (is_null($oMysqli)) { if (is_null($oMysqli)) {
// Reset to standard connection // Reset to standard connection
static::$oDbCnxMockableForQuery = static::$oDbCnxStandard; static::$oDbCnxMockableForQuery = static::$oDbCnxStandard;
} } else {
else {
static::$oDbCnxMockableForQuery = $oMysqli; static::$oDbCnxMockableForQuery = $oMysqli;
} }
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Various dev/debug helpers * Various dev/debug helpers
* TODO: cleanup or at least re-organize * TODO: cleanup or at least re-organize
@@ -25,7 +25,6 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
/** /**
* MyHelpers * MyHelpers
* *
@@ -35,28 +34,23 @@ class MyHelpers
{ {
public static function CheckValueInArray($sDescription, $value, $aData) public static function CheckValueInArray($sDescription, $value, $aData)
{ {
if (!in_array($value, $aData)) if (!in_array($value, $aData)) {
{
self::HandleWrongValue($sDescription, $value, $aData); self::HandleWrongValue($sDescription, $value, $aData);
} }
} }
public static function CheckKeyInArray($sDescription, $key, $aData) public static function CheckKeyInArray($sDescription, $key, $aData)
{ {
if (!array_key_exists($key, $aData)) if (!array_key_exists($key, $aData)) {
{
self::HandleWrongValue($sDescription, $key, array_keys($aData)); self::HandleWrongValue($sDescription, $key, array_keys($aData));
} }
} }
public static function HandleWrongValue($sDescription, $value, $aData) public static function HandleWrongValue($sDescription, $value, $aData)
{ {
if (count($aData) == 0) if (count($aData) == 0) {
{
$sArrayDesc = "{}"; $sArrayDesc = "{}";
} } else {
else
{
$sArrayDesc = "{".implode(", ", $aData)."}"; $sArrayDesc = "{".implode(", ", $aData)."}";
} }
// exit! // exit!
@@ -64,7 +58,7 @@ class MyHelpers
} }
// getmicrotime() // getmicrotime()
// format sss.mmmuuupppnnn // format sss.mmmuuupppnnn
public static function getmicrotime() public static function getmicrotime()
{ {
return microtime(true); return microtime(true);
@@ -74,14 +68,15 @@ class MyHelpers
* MakeSQLComment * MakeSQLComment
* converts hash into text comment which we can use in a (mySQL) query * converts hash into text comment which we can use in a (mySQL) query
*/ */
public static function MakeSQLComment ($aHash) public static function MakeSQLComment($aHash)
{ {
if (empty($aHash)) return ""; if (empty($aHash)) {
return "";
}
$sComment = ""; $sComment = "";
{ {
foreach($aHash as $sKey=>$sValue) foreach ($aHash as $sKey => $sValue) {
{ $sComment .= "\n-- ".$sKey."=>".$sValue;
$sComment .= "\n-- ". $sKey ."=>" . $sValue;
} }
} }
return $sComment; return $sComment;
@@ -90,12 +85,9 @@ class MyHelpers
public static function var_dump_html($aWords, $bFullDisplay = false) public static function var_dump_html($aWords, $bFullDisplay = false)
{ {
echo "<pre>\n"; echo "<pre>\n";
if ($bFullDisplay) if ($bFullDisplay) {
{
print_r($aWords); // full dump! print_r($aWords); // full dump!
} } else {
else
{
var_dump($aWords); // truncate things when they are too big var_dump($aWords); // truncate things when they are too big
} }
echo "\n</pre>\n"; echo "\n</pre>\n";
@@ -123,9 +115,10 @@ class MyHelpers
{ {
$aLines1 = explode("\n", $s1); $aLines1 = explode("\n", $s1);
$aLines2 = explode("\n", $s2); $aLines2 = explode("\n", $s2);
for ($i = 0 ; $i < min(count($aLines1), count($aLines2)) ; $i++) for ($i = 0 ; $i < min(count($aLines1), count($aLines2)) ; $i++) {
{ if ($aLines1[$i] != $aLines2[$i]) {
if ($aLines1[$i] != $aLines2[$i]) return $i; return $i;
}
} }
return false; return false;
} }
@@ -142,9 +135,10 @@ class MyHelpers
// do not work fine with multiline strings // do not work fine with multiline strings
$iLen1 = strlen($s1); $iLen1 = strlen($s1);
$iLen2 = strlen($s2); $iLen2 = strlen($s2);
for ($i = 0 ; $i < min($iLen1, $iLen2) ; $i++) for ($i = 0 ; $i < min($iLen1, $iLen2) ; $i++) {
{ if ($s1[$i] !== $s2[$i]) {
if ($s1[$i] !== $s2[$i]) return $i; return $i;
}
} }
return false; return false;
} }
@@ -154,9 +148,10 @@ class MyHelpers
// do not work fine with multiline strings // do not work fine with multiline strings
$iLen1 = strlen($s1); $iLen1 = strlen($s1);
$iLen2 = strlen($s2); $iLen2 = strlen($s2);
for ($i = 0 ; $i < min(strlen($s1), strlen($s2)) ; $i++) for ($i = 0 ; $i < min(strlen($s1), strlen($s2)) ; $i++) {
{ if ($s1[$iLen1 - $i - 1] !== $s2[$iLen2 - $i - 1]) {
if ($s1[$iLen1 - $i - 1] !== $s2[$iLen2 - $i - 1]) return array($iLen1 - $i, $iLen2 - $i); return [$iLen1 - $i, $iLen2 - $i];
}
} }
return false; return false;
} }
@@ -177,8 +172,7 @@ class MyHelpers
protected static function string_cmp_html($s1, $s2, $sHighlight) protected static function string_cmp_html($s1, $s2, $sHighlight)
{ {
$iDiffPos = self::first_diff($s1, $s2); $iDiffPos = self::first_diff($s1, $s2);
if ($iDiffPos === false) if ($iDiffPos === false) {
{
echo "strings are identical"; echo "strings are identical";
return; return;
} }
@@ -189,7 +183,7 @@ class MyHelpers
$sMiddle1 = substr($s1, $iDiffPos, $aLastDiff[0] - $iDiffPos); $sMiddle1 = substr($s1, $iDiffPos, $aLastDiff[0] - $iDiffPos);
$sMiddle2 = substr($s2, $iDiffPos, $aLastDiff[1] - $iDiffPos); $sMiddle2 = substr($s2, $iDiffPos, $aLastDiff[1] - $iDiffPos);
echo "<p>$sStart<span style=\"$sHighlight\">$sMiddle1</span>$sEnd</p>\n"; echo "<p>$sStart<span style=\"$sHighlight\">$sMiddle1</span>$sEnd</p>\n";
echo "<p>$sStart<span style=\"$sHighlight\">$sMiddle2</span>$sEnd</p>\n"; echo "<p>$sStart<span style=\"$sHighlight\">$sMiddle2</span>$sEnd</p>\n";
} }
@@ -203,40 +197,34 @@ class MyHelpers
public static function var_cmp_html($var1, $var2, $sHighlight = 'color:red; font-weight:bold;') public static function var_cmp_html($var1, $var2, $sHighlight = 'color:red; font-weight:bold;')
{ {
if (is_object($var1)) if (is_object($var1)) {
{
return self::object_cmp_html($var1, $var2, $sHighlight); return self::object_cmp_html($var1, $var2, $sHighlight);
} } elseif (count(explode("\n", $var1)) > 1) {
else if (count(explode("\n", $var1)) > 1)
{
// multiline string // multiline string
return self::text_cmp_html($var1, $var2, $sHighlight); return self::text_cmp_html($var1, $var2, $sHighlight);
} } else {
else
{
return self::string_cmp_html($var1, $var2, $sHighlight); return self::string_cmp_html($var1, $var2, $sHighlight);
} }
} }
public static function get_callstack($iLevelsToIgnore = 0, $aCallStack = null) public static function get_callstack($iLevelsToIgnore = 0, $aCallStack = null)
{ {
if ($aCallStack == null) $aCallStack = debug_backtrace(); if ($aCallStack == null) {
$aCallStack = debug_backtrace();
}
$aCallStack = array_slice($aCallStack, $iLevelsToIgnore); $aCallStack = array_slice($aCallStack, $iLevelsToIgnore);
$aDigestCallStack = array(); $aDigestCallStack = [];
$bFirstLine = true; $bFirstLine = true;
foreach ($aCallStack as $aCallInfo) foreach ($aCallStack as $aCallInfo) {
{
$sLine = empty($aCallInfo['line']) ? "" : $aCallInfo['line']; $sLine = empty($aCallInfo['line']) ? "" : $aCallInfo['line'];
$sFile = empty($aCallInfo['file']) ? "" : $aCallInfo['file']; $sFile = empty($aCallInfo['file']) ? "" : $aCallInfo['file'];
if ($sFile != '') if ($sFile != '') {
{
$sFile = str_replace('\\', '/', $sFile); $sFile = str_replace('\\', '/', $sFile);
$sAppRoot = str_replace('\\', '/', APPROOT); $sAppRoot = str_replace('\\', '/', APPROOT);
$iPos = strpos($sFile, $sAppRoot); $iPos = strpos($sFile, $sAppRoot);
if ($iPos !== false) if ($iPos !== false) {
{
$sFile = substr($sFile, strlen($sAppRoot)); $sFile = substr($sFile, strlen($sAppRoot));
} }
} }
@@ -244,55 +232,51 @@ class MyHelpers
$sType = empty($aCallInfo['type']) ? "" : $aCallInfo['type']; $sType = empty($aCallInfo['type']) ? "" : $aCallInfo['type'];
$sFunction = empty($aCallInfo['function']) ? "" : $aCallInfo['function']; $sFunction = empty($aCallInfo['function']) ? "" : $aCallInfo['function'];
if ($bFirstLine) if ($bFirstLine) {
{
$bFirstLine = false; $bFirstLine = false;
// For this line do not display the "function name" because // For this line do not display the "function name" because
// that will be the name of our error handler for sure ! // that will be the name of our error handler for sure !
$sFunctionInfo = "N/A"; $sFunctionInfo = "N/A";
} } else {
else
{
$args = ''; $args = '';
if (empty($aCallInfo['args'])) $aCallInfo['args'] = array(); if (empty($aCallInfo['args'])) {
foreach ($aCallInfo['args'] as $a) $aCallInfo['args'] = [];
{ }
if (!empty($args)) foreach ($aCallInfo['args'] as $a) {
{ if (!empty($args)) {
$args .= ', '; $args .= ', ';
} }
switch (gettype($a)) switch (gettype($a)) {
{
case 'integer': case 'integer':
case 'double': case 'double':
$args .= $a; $args .= $a;
break; break;
case 'string': case 'string':
$a = Str::pure2html(self::beautifulstr($a, 64, true, false)); $a = Str::pure2html(self::beautifulstr($a, 64, true, false));
$args .= "\"$a\""; $args .= "\"$a\"";
break; break;
case 'array': case 'array':
$args .= 'array('.count($a).')'; $args .= 'array('.count($a).')';
break; break;
case 'object': case 'object':
$args .= 'Object('.get_class($a).')'; $args .= 'Object('.get_class($a).')';
break; break;
case 'resource': case 'resource':
$args .= 'Resource('.strstr($a, '#').')'; $args .= 'Resource('.strstr($a, '#').')';
break; break;
case 'boolean': case 'boolean':
$args .= $a ? 'true' : 'false'; $args .= $a ? 'true' : 'false';
break; break;
case 'NULL': case 'NULL':
$args .= 'null'; $args .= 'null';
break; break;
default: default:
$args .= 'Unknown'; $args .= 'Unknown';
} }
} }
$sFunctionInfo = "$sClass$sType$sFunction($args)"; $sFunctionInfo = "$sClass$sType$sFunction($args)";
} }
$aDigestCallStack[] = array('File'=>$sFile, 'Line'=>$sLine, 'Function'=>$sFunctionInfo); $aDigestCallStack[] = ['File' => $sFile, 'Line' => $sLine, 'Function' => $sFunctionInfo];
} }
return $aDigestCallStack; return $aDigestCallStack;
} }
@@ -311,9 +295,8 @@ class MyHelpers
public static function get_callstack_text($iLevelsToIgnore = 0, $aCallStack = null) public static function get_callstack_text($iLevelsToIgnore = 0, $aCallStack = null)
{ {
$aDigestCallStack = self::get_callstack($iLevelsToIgnore, $aCallStack); $aDigestCallStack = self::get_callstack($iLevelsToIgnore, $aCallStack);
$aRes = array(); $aRes = [];
foreach ($aDigestCallStack as $aCall) foreach ($aDigestCallStack as $aCall) {
{
$aRes[] = $aCall['File'].' at '.$aCall['Line'].', '.$aCall['Function']; $aRes[] = $aCall['File'].' at '.$aCall['Line'].', '.$aCall['Function'];
} }
return implode("\n", $aRes); return implode("\n", $aRes);
@@ -325,21 +308,27 @@ class MyHelpers
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
public static function make_table_from_assoc_array(&$aData) public static function make_table_from_assoc_array(&$aData)
{ {
if (!is_array($aData)) throw new CoreException("make_table_from_assoc_array: Error - the passed argument is not an array"); if (!is_array($aData)) {
throw new CoreException("make_table_from_assoc_array: Error - the passed argument is not an array");
}
$aFirstRow = reset($aData); $aFirstRow = reset($aData);
if (count($aData) == 0) return ''; if (count($aData) == 0) {
if (!is_array($aFirstRow)) throw new CoreException("make_table_from_assoc_array: Error - the passed argument is not a bi-dimensional array"); return '';
}
if (!is_array($aFirstRow)) {
throw new CoreException("make_table_from_assoc_array: Error - the passed argument is not a bi-dimensional array");
}
$sOutput = ""; $sOutput = "";
$sOutput .= "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"1\" CELLPADDING=\"1\">\n"; $sOutput .= "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"1\" CELLPADDING=\"1\">\n";
// Table header // Table header
// //
$sOutput .= " <TR CLASS=celltitle>\n"; $sOutput .= " <TR CLASS=celltitle>\n";
foreach ($aFirstRow as $fieldname=>$trash) { foreach ($aFirstRow as $fieldname => $trash) {
$sOutput .= " <TD><B>".$fieldname."</B></TD>\n"; $sOutput .= " <TD><B>".$fieldname."</B></TD>\n";
} }
$sOutput .= " </TR>\n"; $sOutput .= " </TR>\n";
// Table contents // Table contents
// //
$iCount = 0; $iCount = 0;
@@ -354,7 +343,7 @@ class MyHelpers
} }
$sOutput .= " </TR>\n"; $sOutput .= " </TR>\n";
} }
$sOutput .= "</TABLE>\n"; $sOutput .= "</TABLE>\n";
return $sOutput; return $sOutput;
} }
@@ -368,7 +357,9 @@ class MyHelpers
} }
public static function debug_breakpoint_notempty($arg) public static function debug_breakpoint_notempty($arg)
{ {
if (empty($arg)) return; if (empty($arg)) {
return;
}
echo "<H1> Debug breakpoint (triggered on non-empty value) </H1>\n"; echo "<H1> Debug breakpoint (triggered on non-empty value) </H1>\n";
MyHelpers::var_dump_html($arg); MyHelpers::var_dump_html($arg);
MyHelpers::dump_callstack(); MyHelpers::dump_callstack();
@@ -381,7 +372,7 @@ class MyHelpers
*/ */
public static function xmlentities($string) public static function xmlentities($string)
{ {
return str_replace( array( '&', '"', "'", '<', '>' ), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;' ), $string ); return str_replace([ '&', '"', "'", '<', '>' ], [ '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;' ], $string);
} }
/** /**
@@ -390,20 +381,24 @@ class MyHelpers
*/ */
public static function xmlencode($string) public static function xmlencode($string)
{ {
return xmlentities(iconv("UTF-8", "UTF-8//IGNORE",$string)); return xmlentities(iconv("UTF-8", "UTF-8//IGNORE", $string));
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Source: New - format strings for output // Source: New - format strings for output
// Last modif: 2005/01/18 RQU // Last modif: 2005/01/18 RQU
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
public static function beautifulstr($sLongString, $iMaxLen, $bShowLen=false, $bShowTooltip=true) public static function beautifulstr($sLongString, $iMaxLen, $bShowLen = false, $bShowTooltip = true)
{ {
if (!is_string($sLongString)) throw new CoreException("beautifulstr: expect a string as 1st argument"); if (!is_string($sLongString)) {
throw new CoreException("beautifulstr: expect a string as 1st argument");
}
// Nothing to do if the string is short // Nothing to do if the string is short
if (strlen($sLongString) <= $iMaxLen) return $sLongString; if (strlen($sLongString) <= $iMaxLen) {
return $sLongString;
}
// Truncate the string // Truncate the string
$sSuffix = "..."; $sSuffix = "...";
if ($bShowLen) { if ($bShowLen) {
@@ -411,7 +406,7 @@ class MyHelpers
} }
$sOutput = substr($sLongString, 0, $iMaxLen - strlen($sSuffix)).$sSuffix; $sOutput = substr($sLongString, 0, $iMaxLen - strlen($sSuffix)).$sSuffix;
$sOutput = htmlspecialchars($sOutput); $sOutput = htmlspecialchars($sOutput);
// Add tooltip if required // Add tooltip if required
//if ($bShowTooltip) { //if ($bShowTooltip) {
// $oTooltip = new gui_tooltip($sLongString); // $oTooltip = new gui_tooltip($sLongString);
@@ -427,11 +422,11 @@ Utility class: static methods for cleaning & escaping untrusted (i.e.
user-supplied) strings. user-supplied) strings.
Any string can (usually) be thought of as being in one of these 'modes': Any string can (usually) be thought of as being in one of these 'modes':
pure = what the user actually typed / what you want to see on the page / pure = what the user actually typed / what you want to see on the page /
what is actually stored in the DB what is actually stored in the DB
gpc = incoming GET, POST or COOKIE data gpc = incoming GET, POST or COOKIE data
sql = escaped for passing safely to RDBMS via SQL (also, data from DB sql = escaped for passing safely to RDBMS via SQL (also, data from DB
queries and file reads if you have magic_quotes_runtime on--which queries and file reads if you have magic_quotes_runtime on--which
is rare) is rare)
html = safe for html display (htmlentities applied) html = safe for html display (htmlentities applied)
Always knowing what mode your string is in--using these methods to Always knowing what mode your string is in--using these methods to
convert between modes--will prevent SQL injection and cross-site scripting. convert between modes--will prevent SQL injection and cross-site scripting.
@@ -456,8 +451,11 @@ class Str
} }
public static function gpc2pure($gpc) public static function gpc2pure($gpc)
{ {
if (ini_get('magic_quotes_sybase')) $pure = str_replace("''", "'", $gpc); if (ini_get('magic_quotes_sybase')) {
else $pure = $gpc; $pure = str_replace("''", "'", $gpc);
} else {
$pure = $gpc;
}
return $pure; return $pure;
} }
public static function html2pure($html) public static function html2pure($html)
@@ -477,7 +475,9 @@ class Str
} }
public static function pure2sql($pure, $maxLength = false) public static function pure2sql($pure, $maxLength = false)
{ {
if ($maxLength) $pure = substr($pure, 0, $maxLength); if ($maxLength) {
$pure = substr($pure, 0, $maxLength);
}
return (STR_SYBASE) return (STR_SYBASE)
? str_replace("'", "''", $pure) ? str_replace("'", "''", $pure)
: addslashes($pure); : addslashes($pure);
@@ -485,7 +485,9 @@ class Str
public static function sql2html($sql, $maxLength = false) public static function sql2html($sql, $maxLength = false)
{ {
$pure = self::sql2pure($sql); $pure = self::sql2pure($sql);
if ($maxLength) $pure = substr($pure, 0, $maxLength); if ($maxLength) {
$pure = substr($pure, 0, $maxLength);
}
return self::pure2html($pure); return self::pure2html($pure);
} }
public static function sql2pure($sql) public static function sql2pure($sql)
@@ -507,7 +509,7 @@ class Str
protected static function xmlentities($string) protected static function xmlentities($string)
{ {
return str_replace( array( '&', '"', "'", '<', '>' ), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;' ), $string ); return str_replace([ '&', '"', "'", '<', '>' ], [ '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;' ], $string);
} }
/** /**
@@ -516,7 +518,7 @@ class Str
*/ */
protected static function xmlencode($string) protected static function xmlencode($string)
{ {
return self::xmlentities(iconv("UTF-8", "UTF-8//IGNORE",$string)); return self::xmlentities(iconv("UTF-8", "UTF-8//IGNORE", $string));
} }
public static function islowcase($sString) public static function islowcase($sString)

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -17,64 +18,64 @@ class TemporaryObjectDescriptor extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array( $aParams = [
'category' => 'core', 'category' => 'core',
'key_type' => 'autoincrement', 'key_type' => 'autoincrement',
'name_attcode' => array('item_class', 'temp_id'), 'name_attcode' => ['item_class', 'temp_id'],
'image_attcode' => '', 'image_attcode' => '',
'state_attcode' => '', 'state_attcode' => '',
'reconc_keys' => array(''), 'reconc_keys' => [''],
'db_table' => 'priv_temporary_object_descriptor', 'db_table' => 'priv_temporary_object_descriptor',
'db_key_field' => 'id', 'db_key_field' => 'id',
'db_finalclass_field' => '', 'db_finalclass_field' => '',
'style' => new ormStyle(null, null, null, null, null, null), 'style' => new ormStyle(null, null, null, null, null, null),
'indexes' => array( 'indexes' => [
1 => 1 =>
array( [
0 => 'temp_id', 0 => 'temp_id',
), ],
2 => 2 =>
array( [
0 => 'item_class', 0 => 'item_class',
1 => 'item_id', 1 => 'item_id',
), ],
), ],
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime('expiration_date', array('sql' => 'expiration_date', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeDateTime('expiration_date', ['sql' => 'expiration_date', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeString('temp_id', array('sql' => 'temp_id', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeString('temp_id', ['sql' => 'temp_id', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeString('item_class', array('sql' => 'item_class', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeString('item_class', ['sql' => 'item_class', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeObjectKey('item_id', array('class_attcode' => 'item_class', 'sql' => 'item_id', 'is_null_allowed' => true, 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeObjectKey('item_id', ['class_attcode' => 'item_class', 'sql' => 'item_id', 'is_null_allowed' => true, 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeDateTime('creation_date', array('sql' => 'creation_date', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeDateTime('creation_date', ['sql' => 'creation_date', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeString('host_class', array('sql' => 'host_class', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeString('host_class', ['sql' => 'host_class', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeObjectKey('host_id', array('class_attcode' => 'host_class', 'sql' => 'host_id', 'is_null_allowed' => true, 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeObjectKey('host_id', ['class_attcode' => 'host_class', 'sql' => 'host_id', 'is_null_allowed' => true, 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeString('host_att_code', array('sql' => 'host_att_code', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false))); MetaModel::Init_AddAttribute(new AttributeString('host_att_code', ['sql' => 'host_att_code', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]));
MetaModel::Init_AddAttribute(new AttributeEnum("operation", array("allowed_values" => new ValueSetEnum('create,delete'), "sql" => "operation", "default_value" => "create", "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeEnum("operation", ["allowed_values" => new ValueSetEnum('create,delete'), "sql" => "operation", "default_value" => "create", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_SetZListItems('details', array( MetaModel::Init_SetZListItems('details', [
0 => 'temp_id', 0 => 'temp_id',
1 => 'item_class', 1 => 'item_class',
2 => 'item_id', 2 => 'item_id',
3 => 'creation_date', 3 => 'creation_date',
4 => 'expiration_date', 4 => 'expiration_date',
5 => 'meta', 5 => 'meta',
)); ]);
MetaModel::Init_SetZListItems('standard_search', array( MetaModel::Init_SetZListItems('standard_search', [
0 => 'temp_id', 0 => 'temp_id',
1 => 'item_class', 1 => 'item_class',
2 => 'item_id', 2 => 'item_id',
)); ]);
MetaModel::Init_SetZListItems('list', array( MetaModel::Init_SetZListItems('list', [
0 => 'temp_id', 0 => 'temp_id',
1 => 'item_class', 1 => 'item_class',
2 => 'item_id', 2 => 'item_id',
3 => 'creation_date', 3 => 'creation_date',
4 => 'expiration_date', 4 => 'expiration_date',
));; ]);
;
} }
public function DBInsertNoReload() public function DBInsertNoReload()
{ {
$this->SetCurrentDateIfNull('creation_date'); $this->SetCurrentDateIfNull('creation_date');
@@ -82,7 +83,6 @@ class TemporaryObjectDescriptor extends DBObject
return parent::DBInsertNoReload(); return parent::DBInsertNoReload();
} }
/** /**
* Set/Update all of the '_item' fields * Set/Update all of the '_item' fields
* *

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -30,12 +31,11 @@ use Combodo\iTop\Service\Router\Router;
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT.'/core/asynctask.class.inc.php'); require_once(APPROOT.'/core/asynctask.class.inc.php');
require_once(APPROOT.'/core/email.class.inc.php'); require_once(APPROOT.'/core/email.class.inc.php');
/** /**
* A user defined action, to customize the application * A user defined action, to customize the application
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -47,8 +47,8 @@ abstract class Action extends cmdbAbstractObject
*/ */
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "grant_by_profile,core/cmdb", "category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
@@ -59,14 +59,14 @@ abstract class Action extends cmdbAbstractObject
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
"style" => new ormStyle("ibo-dm-class--Action", "ibo-dm-class-alt--Action", "var(--ibo-dm-class--Action--main-color)", "var(--ibo-dm-class--Action--complementary-color)", null, '../images/icons/icons8-in-transit.svg'), "style" => new ormStyle("ibo-dm-class--Action", "ibo-dm-class-alt--Action", "var(--ibo-dm-class--Action--main-color)", "var(--ibo-dm-class--Action--complementary-color)", null, '../images/icons/icons8-in-transit.svg'),
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array( MetaModel::Init_AddAttribute(new AttributeEnum("status", [
"allowed_values" => new ValueSetEnum(array('test' => 'Being tested', 'enabled' => 'In production', 'disabled' => 'Inactive')), "allowed_values" => new ValueSetEnum(['test' => 'Being tested', 'enabled' => 'In production', 'disabled' => 'Inactive']),
"styled_values" => [ "styled_values" => [
'test' => new ormStyle('ibo-dm-enum--Action-status-test', 'ibo-dm-enum-alt--Action-status-test', 'var(--ibo-dm-enum--Action-status-test--main-color)', 'var(--ibo-dm-enum--Action-status-test--complementary-color)', null, null), 'test' => new ormStyle('ibo-dm-enum--Action-status-test', 'ibo-dm-enum-alt--Action-status-test', 'var(--ibo-dm-enum--Action-status-test--main-color)', 'var(--ibo-dm-enum--Action-status-test--complementary-color)', null, null),
'enabled' => new ormStyle('ibo-dm-enum--Action-status-enabled', 'ibo-dm-enum-alt--Action-status-enabled', 'var(--ibo-dm-enum--Action-status-enabled--main-color)', 'var(--ibo-dm-enum--Action-status-enabled--complementary-color)', 'fas fa-check', null), 'enabled' => new ormStyle('ibo-dm-enum--Action-status-enabled', 'ibo-dm-enum-alt--Action-status-enabled', 'var(--ibo-dm-enum--Action-status-enabled--main-color)', 'var(--ibo-dm-enum--Action-status-enabled--complementary-color)', 'fas fa-check', null),
@@ -76,21 +76,23 @@ abstract class Action extends cmdbAbstractObject
"sql" => "status", "sql" => "status",
"default_value" => "test", "default_value" => "test",
"is_null_allowed" => false, "is_null_allowed" => false,
"depends_on" => array(), "depends_on" => [],
))); ]));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list", MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property'))); "trigger_list",
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array()))); ["linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "display_style" => 'property']
));
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", ["allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => []]));
// Display lists // Display lists
// - Attributes to be displayed for the complete details // - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); MetaModel::Init_SetZListItems('details', ['name', 'description', 'status', 'trigger_list']);
// - Attributes to be displayed for a list // - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); MetaModel::Init_SetZListItems('list', ['finalclass', 'name', 'description', 'status']);
// Search criteria // Search criteria
// - Default criteria of the search form // - Default criteria of the search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status')); MetaModel::Init_SetZListItems('default_search', ['name', 'description', 'status']);
} }
@@ -111,8 +113,7 @@ abstract class Action extends cmdbAbstractObject
*/ */
public function IsActive() public function IsActive()
{ {
switch($this->Get('status')) switch ($this->Get('status')) {
{
case 'enabled': case 'enabled':
case 'test': case 'test':
return true; return true;
@@ -131,8 +132,7 @@ abstract class Action extends cmdbAbstractObject
*/ */
public function IsBeingTested() public function IsBeingTested()
{ {
switch($this->Get('status')) switch ($this->Get('status')) {
{
case 'test': case 'test':
return true; return true;
@@ -220,7 +220,7 @@ abstract class Action extends cmdbAbstractObject
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName); $iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
if ($iLastExecutionDays < 0) { if ($iLastExecutionDays < 0) {
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName)); throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: ".$oConfig->GetDescription($sLastExecutionDaysConfigParamName));
} }
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id'; $sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
@@ -250,7 +250,7 @@ abstract class Action extends cmdbAbstractObject
*/ */
public static function GetAsynchronousGlobalSetting(): bool public static function GetAsynchronousGlobalSetting(): bool
{ {
return false; return false;
} }
/** /**
@@ -270,7 +270,7 @@ abstract class Action extends cmdbAbstractObject
} }
/** /**
* A notification * A notification
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -282,8 +282,8 @@ abstract class ActionNotification extends Action
*/ */
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "grant_by_profile,core/cmdb", "category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
@@ -293,22 +293,22 @@ abstract class ActionNotification extends Action
"db_table" => "priv_action_notification", "db_table" => "priv_action_notification",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
// Display lists // Display lists
// - Attributes to be displayed for the complete details // - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); MetaModel::Init_SetZListItems('details', ['name', 'description', 'status', 'trigger_list']);
// - Attributes to be displayed for a list // - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'description', 'status')); MetaModel::Init_SetZListItems('list', ['finalclass', 'description', 'status']);
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", ["sql" => "language", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
// Search criteria // Search criteria
// - Criteria of the std search form // - Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name')); // MetaModel::Init_SetZListItems('standard_search', array('name'));
// - Default criteria of the search form // - Default criteria of the search form
// MetaModel::Init_SetZListItems('default_search', array('name')); // MetaModel::Init_SetZListItems('default_search', array('name'));
} }
/** /**
@@ -321,7 +321,8 @@ abstract class ActionNotification extends Action
* @throws \DictExceptionUnknownLanguage * @throws \DictExceptionUnknownLanguage
* @since 3.2.0 * @since 3.2.0
*/ */
public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null){ public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null)
{
$sPreviousLanguage = Dict::GetUserLanguage(); $sPreviousLanguage = Dict::GetUserLanguage();
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin'); $aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
$sLanguage = $sLanguage ?? $this->Get('language'); $sLanguage = $sLanguage ?? $this->Get('language');
@@ -338,7 +339,7 @@ abstract class ActionNotification extends Action
} }
/** /**
* An email notification * An email notification
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -348,69 +349,68 @@ class ActionEmail extends ActionNotification
* @var string * @var string
* @since 3.0.1 * @since 3.0.1
*/ */
const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID'; public const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID';
/** /**
* @var string * @var string
* @since 3.0.1 * @since 3.0.1
*/ */
const ENUM_HEADER_NAME_REFERENCES = 'References'; public const ENUM_HEADER_NAME_REFERENCES = 'References';
/** /**
* @var string * @var string
* @since 3.1.0 * @since 3.1.0
*/ */
const TEMPLATE_BODY_CONTENT = '$content$'; public const TEMPLATE_BODY_CONTENT = '$content$';
/** /**
* Wraps the 'body' of the message for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied * Wraps the 'body' of the message for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
* @var string * @var string
* @since 3.1.0 * @since 3.1.0
*/ */
const CONTENT_HIGHLIGHT = '<div style="border:2px dashed #6800ff;position:relative;padding:2px;margin-top:14px;"><div style="background-color:#6800ff;color:#fff;font-family:Courier New, sans-serif;font-size:14px;line-height:16px;padding:3px;display:block;position:absolute;top:-22px;right:0;">$content$</div>%s</div>'; public const CONTENT_HIGHLIGHT = '<div style="border:2px dashed #6800ff;position:relative;padding:2px;margin-top:14px;"><div style="background-color:#6800ff;color:#fff;font-family:Courier New, sans-serif;font-size:14px;line-height:16px;padding:3px;display:block;position:absolute;top:-22px;right:0;">$content$</div>%s</div>';
/** /**
* Wraps a placeholder of the email's body for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied * Wraps a placeholder of the email's body for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
* @var string * @var string
*/ */
const FIELD_HIGHLIGHT = '<span style="background-color:#6800ff;color:#fff;font-size:smaller;font-family:Courier New, sans-serif;padding:2px;">\\$$1\\$</span>'; public const FIELD_HIGHLIGHT = '<span style="background-color:#6800ff;color:#fff;font-size:smaller;font-family:Courier New, sans-serif;padding:2px;">\\$$1\\$</span>';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "grant_by_profile,core/cmdb,application", "category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => ['name'],
"db_table" => "priv_action_email", "db_table" => "priv_action_email",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values" => null, "sql" => "test_recipient", "default_value" => "", "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", ["allowed_values" => null, "sql" => "test_recipient", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values" => null, "sql" => "from", "default_value" => null, "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("from", ["allowed_values" => null, "sql" => "from", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values" => null, "sql" => "from_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("from_label", ["allowed_values" => null, "sql" => "from_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values" => null, "sql" => "reply_to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("reply_to", ["allowed_values" => null, "sql" => "reply_to", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values" => null, "sql" => "reply_to_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", ["allowed_values" => null, "sql" => "reply_to_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeOQL("to", ["allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values" => null, "sql" => "cc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeOQL("cc", ["allowed_values" => null, "sql" => "cc", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values" => null, "sql" => "bcc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeOQL("bcc", ["allowed_values" => null, "sql" => "bcc", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", ["allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", ["allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeEnum("importance", ["allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeBlob("html_template", array("is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false))); MetaModel::Init_AddAttribute(new AttributeBlob("html_template", ["is_null_allowed" => true, "depends_on" => [], "always_load_in_tables" => false]));
MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", array("allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => []]));
// Display lists // Display lists
// - Attributes to be displayed for the complete details // - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array( MetaModel::Init_SetZListItems('details', [
'col:col1' => array( 'col:col1' => [
'fieldset:ActionEmail:main' => array( 'fieldset:ActionEmail:main' => [
0 => 'name', 0 => 'name',
1 => 'description', 1 => 'description',
2 => 'status', 2 => 'status',
@@ -419,14 +419,14 @@ class ActionEmail extends ActionNotification
5 => 'subject', 5 => 'subject',
6 => 'body', 6 => 'body',
// 5 => 'importance', not handled when sending the mail, better hide it then // 5 => 'importance', not handled when sending the mail, better hide it then
), ],
'fieldset:ActionEmail:trigger' => array( 'fieldset:ActionEmail:trigger' => [
0 => 'trigger_list', 0 => 'trigger_list',
1 => 'asynchronous' 1 => 'asynchronous',
), ],
), ],
'col:col2' => array( 'col:col2' => [
'fieldset:ActionEmail:recipients' => array( 'fieldset:ActionEmail:recipients' => [
0 => 'from', 0 => 'from',
1 => 'from_label', 1 => 'from_label',
2 => 'reply_to', 2 => 'reply_to',
@@ -436,17 +436,17 @@ class ActionEmail extends ActionNotification
6 => 'to', 6 => 'to',
7 => 'cc', 7 => 'cc',
8 => 'bcc', 8 => 'bcc',
), ],
), ],
)); ]);
// - Attributes to be displayed for a list // - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('status', 'to', 'subject', 'language')); MetaModel::Init_SetZListItems('list', ['status', 'to', 'subject', 'language']);
// Search criteria // Search criteria
// - Standard criteria of the search // - Standard criteria of the search
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'status', 'subject', 'language')); MetaModel::Init_SetZListItems('standard_search', ['name', 'description', 'status', 'subject', 'language']);
// - Default criteria for the search // - Default criteria for the search
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status', 'subject', 'language')); MetaModel::Init_SetZListItems('default_search', ['name', 'description', 'status', 'subject', 'language']);
} }
// count the recipients found // count the recipients found
@@ -477,10 +477,11 @@ class ActionEmail extends ActionNotification
{ {
$oTrigger = $aArgs['trigger->object()'] ?? null; $oTrigger = $aArgs['trigger->object()'] ?? null;
$sOQL = $this->Get($sRecipAttCode); $sOQL = $this->Get($sRecipAttCode);
if (utils::IsNullOrEmptyString($sOQL)) return ''; if (utils::IsNullOrEmptyString($sOQL)) {
return '';
}
try try {
{
$oSearch = DBObjectSearch::FromOQL($sOQL); $oSearch = DBObjectSearch::FromOQL($sOQL);
if ($this->Get('ignore_notify') === 'no') { if ($this->Get('ignore_notify') === 'no') {
// In theory, it is possible to notify *any* kind of object, // In theory, it is possible to notify *any* kind of object,
@@ -492,31 +493,26 @@ class ActionEmail extends ActionNotification
} }
} }
$oSearch->AllowAllData(); $oSearch->AllowAllData();
} } catch (OQLException $e) {
catch (OQLException $e)
{
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'"; $this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
return $e->getMessage(); return $e->getMessage();
} }
$sClass = $oSearch->GetClass(); $sClass = $oSearch->GetClass();
// Determine the email attribute (the first one will be our choice) // Determine the email attribute (the first one will be our choice)
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
{ if ($oAttDef instanceof AttributeEmailAddress) {
if ($oAttDef instanceof AttributeEmailAddress)
{
$sEmailAttCode = $sAttCode; $sEmailAttCode = $sAttCode;
// we've got one, exit the loop // we've got one, exit the loop
break; break;
} }
} }
if (!isset($sEmailAttCode)) if (!isset($sEmailAttCode)) {
{
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'"; $this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
return "The objects of the class '$sClass' do not have any email attribute"; return "The objects of the class '$sClass' do not have any email attribute";
} }
if($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) { if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
$aArgs['trigger_id'] = $oTrigger->GetKey(); $aArgs['trigger_id'] = $oTrigger->GetKey();
$aArgs['action_id'] = $this->GetKey(); $aArgs['action_id'] = $this->GetKey();
@@ -526,13 +522,11 @@ class ActionEmail extends ActionNotification
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)")); $oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
} }
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs); $oSet = new DBObjectSet($oSearch, [] /* order */, $aArgs);
$aRecipients = array(); $aRecipients = [];
while ($oObj = $oSet->Fetch()) while ($oObj = $oSet->Fetch()) {
{
$sAddress = trim($oObj->Get($sEmailAttCode)); $sAddress = trim($oObj->Get($sEmailAttCode));
if (utils::IsNotNullOrEmptyString($sAddress)) if (utils::IsNotNullOrEmptyString($sAddress)) {
{
$aRecipients[] = $sAddress; $aRecipients[] = $sAddress;
$this->m_iRecipients++; $this->m_iRecipients++;
} }
@@ -551,15 +545,11 @@ class ActionEmail extends ActionNotification
*/ */
public function DoExecute($oTrigger, $aContextArgs) public function DoExecute($oTrigger, $aContextArgs)
{ {
if (MetaModel::IsLogEnabledNotification()) if (MetaModel::IsLogEnabledNotification()) {
{
$oLog = new EventNotificationEmail(); $oLog = new EventNotificationEmail();
if ($this->IsBeingTested()) if ($this->IsBeingTested()) {
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')'); $oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
} } else {
else
{
$oLog->Set('message', 'Notification pending'); $oLog->Set('message', 'Notification pending');
} }
$oLog->Set('userinfo', UserRights::GetUser()); $oLog->Set('userinfo', UserRights::GetUser());
@@ -570,49 +560,36 @@ class ActionEmail extends ActionNotification
// Must be inserted now so that it gets a valid id that will make the link // Must be inserted now so that it gets a valid id that will make the link
// between an eventual asynchronous task (queued) and the log // between an eventual asynchronous task (queued) and the log
$oLog->DBInsertNoReload(); $oLog->DBInsertNoReload();
} } else {
else
{
$oLog = null; $oLog = null;
} }
try try {
{
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog); $sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
if ($this->IsBeingTested()) if ($this->IsBeingTested()) {
{
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - '; $sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
} } else {
else
{
$sPrefix = ''; $sPrefix = '';
} }
if ($oLog) if ($oLog) {
{ $oLog->Set('message', $sPrefix.$sRes);
$oLog->Set('message', $sPrefix . $sRes); $oLog->DBUpdate();
$oLog->DBUpdate(); }
}
} } catch (Exception $e) {
catch (Exception $e) if ($oLog) {
{
if ($oLog)
{
$oLog->Set('message', 'Error: '.$e->getMessage()); $oLog->Set('message', 'Error: '.$e->getMessage());
try try {
{ $oLog->DBUpdate();
$oLog->DBUpdate(); } catch (Exception $eSecondTryUpdate) {
} IssueLog::Error("Failed to process email ".$oLog->GetKey()." - reason: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString());
catch (Exception $eSecondTryUpdate)
{
IssueLog::Error("Failed to process email ".$oLog->GetKey()." - reason: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString());
$oLog->Set('message', 'Error: more details in the log for email "'.$oLog->GetKey().'"'); $oLog->Set('message', 'Error: more details in the log for email "'.$oLog->GetKey().'"');
$oLog->DBUpdate(); $oLog->DBUpdate();
} }
} }
} }
@@ -629,11 +606,11 @@ class ActionEmail extends ActionNotification
*/ */
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog) protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{ {
$sStyles = file_get_contents(APPROOT . utils::GetCSSFromSASS("css/email.scss")); $sStyles = file_get_contents(APPROOT.utils::GetCSSFromSASS("css/email.scss"));
$sStyles .= MetaModel::GetConfig()->Get('email_css'); $sStyles .= MetaModel::GetConfig()->Get('email_css');
$oEmail = new EMail(); $oEmail = new EMail();
$aEmailContent = $this->PrepareMessageContent($aContextArgs, $oLog); $aEmailContent = $this->PrepareMessageContent($aContextArgs, $oLog);
$oEmail->SetSubject($aEmailContent['subject']); $oEmail->SetSubject($aEmailContent['subject']);
$oEmail->SetBody($aEmailContent['body'], 'text/html', $sStyles); $oEmail->SetBody($aEmailContent['body'], 'text/html', $sStyles);
@@ -645,23 +622,18 @@ class ActionEmail extends ActionNotification
$oEmail->SetReferences($aEmailContent['references']); $oEmail->SetReferences($aEmailContent['references']);
$oEmail->SetMessageId($aEmailContent['message_id']); $oEmail->SetMessageId($aEmailContent['message_id']);
$oEmail->SetInReplyTo($aEmailContent['in_reply_to']); $oEmail->SetInReplyTo($aEmailContent['in_reply_to']);
foreach($aEmailContent['attachments'] as $aAttachment) { foreach ($aEmailContent['attachments'] as $aAttachment) {
$oEmail->AddAttachment($aAttachment['data'], $aAttachment['filename'], $aAttachment['mime_type']); $oEmail->AddAttachment($aAttachment['data'], $aAttachment['filename'], $aAttachment['mime_type']);
} }
if (empty($this->m_aMailErrors)) if (empty($this->m_aMailErrors)) {
{ if ($this->m_iRecipients == 0) {
if ($this->m_iRecipients == 0)
{
return 'No recipient'; return 'No recipient';
} } else {
else
{
$aErrors = []; $aErrors = [];
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog); $iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
switch ($iRes) switch ($iRes) {
{
case EMAIL_SEND_OK: case EMAIL_SEND_OK:
return "Sent"; return "Sent";
@@ -721,39 +693,36 @@ class ActionEmail extends ActionNotification
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass(); $sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage(); [$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
try try {
{
$this->m_iRecipients = 0; $this->m_iRecipients = 0;
$this->m_aMailErrors = array(); $this->m_aMailErrors = [];
// Determine recipients // Determine recipients
// //
$aMessageContent['to'] = $this->FindRecipients('to', $aContextArgs); $aMessageContent['to'] = $this->FindRecipients('to', $aContextArgs);
$aMessageContent['cc'] = $this->FindRecipients('cc', $aContextArgs); $aMessageContent['cc'] = $this->FindRecipients('cc', $aContextArgs);
$aMessageContent['bcc'] = $this->FindRecipients('bcc', $aContextArgs); $aMessageContent['bcc'] = $this->FindRecipients('bcc', $aContextArgs);
$aMessageContent['from'] = MetaModel::ApplyParams($this->Get('from'), $aContextArgs); $aMessageContent['from'] = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$aMessageContent['from_label'] = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs); $aMessageContent['from_label'] = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
$aMessageContent['reply_to'] = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs); $aMessageContent['reply_to'] = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$aMessageContent['reply_to_label'] = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs); $aMessageContent['reply_to_label'] = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
$aMessageContent['subject'] = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs); $aMessageContent['subject'] = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = $this->BuildMessageBody(false); $sBody = $this->BuildMessageBody(false);
$aMessageContent['body'] = MetaModel::ApplyParams($sBody, $aContextArgs); $aMessageContent['body'] = MetaModel::ApplyParams($sBody, $aContextArgs);
$oObj = $aContextArgs['this->object()']; $oObj = $aContextArgs['this->object()'];
$aMessageContent['message_id'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID); $aMessageContent['message_id'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
$aMessageContent['references'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES); $aMessageContent['references'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
} } catch (Exception $e) {
catch (Exception $e) {
/** @noinspection PhpUnhandledExceptionInspection */ /** @noinspection PhpUnhandledExceptionInspection */
throw $e; throw $e;
} } finally {
finally {
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker); ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null); $this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
} }
if (!is_null($oLog)) { if (!is_null($oLog)) {
// Note: we have to secure this because those values are calculated // Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as // inside the try statement, and we would like to keep track of as
@@ -802,19 +771,17 @@ class ActionEmail extends ActionNotification
} }
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification // Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
$aMessageContent['in_reply_to'] = $aMessageContent['references']; $aMessageContent['in_reply_to'] = $aMessageContent['references'];
if (isset($aContextArgs['attachments'])) if (isset($aContextArgs['attachments'])) {
{ $aAttachmentReport = [];
$aAttachmentReport = array();
/** @var \ormDocument $oDocument */ /** @var \ormDocument $oDocument */
foreach($aContextArgs['attachments'] as $oDocument) foreach ($aContextArgs['attachments'] as $oDocument) {
{
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()]; $aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? '')); $aAttachmentReport[] = [$oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? '')];
} }
$oLog->Set('attachments', $aAttachmentReport); $oLog->Set('attachments', $aAttachmentReport);
} }
return $aMessageContent; return $aMessageContent;
} }
@@ -859,11 +826,11 @@ class ActionEmail extends ActionNotification
]); ]);
throw new Exception($sErrorMessage); throw new Exception($sErrorMessage);
} }
/** /**
* Compose the body of the message from the 'body' attribute and the HTML template (if any) * Compose the body of the message from the 'body' attribute and the HTML template (if any)
* @since 3.1.0 N°4849 * @since 3.1.0 N°4849
* @param bool $bHighlightPlaceholders If true add some extra HTML around placeholders to highlight them * @param bool $bHighlightPlaceholders If true add some extra HTML around placeholders to highlight them
* @return string * @return string
*/ */
protected function BuildMessageBody(bool $bHighlightPlaceholders = false): string protected function BuildMessageBody(bool $bHighlightPlaceholders = false): string
@@ -889,13 +856,13 @@ HTML;
$sBody = $oHtmlTemplate->GetData(); $sBody = $oHtmlTemplate->GetData();
} }
} }
if($bHighlightPlaceholders) { if ($bHighlightPlaceholders) {
// Highlight all placeholders // Highlight all placeholders
$sBody = preg_replace('/\\$([^$]+)\\$/', static::FIELD_HIGHLIGHT, $sBody); $sBody = preg_replace('/\\$([^$]+)\\$/', static::FIELD_HIGHLIGHT, $sBody);
} }
return $sBody; return $sBody;
} }
/** /**
* @since 3.1.0 N°4849 * @since 3.1.0 N°4849
* @inheritDoc * @inheritDoc

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2016-2024 Combodo SAS // Copyright (C) 2016-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -20,8 +21,7 @@
// Note: for PHP < 7, this compatibility used to be provided by APCU itself (if compiled with some options) // Note: for PHP < 7, this compatibility used to be provided by APCU itself (if compiled with some options)
// for PHP 7+, it can be provided by the mean of apcu_bc, which is not so simple to install // for PHP 7+, it can be provided by the mean of apcu_bc, which is not so simple to install
// The current emulation aims at skipping this complexity // The current emulation aims at skipping this complexity
if (!function_exists('apc_store') && function_exists('apcu_store')) if (!function_exists('apc_store') && function_exists('apcu_store')) {
{
function apc_add($key, $var, $ttl = 0) function apc_add($key, $var, $ttl = 0)
{ {
return apcu_add($key, $var, $ttl); return apcu_add($key, $var, $ttl);
@@ -74,25 +74,23 @@ if (!function_exists('apc_store') && function_exists('apcu_store'))
*/ */
function apc_cache_info_compat() function apc_cache_info_compat()
{ {
if (!function_exists('apc_cache_info')) return array(); if (!function_exists('apc_cache_info')) {
return [];
}
$oFunction = new ReflectionFunction('apc_cache_info'); $oFunction = new ReflectionFunction('apc_cache_info');
if ($oFunction->getNumberOfParameters() != 2) if ($oFunction->getNumberOfParameters() != 2) {
{
// Beware: APCu behaves slightly differently from APC !! // Beware: APCu behaves slightly differently from APC !!
// Worse: the compatibility layer integrated into APC differs from apcu-bc (testing the number of parameters is a must) // Worse: the compatibility layer integrated into APC differs from apcu-bc (testing the number of parameters is a must)
// In CLI mode (PHP > 7) apc_cache_info returns null and outputs an error message. // In CLI mode (PHP > 7) apc_cache_info returns null and outputs an error message.
$aCacheUserData = @apc_cache_info(); $aCacheUserData = @apc_cache_info();
} } else {
else
{
$aCacheUserData = @apc_cache_info('user'); $aCacheUserData = @apc_cache_info('user');
} }
return $aCacheUserData; return $aCacheUserData;
} }
// Cache emulation // Cache emulation
if (!function_exists('apc_store')) if (!function_exists('apc_store')) {
{
require_once(APPROOT.'core/apc-emulation.php'); require_once(APPROOT.'core/apc-emulation.php');
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (c) 2010-2024 Combodo SAS // Copyright (c) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -28,7 +29,7 @@
*/ */
function apc_cache_info($cache_type = '', $limited = false) function apc_cache_info($cache_type = '', $limited = false)
{ {
$aInfo = array(); $aInfo = [];
$sRootCacheDir = apcFile::GetCacheFileName(); $sRootCacheDir = apcFile::GetCacheFileName();
$aInfo['cache_list'] = apcFile::GetCacheEntries($sRootCacheDir); $aInfo['cache_list'] = apcFile::GetCacheEntries($sRootCacheDir);
return $aInfo; return $aInfo;
@@ -40,13 +41,11 @@ function apc_cache_info($cache_type = '', $limited = false)
* @param int $ttl * @param int $ttl
* @return array|bool * @return array|bool
*/ */
function apc_store($key, $var = NULL, $ttl = 0) function apc_store($key, $var = null, $ttl = 0)
{ {
if (is_array($key)) if (is_array($key)) {
{ $aResult = [];
$aResult = array(); foreach ($key as $sKey => $value) {
foreach($key as $sKey => $value)
{
$aResult[] = apcFile::StoreOneFile($sKey, $value, $ttl); $aResult[] = apcFile::StoreOneFile($sKey, $value, $ttl);
} }
return $aResult; return $aResult;
@@ -89,8 +88,7 @@ function apc_clear_cache($cache_type = '')
*/ */
function apc_delete($key) function apc_delete($key)
{ {
if (empty($key)) if (empty($key)) {
{
return false; return false;
} }
$bRet1 = apcFile::DeleteEntry(apcFile::GetCacheFileName($key)); $bRet1 = apcFile::DeleteEntry(apcFile::GetCacheFileName($key));
@@ -126,17 +124,17 @@ function apc_exists($keys)
class apcFile class apcFile
{ {
// Check only once per request // Check only once per request
static public $aFilesByTime = null; public static $aFilesByTime = null;
static public $iFileCount = 0; public static $iFileCount = 0;
/** Get the file name corresponding to the cache entry. /** Get the file name corresponding to the cache entry.
* If an empty key is provided, the root of the cache is returned. * If an empty key is provided, the root of the cache is returned.
* @param $sKey * @param $sKey
* @return string * @return string
*/ */
static public function GetCacheFileName($sKey = '') public static function GetCacheFileName($sKey = '')
{ {
$sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey ?? ''); $sPath = str_replace([' ', '/', '\\', '.'], '-', $sKey ?? '');
return utils::GetCachePath().'apc-emul/'.$sPath; return utils::GetCachePath().'apc-emul/'.$sPath;
} }
@@ -144,26 +142,21 @@ class apcFile
* @param $sEntry string starting folder. * @param $sEntry string starting folder.
* @return array list of entries stored into array of key 'info' * @return array list of entries stored into array of key 'info'
*/ */
static public function GetCacheEntries($sEntry) public static function GetCacheEntries($sEntry)
{ {
$aResult = array(); $aResult = [];
if (is_dir($sEntry)) if (is_dir($sEntry)) {
{ $aFiles = array_diff(scandir($sEntry), ['.', '..']);
$aFiles = array_diff(scandir($sEntry), array('.', '..')); foreach ($aFiles as $sFile) {
foreach($aFiles as $sFile)
{
$sSubFile = $sEntry.'/'.$sFile; $sSubFile = $sEntry.'/'.$sFile;
$aResult = array_merge($aResult, self::GetCacheEntries($sSubFile)); $aResult = array_merge($aResult, self::GetCacheEntries($sSubFile));
} }
} } else {
else
{
$sKey = basename($sEntry); $sKey = basename($sEntry);
if (strpos($sKey, '-') === 0) if (strpos($sKey, '-') === 0) {
{
$sKey = substr($sKey, 1); $sKey = substr($sKey, 1);
} }
$aResult[] = array('info' => $sKey); $aResult[] = ['info' => $sKey];
} }
return $aResult; return $aResult;
} }
@@ -172,35 +165,25 @@ class apcFile
* @param $sCache * @param $sCache
* @return bool true if the entry was deleted false if error occurs (like entry did not exist). * @return bool true if the entry was deleted false if error occurs (like entry did not exist).
*/ */
static public function DeleteEntry($sCache) public static function DeleteEntry($sCache)
{ {
if (is_dir($sCache)) if (is_dir($sCache)) {
{ $aFiles = array_diff(scandir($sCache), ['.', '..']);
$aFiles = array_diff(scandir($sCache), array('.', '..')); foreach ($aFiles as $sFile) {
foreach($aFiles as $sFile)
{
$sSubFile = $sCache.'/'.$sFile; $sSubFile = $sCache.'/'.$sFile;
if (!self::DeleteEntry($sSubFile)) if (!self::DeleteEntry($sSubFile)) {
{
return false; return false;
} }
} }
if (!@rmdir($sCache)) if (!@rmdir($sCache)) {
{
return false; return false;
} }
} } else {
else if (is_file($sCache)) {
{ if (!@unlink($sCache)) {
if (is_file($sCache))
{
if (!@unlink($sCache))
{
return false; return false;
} }
} } else {
else
{
return false; return false;
} }
} }
@@ -215,23 +198,22 @@ class apcFile
* @return bool * @return bool
* @since 3.2.0 N°7068 * @since 3.2.0 N°7068
*/ */
static public function ExistsOneFile($sKey) { public static function ExistsOneFile($sKey)
return is_file(self::GetCacheFileName('-' . $sKey)) || is_file(self::GetCacheFileName($sKey)); {
return is_file(self::GetCacheFileName('-'.$sKey)) || is_file(self::GetCacheFileName($sKey));
} }
/** Get one cache entry content. /** Get one cache entry content.
* @param $sKey * @param $sKey
* @return bool|mixed * @return bool|mixed
*/ */
static public function FetchOneFile($sKey) public static function FetchOneFile($sKey)
{ {
// Try the 'TTLed' version // Try the 'TTLed' version
$sValue = self::ReadCacheLocked(self::GetCacheFileName('-'.$sKey)); $sValue = self::ReadCacheLocked(self::GetCacheFileName('-'.$sKey));
if ($sValue === false) if ($sValue === false) {
{
$sValue = self::ReadCacheLocked(self::GetCacheFileName($sKey)); $sValue = self::ReadCacheLocked(self::GetCacheFileName($sKey));
if ($sValue === false) if ($sValue === false) {
{
return false; return false;
} }
} }
@@ -245,7 +227,7 @@ class apcFile
* @param int $iTTL time to live * @param int $iTTL time to live
* @return bool * @return bool
*/ */
static public function StoreOneFile($sKey, $value, $iTTL) public static function StoreOneFile($sKey, $value, $iTTL)
{ {
if (empty($sKey)) { if (empty($sKey)) {
return false; return false;
@@ -279,40 +261,31 @@ class apcFile
* remove older files if the mamximum is reached. * remove older files if the mamximum is reached.
* @param $sNewFilename * @param $sNewFilename
*/ */
static protected function AddFile($sNewFilename) protected static function AddFile($sNewFilename)
{ {
if (strpos(basename($sNewFilename), '-') !== 0) if (strpos(basename($sNewFilename), '-') !== 0) {
{
return; return;
} }
$iMaxFiles = MetaModel::GetConfig()->Get('apc_cache_emulation.max_entries'); $iMaxFiles = MetaModel::GetConfig()->Get('apc_cache_emulation.max_entries');
if ($iMaxFiles == 0) if ($iMaxFiles == 0) {
{
return; return;
} }
if (!self::$aFilesByTime) if (!self::$aFilesByTime) {
{
self::ListFilesByTime(); self::ListFilesByTime();
self::$iFileCount = count(self::$aFilesByTime); self::$iFileCount = count(self::$aFilesByTime);
if ($iMaxFiles !== 0) if ($iMaxFiles !== 0) {
{
asort(self::$aFilesByTime); asort(self::$aFilesByTime);
} }
} } else {
else
{
self::$aFilesByTime[$sNewFilename] = time(); self::$aFilesByTime[$sNewFilename] = time();
self::$iFileCount++; self::$iFileCount++;
} }
if (self::$iFileCount > $iMaxFiles) if (self::$iFileCount > $iMaxFiles) {
{
$iFileNbToRemove = self::$iFileCount - $iMaxFiles; $iFileNbToRemove = self::$iFileCount - $iMaxFiles;
foreach(self::$aFilesByTime as $sFileToRemove => $iTime) foreach (self::$aFilesByTime as $sFileToRemove => $iTime) {
{
@unlink($sFileToRemove); @unlink($sFileToRemove);
if (--$iFileNbToRemove === 0) if (--$iFileNbToRemove === 0) {
{
break; break;
} }
} }
@@ -324,25 +297,19 @@ class apcFile
/** Get the list of files with their associated access time /** Get the list of files with their associated access time
* @param string $sCheck Directory to scan * @param string $sCheck Directory to scan
*/ */
static protected function ListFilesByTime($sCheck = null) protected static function ListFilesByTime($sCheck = null)
{ {
if (empty($sCheck)) if (empty($sCheck)) {
{
$sCheck = self::GetCacheFileName(); $sCheck = self::GetCacheFileName();
} }
// Garbage collection // Garbage collection
$aFiles = array_diff(@scandir($sCheck), array('.', '..')); $aFiles = array_diff(@scandir($sCheck), ['.', '..']);
foreach($aFiles as $sFile) foreach ($aFiles as $sFile) {
{
$sSubFile = $sCheck.'/'.$sFile; $sSubFile = $sCheck.'/'.$sFile;
if (is_dir($sSubFile)) if (is_dir($sSubFile)) {
{
self::ListFilesByTime($sSubFile); self::ListFilesByTime($sSubFile);
} } else {
else if (strpos(basename($sSubFile), '-') === 0) {
{
if (strpos(basename($sSubFile), '-') === 0)
{
self::$aFilesByTime[$sSubFile] = @fileatime($sSubFile); self::$aFilesByTime[$sSubFile] = @fileatime($sSubFile);
} }
} }
@@ -353,7 +320,7 @@ class apcFile
* @param $sFilename * @param $sFilename
* @return bool|string the content of the cache entry or false if error * @return bool|string the content of the cache entry or false if error
*/ */
static protected function ReadCacheLocked($sFilename) protected static function ReadCacheLocked($sFilename)
{ {
$sContent = false; $sContent = false;
$file = @fopen($sFilename, 'r'); $file = @fopen($sFilename, 'r');
@@ -367,7 +334,7 @@ class apcFile
return $sContent; return $sContent;
} }
static protected function ResetFileCount() protected static function ResetFileCount()
{ {
self::$aFilesByTime = null; self::$aFilesByTime = null;
self::$iFileCount = 0; self::$iFileCount = 0;

View File

@@ -4,8 +4,10 @@
* Class ApcService * Class ApcService
* @since 2.7.6 N°4125 * @since 2.7.6 N°4125
*/ */
class ApcService { class ApcService
public function __construct() { {
public function __construct()
{
} }
/** /**
@@ -13,7 +15,8 @@ class ApcService {
* @return bool * @return bool
* @see function_exists() * @see function_exists()
*/ */
public function function_exists($function_name) { public function function_exists($function_name)
{
return function_exists($function_name); return function_exists($function_name);
} }
@@ -22,7 +25,7 @@ class ApcService {
* @return mixed * @return mixed
* @see apc_fetch() * @see apc_fetch()
*/ */
function apc_fetch($key) public function apc_fetch($key)
{ {
return apc_fetch($key); return apc_fetch($key);
} }
@@ -34,9 +37,8 @@ class ApcService {
* @return array|bool * @return array|bool
* @see apc_store() * @see apc_store()
*/ */
function apc_store($key, $var = NULL, $ttl = 0) public function apc_store($key, $var = null, $ttl = 0)
{ {
return apc_store($key, $var, $ttl); return apc_store($key, $var, $ttl);
} }
} }
?>

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -17,7 +18,6 @@
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Service\Notification\Event\EventNotificationNewsroomService; use Combodo\iTop\Service\Notification\Event\EventNotificationNewsroomService;
/** /**
* Persistent classes (internal): user defined actions * Persistent classes (internal): user defined actions
* *
@@ -25,11 +25,10 @@ use Combodo\iTop\Service\Notification\Event\EventNotificationNewsroomService;
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class ExecAsyncTask implements iBackgroundProcess class ExecAsyncTask implements iBackgroundProcess
{ {
public function GetPeriodicity() public function GetPeriodicity()
{ {
return 2; // seconds return 2; // seconds
} }
@@ -39,19 +38,16 @@ class ExecAsyncTask implements iBackgroundProcess
// Criteria: planned, and expected to occur... ASAP or in the past // Criteria: planned, and expected to occur... ASAP or in the past
$sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '$sNow'))"; $sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '$sNow'))";
$iProcessed = 0; $iProcessed = 0;
while (time() < $iTimeLimit) while (time() < $iTimeLimit) {
{
// Next one ? // Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */); $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), ['created' => true] /* order by*/, [], null, 1 /* limit count */);
$oTask = $oSet->Fetch(); $oTask = $oSet->Fetch();
if (is_null($oTask)) if (is_null($oTask)) {
{
// Nothing to be done // Nothing to be done
break; break;
} }
$iProcessed++; $iProcessed++;
if ($oTask->Process()) if ($oTask->Process()) {
{
$oTask->DBDelete(); $oTask->DBDelete();
} }
} }
@@ -60,7 +56,7 @@ class ExecAsyncTask implements iBackgroundProcess
} }
/** /**
* A * A
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -72,79 +68,72 @@ abstract class AsyncTask extends DBObject
*/ */
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "core/cmdb", "category" => "core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => array('created'), "name_attcode" => ['created'],
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_async_task", "db_table" => "priv_async_task",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
// Null is allowed to ease the migration from iTop 2.0.2 and earlier, when the status did not exist, and because the default value is not taken into account in the SQL definition // Null is allowed to ease the migration from iTop 2.0.2 and earlier, when the status did not exist, and because the default value is not taken into account in the SQL definition
// The value is set from null to planned in the setup program // The value is set from null to planned in the setup program
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('planned,running,idle,error'), "sql"=>"status", "default_value"=>"planned", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("status", ["allowed_values" => new ValueSetEnum('planned,running,idle,error'), "sql" => "status", "default_value" => "planned", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("created", ["allowed_values" => null, "sql" => "created", "default_value" => "NOW()", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("started", array("allowed_values"=>null, "sql"=>"started", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("started", ["allowed_values" => null, "sql" => "started", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("planned", ["allowed_values" => null, "sql" => "planned", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", ["targetclass" => "Event", "jointype" => "", "allowed_values" => null, "sql" => "event_id", "is_null_allowed" => true, "on_target_delete" => DEL_SILENT, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", array("allowed_values"=>null, "sql"=>"remaining_retries", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", ["allowed_values" => null, "sql" => "remaining_retries", "default_value" => 0, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeInteger("last_error_code", array("allowed_values"=>null, "sql"=>"last_error_code", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("last_error_code", ["allowed_values" => null, "sql" => "last_error_code", "default_value" => 0, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("last_error", ["allowed_values" => null, "sql" => "last_error", "default_value" => '', "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_attempt", array("allowed_values"=>null, "sql"=>"last_attempt", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("last_attempt", ["allowed_values" => null, "sql" => "last_attempt", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
} }
/** /**
* Every is fine * Every is fine
*/ */
const OK = 0; public const OK = 0;
/** /**
* The task no longer exists * The task no longer exists
*/ */
const DELETED = 1; public const DELETED = 1;
/** /**
* The task is already being executed * The task is already being executed
*/ */
const ALREADY_RUNNING = 2; public const ALREADY_RUNNING = 2;
/** /**
* The current process requests the ownership on the task. * The current process requests the ownership on the task.
* In case the task can be accessed concurrently, this function can be overloaded to add a critical section. * In case the task can be accessed concurrently, this function can be overloaded to add a critical section.
* The function must not block the caller if another process is already owning the task * The function must not block the caller if another process is already owning the task
* *
* @return integer A code among OK/DELETED/ALREADY_RUNNING. * @return integer A code among OK/DELETED/ALREADY_RUNNING.
*/ */
public function MarkAsRunning() public function MarkAsRunning()
{ {
try try {
{ if ($this->Get('status') == 'running') {
if ($this->Get('status') == 'running')
{
return self::ALREADY_RUNNING; return self::ALREADY_RUNNING;
} } else {
else
{
$this->Set('status', 'running'); $this->Set('status', 'running');
$this->Set('started', time()); $this->Set('started', time());
$this->DBUpdate(); $this->DBUpdate();
return self::OK; return self::OK;
} }
} } catch (Exception $e) {
catch(Exception $e)
{
// Corrupted task !! (for example: "Failed to reload object") // Corrupted task !! (for example: "Failed to reload object")
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.'); IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.');
if ($this->Get('event_id') != 0) if ($this->Get('event_id') != 0) {
{ $oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id')); $oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage());
$oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage()); $oEventLog->DBUpdate();
$oEventLog->DBUpdate();
} }
$this->DBDelete(); $this->DBDelete();
return self::DELETED; return self::DELETED;
@@ -155,8 +144,7 @@ abstract class AsyncTask extends DBObject
{ {
$iRetryDelay = 600; $iRetryDelay = 600;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries'); $aRetries = MetaModel::GetConfig()->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) {
{
$aConfig = $aRetries[get_class($this)]; $aConfig = $aRetries[get_class($this)];
$iRetryDelay = $aConfig['retry_delay'] ?? $iRetryDelay; $iRetryDelay = $aConfig['retry_delay'] ?? $iRetryDelay;
} }
@@ -167,8 +155,7 @@ abstract class AsyncTask extends DBObject
{ {
$iMaxRetries = 0; $iMaxRetries = 0;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries'); $aRetries = MetaModel::GetConfig()->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) {
{
$aConfig = $aRetries[get_class($this)]; $aConfig = $aRetries[get_class($this)];
$iMaxRetries = $aConfig['max_retries'] ?? $iMaxRetries; $iMaxRetries = $aConfig['max_retries'] ?? $iMaxRetries;
} }
@@ -177,40 +164,33 @@ abstract class AsyncTask extends DBObject
public function IsRetryDelayExponential() public function IsRetryDelayExponential()
{ {
$bExponential = false; $bExponential = false;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries'); $aRetries = MetaModel::GetConfig()->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) {
{ $aConfig = $aRetries[get_class($this)];
$aConfig = $aRetries[get_class($this)]; $bExponential = (bool) ($aConfig['exponential_delay'] ?? $bExponential);
$bExponential = (bool) ($aConfig['exponential_delay'] ?? $bExponential); }
} return $bExponential;
return $bExponential;
} }
public static function CheckRetryConfig(Config $oConfig, $sAsyncTaskClass) public static function CheckRetryConfig(Config $oConfig, $sAsyncTaskClass)
{ {
$aMessages = []; $aMessages = [];
$aRetries = $oConfig->Get('async_task_retries'); $aRetries = $oConfig->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists($sAsyncTaskClass, $aRetries)) if (is_array($aRetries) && array_key_exists($sAsyncTaskClass, $aRetries)) {
{ $aValidKeys = ["retry_delay", "max_retries", "exponential_delay"];
$aValidKeys = array("retry_delay", "max_retries", "exponential_delay"); $aConfig = $aRetries[$sAsyncTaskClass];
$aConfig = $aRetries[$sAsyncTaskClass]; if (!is_array($aConfig)) {
if (!is_array($aConfig)) $aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_Keys', $sAsyncTaskClass, implode(', ', $aValidKeys));
{ } else {
$aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_Keys', $sAsyncTaskClass, implode(', ', $aValidKeys)); foreach ($aConfig as $key => $value) {
} if (!in_array($key, $aValidKeys)) {
else $aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_InvalidKey_Keys', $sAsyncTaskClass, $key, implode(', ', $aValidKeys));
{ }
foreach($aConfig as $key => $value) }
{ }
if (!in_array($key, $aValidKeys)) }
{ return $aMessages;
$aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_InvalidKey_Keys', $sAsyncTaskClass, $key, implode(', ', $aValidKeys));
}
}
}
}
return $aMessages;
} }
/** /**
@@ -223,16 +203,15 @@ abstract class AsyncTask extends DBObject
*/ */
public static function GetNextRetryDelay($bIsExponential, $iRetryDelay, $iMaxRetries, $iRemainingRetries) public static function GetNextRetryDelay($bIsExponential, $iRetryDelay, $iMaxRetries, $iRemainingRetries)
{ {
if ($bIsExponential) if ($bIsExponential) {
{ $iExponent = $iMaxRetries - $iRemainingRetries;
$iExponent = $iMaxRetries - $iRemainingRetries; if ($iExponent < 0) {
if ($iExponent < 0) $iExponent = 0; // Safety net in case on configuration change in the middle of retries $iExponent = 0;
return $iRetryDelay * (2 ** $iExponent); } // Safety net in case on configuration change in the middle of retries
} return $iRetryDelay * (2 ** $iExponent);
else } else {
{ return $iRetryDelay;
return $iRetryDelay; }
}
} }
/** /**
@@ -242,14 +221,14 @@ abstract class AsyncTask extends DBObject
{ {
} }
protected function OnInsert() protected function OnInsert()
{ {
$this->Set('created', time()); $this->Set('created', time());
} }
/** /**
* @return boolean True if the task record can be deleted * @return boolean True if the task record can be deleted
*/ */
public function Process() public function Process()
{ {
// By default: consider that the task is not completed // By default: consider that the task is not completed
@@ -257,25 +236,19 @@ abstract class AsyncTask extends DBObject
// Attempt to take the ownership // Attempt to take the ownership
$iStatus = $this->MarkAsRunning(); $iStatus = $this->MarkAsRunning();
if ($iStatus == self::OK) if ($iStatus == self::OK) {
{ try {
try
{
$sStatus = $this->DoProcess(); $sStatus = $this->DoProcess();
if ($this->Get('event_id') != 0) if ($this->Get('event_id') != 0) {
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id')); $oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', $sStatus); $oEventLog->Set('message', $sStatus);
$oEventLog->DBUpdate(); $oEventLog->DBUpdate();
} }
$bRet = true; $bRet = true;
} catch (Exception $e) } catch (Exception $e) {
{
$this->HandleError($e->getMessage(), $e->getCode()); $this->HandleError($e->getMessage(), $e->getCode());
} }
} } else {
else
{
// Already done or being handled by another process... skip... // Already done or being handled by another process... skip...
$bRet = false; $bRet = false;
} }
@@ -288,8 +261,7 @@ abstract class AsyncTask extends DBObject
*/ */
protected function HandleError($sErrorMessage, $iErrorCode) protected function HandleError($sErrorMessage, $iErrorCode)
{ {
if ($this->Get('last_attempt') == '') if ($this->Get('last_attempt') == '') {
{
// First attempt // First attempt
$this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode)); $this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode));
} }
@@ -299,45 +271,34 @@ abstract class AsyncTask extends DBObject
$this->Set('last_attempt', time()); $this->Set('last_attempt', time());
$iRemaining = $this->Get('remaining_retries'); $iRemaining = $this->Get('remaining_retries');
if ($iRemaining > 0) if ($iRemaining > 0) {
{
$iRetryDelay = $this->GetRetryDelay($iErrorCode); $iRetryDelay = $this->GetRetryDelay($iErrorCode);
$iNextRetryDelay = static::GetNextRetryDelay($this->IsRetryDelayExponential(), $iRetryDelay, $this->GetMaxRetries($iErrorCode), $iRemaining); $iNextRetryDelay = static::GetNextRetryDelay($this->IsRetryDelayExponential(), $iRetryDelay, $this->GetMaxRetries($iErrorCode), $iRemaining);
IssueLog::Info('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage.' - remaining retries: '.$iRemaining.' - next retry in '.$iNextRetryDelay.'s'); IssueLog::Info('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage.' - remaining retries: '.$iRemaining.' - next retry in '.$iNextRetryDelay.'s');
if ($this->Get('event_id') != 0) if ($this->Get('event_id') != 0) {
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id')); $oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s"); $oEventLog->Set('message', "$sErrorMessage\nFailed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s");
try try {
{ $oEventLog->DBUpdate();
$oEventLog->DBUpdate(); } catch (Exception $e) {
} $oEventLog->Set('message', "Failed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s, more details in the log");
catch (Exception $e) $oEventLog->DBUpdate();
{ }
$oEventLog->Set('message', "Failed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s, more details in the log");
$oEventLog->DBUpdate();
}
} }
$this->Set('remaining_retries', $iRemaining - 1); $this->Set('remaining_retries', $iRemaining - 1);
$this->Set('status', 'planned'); $this->Set('status', 'planned');
$this->Set('started', null); $this->Set('started', null);
$this->Set('planned', time() + $iNextRetryDelay); $this->Set('planned', time() + $iNextRetryDelay);
} } else {
else
{
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage); IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage);
if ($this->Get('event_id') != 0) if ($this->Get('event_id') != 0) {
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id')); $oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task."); $oEventLog->Set('message', "$sErrorMessage\nFailed to process async task.");
try try {
{ $oEventLog->DBUpdate();
$oEventLog->DBUpdate(); } catch (Exception $e) {
} $oEventLog->Set('message', 'Failed to process async task, more details in the log');
catch (Exception $e) $oEventLog->DBUpdate();
{
$oEventLog->Set('message', 'Failed to process async task, more details in the log');
$oEventLog->DBUpdate();
} }
} }
$this->Set('status', 'error'); $this->Set('status', 'error');
@@ -352,20 +313,20 @@ abstract class AsyncTask extends DBObject
* Throws an exception (message and code) * Throws an exception (message and code)
* *
* @return string * @return string
*/ */
abstract public function DoProcess(); abstract public function DoProcess();
/** /**
* Describes the error codes that DoProcess can return by the mean of exceptions * Describes the error codes that DoProcess can return by the mean of exceptions
*/ */
static public function EnumErrorCodes() public static function EnumErrorCodes()
{ {
return array(); return [];
} }
} }
/** /**
* An email notification * An email notification
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -373,38 +334,37 @@ class AsyncSendEmail extends AsyncTask
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "core/cmdb", "category" => "core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "created", "name_attcode" => "created",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_async_send_email", "db_table" => "priv_async_send_email",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("version", ["allowed_values" => null, "sql" => "version", "default_value" => Email::ORIGINAL_FORMAT, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("to", ["allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("subject", ["allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeLongText("message", ["allowed_values" => null, "sql" => "message", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
// Display lists // Display lists
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details // MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
// MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list // MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria // Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
static public function AddToQueue(EMail $oEMail, $oLog) public static function AddToQueue(EMail $oEMail, $oLog)
{ {
$oNew = MetaModel::NewObject(__class__); $oNew = MetaModel::NewObject(__class__);
if ($oLog) if ($oLog) {
{
$oNew->Set('event_id', $oLog->GetKey()); $oNew->Set('event_id', $oLog->GetKey());
} }
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */)); $oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
@@ -425,35 +385,33 @@ class AsyncSendEmail extends AsyncTask
{ {
$sMessage = $this->Get('message'); $sMessage = $this->Get('message');
$iVersion = (int) $this->Get('version'); $iVersion = (int) $this->Get('version');
switch($iVersion) switch ($iVersion) {
{
case Email::FORMAT_V2: case Email::FORMAT_V2:
$oEMail = Email::UnSerializeV2($sMessage); $oEMail = Email::UnSerializeV2($sMessage);
break; break;
case Email::ORIGINAL_FORMAT: case Email::ORIGINAL_FORMAT:
$oEMail = unserialize($sMessage); $oEMail = unserialize($sMessage);
break; break;
default: default:
return 'Unknown version of the serialization format: '.$iVersion; return 'Unknown version of the serialization format: '.$iVersion;
} }
$iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */); $iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */);
switch ($iRes) switch ($iRes) {
{ case EMAIL_SEND_OK:
case EMAIL_SEND_OK: return "Sent";
return "Sent";
case EMAIL_SEND_PENDING: case EMAIL_SEND_PENDING:
return "Bug - the email should be sent in synchronous mode"; return "Bug - the email should be sent in synchronous mode";
case EMAIL_SEND_ERROR: case EMAIL_SEND_ERROR:
if (is_array($aIssues)) { if (is_array($aIssues)) {
$sMessage = "Sending eMail failed: ".implode(', ', $aIssues); $sMessage = "Sending eMail failed: ".implode(', ', $aIssues);
} else { } else {
$sMessage = "Sending eMail failed."; $sMessage = "Sending eMail failed.";
} }
throw new Exception($sMessage); throw new Exception($sMessage);
} }
return ''; return '';
} }
@@ -463,33 +421,33 @@ class AsyncSendEmail extends AsyncTask
* An async notification to be sent to iTop users through the newsroom * An async notification to be sent to iTop users through the newsroom
* @since 3.2.0 * @since 3.2.0
*/ */
class AsyncSendNewsroom extends AsyncTask { class AsyncSendNewsroom extends AsyncTask
{
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "core/cmdb", "category" => "core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "created", "name_attcode" => "created",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_async_send_newsroom", "db_table" => "priv_async_send_newsroom",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("recipients", array("allowed_values"=>null, "sql"=>"recipients", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("recipients", ["allowed_values" => null, "sql" => "recipients", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "allowed_values"=>null, "sql"=>"action_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", ["targetclass" => "Action", "allowed_values" => null, "sql" => "action_id", "default_value" => null, "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "allowed_values"=>null, "sql"=>"trigger_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", ["targetclass" => "Trigger", "allowed_values" => null, "sql" => "trigger_id", "default_value" => null, "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("title", array("allowed_values"=>null, "sql"=>"title", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("title", ["allowed_values" => null, "sql" => "title", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("message", ["allowed_values" => null, "sql" => "message", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("object_id", ["allowed_values" => null, "sql" => "object_id", "default_value" => null, "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("object_class", ["allowed_values" => null, "sql" => "object_class", "default_value" => null, "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("url", ["allowed_values" => null, "sql" => "url", "default_value" => null, "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>'NOW()', "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("date", ["allowed_values" => null, "sql" => "date", "default_value" => 'NOW()', "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
} }
@@ -514,7 +472,7 @@ class AsyncSendNewsroom extends AsyncTask {
$oNew->Set('object_id', $iObjectId); $oNew->Set('object_id', $iObjectId);
$oNew->Set('object_class', $sObjectClass); $oNew->Set('object_class', $sObjectClass);
$oNew->SetCurrentDate('date'); $oNew->SetCurrentDate('date');
$oNew->DBInsert(); $oNew->DBInsert();
} }
@@ -532,13 +490,12 @@ class AsyncSendNewsroom extends AsyncTask {
$iObjectId = $this->Get('object_id'); $iObjectId = $this->Get('object_id');
$sObjectClass = $this->Get('object_class'); $sObjectClass = $this->Get('object_class');
$sDate = $this->Get('date'); $sDate = $this->Get('date');
foreach ($aRecipients as $iRecipientId) foreach ($aRecipients as $iRecipientId) {
{
$oEvent = EventNotificationNewsroomService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate); $oEvent = EventNotificationNewsroomService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate);
$oEvent->DBInsertNoReload(); $oEvent->DBInsertNoReload();
} }
return "Sent"; return "Sent";
} }
} }

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2024 Combodo SAS // Copyright (C) 2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -25,7 +26,6 @@ MetaModel::IncludeModule('application/audit.domain.class.inc.php');
MetaModel::IncludeModule('application/query.class.inc.php'); MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php'); MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php'); MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php'); MetaModel::IncludeModule('core/action.class.inc.php');
MetaModel::IncludeModule('core/trigger.class.inc.php'); MetaModel::IncludeModule('core/trigger.class.inc.php');

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2024 Combodo SAS // Copyright (C) 2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Tasks performed in the background * Tasks performed in the background
* *
@@ -24,7 +24,6 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class ObsolescenceDateUpdater implements iBackgroundProcess class ObsolescenceDateUpdater implements iBackgroundProcess
{ {
public function GetPeriodicity() public function GetPeriodicity()
@@ -37,18 +36,17 @@ class ObsolescenceDateUpdater implements iBackgroundProcess
$iCountSet = 0; $iCountSet = 0;
$iCountReset = 0; $iCountReset = 0;
$iClasses = 0; $iClasses = 0;
foreach (MetaModel::EnumObsoletableClasses() as $sClass) foreach (MetaModel::EnumObsoletableClasses() as $sClass) {
{
$oObsoletedToday = new DBObjectSearch($sClass); $oObsoletedToday = new DBObjectSearch($sClass);
$oObsoletedToday->AddCondition('obsolescence_flag', 1, '='); $oObsoletedToday->AddCondition('obsolescence_flag', 1, '=');
$oObsoletedToday->AddCondition('obsolescence_date', null, '='); $oObsoletedToday->AddCondition('obsolescence_date', null, '=');
$sToday = date(AttributeDate::GetSQLFormat()); $sToday = date(AttributeDate::GetSQLFormat());
$iCountSet += MetaModel::BulkUpdate($oObsoletedToday, array('obsolescence_date' => $sToday)); $iCountSet += MetaModel::BulkUpdate($oObsoletedToday, ['obsolescence_date' => $sToday]);
$oObsoletedToday = new DBObjectSearch($sClass); $oObsoletedToday = new DBObjectSearch($sClass);
$oObsoletedToday->AddCondition('obsolescence_flag', 1, '!='); $oObsoletedToday->AddCondition('obsolescence_flag', 1, '!=');
$oObsoletedToday->AddCondition('obsolescence_date', null, '!='); $oObsoletedToday->AddCondition('obsolescence_date', null, '!=');
$iCountReset += MetaModel::BulkUpdate($oObsoletedToday, array('obsolescence_date' => null)); $iCountReset += MetaModel::BulkUpdate($oObsoletedToday, ['obsolescence_date' => null]);
} }
return "Obsolescence date updated (classes: $iClasses ; set: $iCountSet ; reset: $iCountReset)\n"; return "Obsolescence date updated (classes: $iClasses ; set: $iCountSet ; reset: $iCountReset)\n";
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2010-2024 Combodo SAS * Copyright (C) 2010-2024 Combodo SAS
* *
@@ -17,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
*/ */
interface iProcess interface iProcess
{ {
/** /**
@@ -33,7 +33,7 @@ interface iProcess
/** /**
* interface iBackgroundProcess * interface iBackgroundProcess
* Any extension that must be called regularly to be executed in the background * Any extension that must be called regularly to be executed in the background
* *
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -62,7 +62,6 @@ interface iScheduledProcess extends iProcess
public function GetNextOccurrence(); public function GetNextOccurrence();
} }
/** /**
* Implementation of {@link iScheduledProcess}, using config parameters for module * Implementation of {@link iScheduledProcess}, using config parameters for module
* *
@@ -82,11 +81,11 @@ interface iScheduledProcess extends iProcess
abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
{ {
// param have default names/values but can be overridden // param have default names/values but can be overridden
const MODULE_SETTING_ENABLED = 'enabled'; public const MODULE_SETTING_ENABLED = 'enabled';
const DEFAULT_MODULE_SETTING_ENABLED = true; public const DEFAULT_MODULE_SETTING_ENABLED = true;
const MODULE_SETTING_WEEKDAYS = 'week_days'; public const MODULE_SETTING_WEEKDAYS = 'week_days';
const DEFAULT_MODULE_SETTING_WEEKDAYS = 'monday, tuesday, wednesday, thursday, friday, saturday, sunday'; public const DEFAULT_MODULE_SETTING_WEEKDAYS = 'monday, tuesday, wednesday, thursday, friday, saturday, sunday';
const MODULE_SETTING_TIME = 'time'; public const MODULE_SETTING_TIME = 'time';
/** /**
* @var Config can be used to mock config for tests * @var Config can be used to mock config for tests
@@ -111,15 +110,13 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
*/ */
public function getOConfig() public function getOConfig()
{ {
if (!isset($this->oConfig)) if (!isset($this->oConfig)) {
{
$this->oConfig = MetaModel::GetConfig(); $this->oConfig = MetaModel::GetConfig();
} }
return $this->oConfig; return $this->oConfig;
} }
/** /**
* Interpret current setting for the week days * Interpret current setting for the week days
* *
@@ -128,7 +125,7 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
*/ */
public function InterpretWeekDays() public function InterpretWeekDays()
{ {
static $aWEEKDAYTON = array( static $aWEEKDAYTON = [
'monday' => 1, 'monday' => 1,
'tuesday' => 2, 'tuesday' => 2,
'wednesday' => 3, 'wednesday' => 3,
@@ -136,32 +133,26 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
'friday' => 5, 'friday' => 5,
'saturday' => 6, 'saturday' => 6,
'sunday' => 7, 'sunday' => 7,
); ];
$aDays = array(); $aDays = [];
$sWeekDays = $this->getOConfig()->GetModuleSetting( $sWeekDays = $this->getOConfig()->GetModuleSetting(
$this->GetModuleName(), $this->GetModuleName(),
static::MODULE_SETTING_WEEKDAYS, static::MODULE_SETTING_WEEKDAYS,
static::DEFAULT_MODULE_SETTING_WEEKDAYS static::DEFAULT_MODULE_SETTING_WEEKDAYS
); );
if ($sWeekDays !== '') if ($sWeekDays !== '') {
{
$aWeekDaysRaw = explode(',', $sWeekDays); $aWeekDaysRaw = explode(',', $sWeekDays);
foreach ($aWeekDaysRaw as $sWeekDay) foreach ($aWeekDaysRaw as $sWeekDay) {
{
$sWeekDay = strtolower(trim($sWeekDay)); $sWeekDay = strtolower(trim($sWeekDay));
if (array_key_exists($sWeekDay, $aWEEKDAYTON)) if (array_key_exists($sWeekDay, $aWEEKDAYTON)) {
{
$aDays[] = $aWEEKDAYTON[$sWeekDay]; $aDays[] = $aWEEKDAYTON[$sWeekDay];
} } else {
else
{
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_WEEKDAYS."' (found '$sWeekDay')"); throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_WEEKDAYS."' (found '$sWeekDay')");
} }
} }
} }
if (count($aDays) === 0) if (count($aDays) === 0) {
{
throw new ProcessInvalidConfigException($this->GetModuleName().': missing setting \''.static::MODULE_SETTING_WEEKDAYS.'\''); throw new ProcessInvalidConfigException($this->GetModuleName().': missing setting \''.static::MODULE_SETTING_WEEKDAYS.'\'');
} }
$aDays = array_unique($aDays); $aDays = array_unique($aDays);
@@ -185,8 +176,7 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
static::DEFAULT_MODULE_SETTING_ENABLED static::DEFAULT_MODULE_SETTING_ENABLED
); );
if (!$bEnabled) if (!$bEnabled) {
{
return new DateTime('3000-01-01'); return new DateTime('3000-01-01');
} }
@@ -202,21 +192,17 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
static::GetDefaultModuleSettingTime() static::GetDefaultModuleSettingTime()
); );
$sProcessTime = trim($sProcessTime); $sProcessTime = trim($sProcessTime);
if (!preg_match('/[0-2]\d:[0-5]\d/', $sProcessTime)) if (!preg_match('/[0-2]\d:[0-5]\d/', $sProcessTime)) {
{
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_TIME."' (found '$sProcessTime')"); throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_TIME."' (found '$sProcessTime')");
} }
$oNow = new DateTime($sCurrentTime); $oNow = new DateTime($sCurrentTime);
$iNextPos = false; $iNextPos = false;
$sDay = $oNow->format('N'); $sDay = $oNow->format('N');
for ($iDay = (int) $sDay; $iDay <= 7; $iDay++) for ($iDay = (int) $sDay; $iDay <= 7; $iDay++) {
{
$iNextPos = array_search($iDay, $aDays, true); $iNextPos = array_search($iDay, $aDays, true);
if ($iNextPos !== false) if ($iNextPos !== false) {
{ if (($iDay > $oNow->format('N')) || ($oNow->format('H:i') < $sProcessTime)) {
if (($iDay > $oNow->format('N')) || ($oNow->format('H:i') < $sProcessTime))
{
break; break;
} }
$iNextPos = false; // necessary on sundays $iNextPos = false; // necessary on sundays
@@ -225,17 +211,14 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
// 3rd - Compute the result // 3rd - Compute the result
// //
if ($iNextPos === false) if ($iNextPos === false) {
{
// Jump to the first day within the next week // Jump to the first day within the next week
$iFirstDayOfWeek = $aDays[0]; $iFirstDayOfWeek = $aDays[0];
$iDayMove = $oNow->format('N') - $iFirstDayOfWeek; $iDayMove = $oNow->format('N') - $iFirstDayOfWeek;
$oRet = clone $oNow; $oRet = clone $oNow;
$oRet->modify(-$iDayMove.' days'); $oRet->modify(-$iDayMove.' days');
$oRet->modify('+1 weeks'); $oRet->modify('+1 weeks');
} } else {
else
{
$iNextDayOfWeek = $aDays[$iNextPos]; $iNextDayOfWeek = $aDays[$iNextPos];
$iMove = $iNextDayOfWeek - $oNow->format('N'); $iMove = $iNextDayOfWeek - $oNow->format('N');
$oRet = clone $oNow; $oRet = clone $oNow;

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2024 Combodo SAS // Copyright (C) 2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Class BackgroundTask * Class BackgroundTask
* A class to record information about the execution of background processes ({@link iProcess} impl) * A class to record information about the execution of background processes ({@link iProcess} impl)
@@ -46,49 +46,47 @@ class BackgroundTask extends DBObject
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "core/cmdb", "category" => "core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "class_name", "name_attcode" => "class_name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_backgroundtask", "db_table" => "priv_backgroundtask",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("class_name", array("allowed_values"=>null, "sql"=>"class_name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("class_name", ["allowed_values" => null, "sql" => "class_name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("first_run_date", array("allowed_values"=>null, "sql"=>"first_run_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("first_run_date", ["allowed_values" => null, "sql" => "first_run_date", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("latest_run_date", array("allowed_values"=>null, "sql"=>"latest_run_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("latest_run_date", ["allowed_values" => null, "sql" => "latest_run_date", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("next_run_date", array("allowed_values"=>null, "sql"=>"next_run_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("next_run_date", ["allowed_values" => null, "sql" => "next_run_date", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeInteger("total_exec_count", array("allowed_values"=>null, "sql"=>"total_exec_count", "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDecimal("latest_run_duration", array("allowed_values"=>null, "sql"=>"latest_run_duration", "digits"=> 8, "decimals"=> 3, "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDecimal("min_run_duration", array("allowed_values"=>null, "sql"=>"min_run_duration", "digits"=> 8, "decimals"=> 3, "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDecimal("max_run_duration", array("allowed_values"=>null, "sql"=>"max_run_duration", "digits"=> 8, "decimals"=> 3, "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDecimal("average_run_duration", array("allowed_values"=>null, "sql"=>"average_run_duration", "digits"=> 8, "decimals"=> 3, "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBoolean("running", array("allowed_values"=>null, "sql"=>"running", "default_value"=>false, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("total_exec_count", ["allowed_values" => null, "sql" => "total_exec_count", "default_value" => "0", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('active,paused,removed'), "sql"=>"status", "default_value"=>'active', "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDecimal("latest_run_duration", ["allowed_values" => null, "sql" => "latest_run_duration", "digits" => 8, "decimals" => 3, "default_value" => "0", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("system_user", array("allowed_values"=>null, "sql"=>"system_user", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDecimal("min_run_duration", ["allowed_values" => null, "sql" => "min_run_duration", "digits" => 8, "decimals" => 3, "default_value" => "0", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDecimal("max_run_duration", ["allowed_values" => null, "sql" => "max_run_duration", "digits" => 8, "decimals" => 3, "default_value" => "0", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDecimal("average_run_duration", ["allowed_values" => null, "sql" => "average_run_duration", "digits" => 8, "decimals" => 3, "default_value" => "0", "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeBoolean("running", ["allowed_values" => null, "sql" => "running", "default_value" => false, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("status", ["allowed_values" => new ValueSetEnum('active,paused,removed'), "sql" => "status", "default_value" => 'active', "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("system_user", ["allowed_values" => null, "sql" => "system_user", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
} }
public function ComputeDurations($fLatestDuration) public function ComputeDurations($fLatestDuration)
{ {
$iTotalRun = $this->Get('total_exec_count'); $iTotalRun = $this->Get('total_exec_count');
$fAverageDuration = ($this->Get('average_run_duration') * $iTotalRun + $fLatestDuration) / (1+$iTotalRun); $fAverageDuration = ($this->Get('average_run_duration') * $iTotalRun + $fLatestDuration) / (1 + $iTotalRun);
$this->Set('average_run_duration', sprintf('%.3f',$fAverageDuration)); $this->Set('average_run_duration', sprintf('%.3f', $fAverageDuration));
$this->Set('total_exec_count', 1+$iTotalRun); $this->Set('total_exec_count', 1 + $iTotalRun);
if ($fLatestDuration < $this->Get('min_run_duration')) if ($fLatestDuration < $this->Get('min_run_duration')) {
{ $this->Set('min_run_duration', sprintf('%.3f', $fLatestDuration));
$this->Set('min_run_duration', sprintf('%.3f',$fLatestDuration));
} }
if ($fLatestDuration > $this->Get('max_run_duration')) if ($fLatestDuration > $this->Get('max_run_duration')) {
{ $this->Set('max_run_duration', sprintf('%.3f', $fLatestDuration));
$this->Set('max_run_duration', sprintf('%.3f',$fLatestDuration));
} }
$this->Set('latest_run_duration', sprintf('%.3f',$fLatestDuration)); $this->Set('latest_run_duration', sprintf('%.3f', $fLatestDuration));
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Persistent class (internal) cmdbChange * Persistent class (internal) cmdbChange
* *
@@ -9,7 +10,7 @@
use Combodo\iTop\Core\CMDBChange\CMDBChangeOrigin; use Combodo\iTop\Core\CMDBChange\CMDBChangeOrigin;
/** /**
* A change as requested/validated at once by user, may groups many atomic changes * A change as requested/validated at once by user, may groups many atomic changes
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -17,26 +18,26 @@ class CMDBChange extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "core/cmdb, grant_by_profile", "category" => "core/cmdb, grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "date", "name_attcode" => "date",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_change", "db_table" => "priv_change",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'indexes' => array( 'indexes' => [
array('origin'), ['origin'],
), ],
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("date", ["allowed_values" => null, "sql" => "date", "default_value" => "NOW()", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("userinfo", ["allowed_values" => null, "sql" => "userinfo", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("allowed_values"=>null, "sql"=>"user_id", "targetclass"=>"User", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", ["allowed_values" => null, "sql" => "user_id", "targetclass" => "User", "is_null_allowed" => true, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum(implode(',', [CMDBChangeOrigin::INTERACTIVE, CMDBChangeOrigin::CSV_INTERACTIVE, CMDBChangeOrigin::CSV_IMPORT, CMDBChangeOrigin::WEBSERVICE_SOAP, CMDBChangeOrigin::WEBSERVICE_REST, CMDBChangeOrigin::SYNCHRO_DATA_SOURCE, CMDBChangeOrigin::EMAIL_PROCESSING, CMDBChangeOrigin::CUSTOM_EXTENSION])), "sql"=>"origin", "default_value"=>CMDBChangeOrigin::INTERACTIVE, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("origin", ["allowed_values" => new ValueSetEnum(implode(',', [CMDBChangeOrigin::INTERACTIVE, CMDBChangeOrigin::CSV_INTERACTIVE, CMDBChangeOrigin::CSV_IMPORT, CMDBChangeOrigin::WEBSERVICE_SOAP, CMDBChangeOrigin::WEBSERVICE_REST, CMDBChangeOrigin::SYNCHRO_DATA_SOURCE, CMDBChangeOrigin::EMAIL_PROCESSING, CMDBChangeOrigin::CUSTOM_EXTENSION])), "sql" => "origin", "default_value" => CMDBChangeOrigin::INTERACTIVE, "is_null_allowed" => true, "depends_on" => []]));
} }
/** /**
@@ -48,12 +49,9 @@ class CMDBChange extends DBObject
*/ */
public static function GetCurrentUserName() public static function GetCurrentUserName()
{ {
if (UserRights::IsImpersonated()) if (UserRights::IsImpersonated()) {
{
$sUserString = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUserFriendlyName(), UserRights::GetUserFriendlyName()); $sUserString = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUserFriendlyName(), UserRights::GetUserFriendlyName());
} } else {
else
{
$sUserString = UserRights::GetUserFriendlyName(); $sUserString = UserRights::GetUserFriendlyName();
} }
return $sUserString; return $sUserString;
@@ -74,12 +72,9 @@ class CMDBChange extends DBObject
public function GetUserName() public function GetUserName()
{ {
if (preg_match('/^(.*)\\(CSV\\)$/i', $this->Get('userinfo'), $aMatches)) if (preg_match('/^(.*)\\(CSV\\)$/i', $this->Get('userinfo'), $aMatches)) {
{
$sUser = $aMatches[1]; $sUser = $aMatches[1];
} } else {
else
{
$sUser = $this->Get('userinfo'); $sUser = $this->Get('userinfo');
} }
return $sUser; return $sUser;

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2010-2024 Combodo SAS * Copyright (C) 2010-2024 Combodo SAS
* *
@@ -18,7 +19,6 @@
* along with iTop. If not, see <http://www.gnu.org/licenses/> * along with iTop. If not, see <http://www.gnu.org/licenses/>
*/ */
/** /**
* Any extension to compute things like a stop watch deadline or working hours * Any extension to compute things like a stop watch deadline or working hours
* *
@@ -29,7 +29,7 @@
/** /**
* Metric computing for stop watches. * Metric computing for stop watches.
* Can be used for AttributeStopWatch goal (iTop XML node xpath: /itop_design/classes/class/fields/field/goal) * Can be used for AttributeStopWatch goal (iTop XML node xpath: /itop_design/classes/class/fields/field/goal)
*/ */
interface iMetricComputer interface iMetricComputer
{ {
public static function GetDescription(); public static function GetDescription();
@@ -44,7 +44,7 @@ interface iMetricComputer
/** /**
* Working time computing for stop watches * Working time computing for stop watches
*/ */
interface iWorkingTimeComputer interface iWorkingTimeComputer
{ {
public static function GetDescription(); public static function GetDescription();
@@ -58,7 +58,7 @@ interface iWorkingTimeComputer
* considering only the valid (open) hours for a specified object * considering only the valid (open) hours for a specified object
*/ */
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate); public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
/** /**
* @param DBObject $oObject The object for which to compute the duration * @param DBObject $oObject The object for which to compute the duration
* @param DateTime $oStartDate The starting point for the computation (default = now) * @param DateTime $oStartDate The starting point for the computation (default = now)
@@ -87,7 +87,7 @@ class DefaultMetricComputer implements iMetricComputer
/** /**
* Default implementation of working time computing * Default implementation of working time computing
*/ */
class DefaultWorkingTimeComputer implements iWorkingTimeComputer class DefaultWorkingTimeComputer implements iWorkingTimeComputer
{ {
public static function GetDescription() public static function GetDescription()
@@ -100,8 +100,7 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
*/ */
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate) public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{ {
if (class_exists('WorkingTimeRecorder')) if (class_exists('WorkingTimeRecorder')) {
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__); WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
} }
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n"; //echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
@@ -109,26 +108,23 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
// the specified duration to the given date/time // the specified duration to the given date/time
$oResult = clone $oStartDate; $oResult = clone $oStartDate;
$oResult->modify($iDuration.' seconds'); $oResult->modify($iDuration.' seconds');
if (class_exists('WorkingTimeRecorder')) if (class_exists('WorkingTimeRecorder')) {
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oResult->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_END); WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oResult->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_END);
} }
return $oResult; return $oResult;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate) public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{ {
if (class_exists('WorkingTimeRecorder')) if (class_exists('WorkingTimeRecorder')) {
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__); WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
} }
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n"; //echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
$iDuration = abs($oEndDate->format('U') - $oStartDate->format('U')); $iDuration = abs($oEndDate->format('U') - $oStartDate->format('U'));
if (class_exists('WorkingTimeRecorder')) if (class_exists('WorkingTimeRecorder')) {
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oEndDate->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_DURATION); WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oEndDate->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_DURATION);
} }
return $iDuration; return $iDuration;

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2016-2024 Combodo SAS // Copyright (C) 2016-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Simple helper class for keeping track of the context inside the call stack * Simple helper class for keeping track of the context inside the call stack
* *
@@ -63,7 +63,7 @@ class ContextTag
* @since 3.1.0 N°6047 * @since 3.1.0 N°6047
*/ */
public const TAG_IMPORT = 'Import'; public const TAG_IMPORT = 'Import';
/** /**
* @since 3.1.0 N°6047 * @since 3.1.0 N°6047
*/ */
public const TAG_EXPORT = 'Export'; public const TAG_EXPORT = 'Export';
@@ -74,7 +74,7 @@ class ContextTag
*/ */
public const TAG_OBJECT_SEARCH = 'ObjectSearch'; public const TAG_OBJECT_SEARCH = 'ObjectSearch';
protected static $aStack = array(); protected static $aStack = [];
/** /**
* Store a context tag on the stack * Store a context tag on the stack
@@ -124,33 +124,29 @@ class ContextTag
*/ */
public static function GetTags() public static function GetTags()
{ {
$aRawTags = array( $aRawTags = [
ContextTag::TAG_REST, ContextTag::TAG_REST,
ContextTag::TAG_SYNCHRO, ContextTag::TAG_SYNCHRO,
ContextTag::TAG_SETUP, ContextTag::TAG_SETUP,
ContextTag::TAG_CONSOLE, ContextTag::TAG_CONSOLE,
ContextTag::TAG_CRON, ContextTag::TAG_CRON,
ContextTag::TAG_PORTAL); ContextTag::TAG_PORTAL];
$aTags = array(); $aTags = [];
foreach ($aRawTags as $sRawTag) foreach ($aRawTags as $sRawTag) {
{
$aTags[$sRawTag] = Dict::S("Core:Context={$sRawTag}"); $aTags[$sRawTag] = Dict::S("Core:Context={$sRawTag}");
} }
$aPortalsConf = PortalDispatcherData::GetData(); $aPortalsConf = PortalDispatcherData::GetData();
$aDispatchers = array(); $aDispatchers = [];
foreach ($aPortalsConf as $sPortalId => $aConf) foreach ($aPortalsConf as $sPortalId => $aConf) {
{
$sHandlerClass = $aConf['handler']; $sHandlerClass = $aConf['handler'];
$aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId); $aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId);
} }
foreach ($aDispatchers as $sPortalId => $oDispatcher) foreach ($aDispatchers as $sPortalId => $oDispatcher) {
{ if ($sPortalId != 'backoffice') {
if ($sPortalId != 'backoffice')
{
$aTags['Portal:'.$sPortalId] = $oDispatcher->GetLabel(); $aTags['Portal:'.$sPortalId] = $oDispatcher->GetLabel();
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -17,14 +18,12 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
*/ */
/** /**
* Class ItopCounter * Class ItopCounter
* *
*/ */
final class ItopCounter final class ItopCounter
{ {
/** /**
* Key based counter. * Key based counter.
* The counter is protected against concurrency script. * The counter is protected against concurrency script.
@@ -48,8 +47,7 @@ final class ItopCounter
$oiTopMutex->Lock(); $oiTopMutex->Lock();
$bIsInsideTransaction = CMDBSource::IsInsideTransaction(); $bIsInsideTransaction = CMDBSource::IsInsideTransaction();
if ($bIsInsideTransaction) if ($bIsInsideTransaction) {
{
// # Transaction isolation hack: // # Transaction isolation hack:
// When inside a transaction, we need to open a new connection for the counter. // When inside a transaction, we need to open a new connection for the counter.
// So it is visible immediately to the connections outside of the transaction. // So it is visible immediately to the connections outside of the transaction.
@@ -59,75 +57,61 @@ final class ItopCounter
// we did not wanted this! As opening a short connection is less prone to starving than a long running one. // we did not wanted this! As opening a short connection is less prone to starving than a long running one.
// Plus it would trigger way more deadlocks! // Plus it would trigger way more deadlocks!
$hDBLink = self::InitMySQLSession(); $hDBLink = self::InitMySQLSession();
} } else {
else
{
$hDBLink = CMDBSource::GetMysqli(); $hDBLink = CMDBSource::GetMysqli();
} }
try try {
{ $oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', [
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
'key_name' => $sCounterName, 'key_name' => $sCounterName,
'namespace' => $sSelfClassName, 'namespace' => $sSelfClassName,
)); ]);
$oAttDef = MetaModel::GetAttributeDef(KeyValueStore::class, 'value'); $oAttDef = MetaModel::GetAttributeDef(KeyValueStore::class, 'value');
$aAttToLoad = array(KeyValueStore::class => array('value' => $oAttDef)); $aAttToLoad = [KeyValueStore::class => ['value' => $oAttDef]];
$sSql = $oFilter->MakeSelectQuery(array(), array(), $aAttToLoad); $sSql = $oFilter->MakeSelectQuery([], [], $aAttToLoad);
$hResult = mysqli_query($hDBLink, $sSql); $hResult = mysqli_query($hDBLink, $sSql);
$aCounter = mysqli_fetch_array($hResult, MYSQLI_NUM); $aCounter = mysqli_fetch_array($hResult, MYSQLI_NUM);
mysqli_free_result($hResult); mysqli_free_result($hResult);
//Rebuild the filter, as the MakeSelectQuery polluted the orignal and it cannot be reused //Rebuild the filter, as the MakeSelectQuery polluted the orignal and it cannot be reused
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array( $oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', [
'key_name' => $sCounterName, 'key_name' => $sCounterName,
'namespace' => $sSelfClassName, 'namespace' => $sSelfClassName,
)); ]);
if (is_null($aCounter)) if (is_null($aCounter)) {
{ if (null != $oNewObjectValueProvider) {
if (null != $oNewObjectValueProvider)
{
$iComputedValue = $oNewObjectValueProvider(); $iComputedValue = $oNewObjectValueProvider();
} } else {
else
{
$iComputedValue = 0; $iComputedValue = 0;
} }
$iCurrentValue = $iComputedValue + 1; $iCurrentValue = $iComputedValue + 1;
$aQueryParams = array( $aQueryParams = [
'key_name' => $sCounterName, 'key_name' => $sCounterName,
'value' => "$iCurrentValue", 'value' => "$iCurrentValue",
'namespace' => $sSelfClassName, 'namespace' => $sSelfClassName,
); ];
$sSql = $oFilter->MakeInsertQuery($aQueryParams); $sSql = $oFilter->MakeInsertQuery($aQueryParams);
} } else {
else
{
$iCurrentValue = (int) $aCounter[1]; $iCurrentValue = (int) $aCounter[1];
$iCurrentValue++; $iCurrentValue++;
$aQueryParams = array( $aQueryParams = [
'value' => "$iCurrentValue", 'value' => "$iCurrentValue",
); ];
$sSql = $oFilter->MakeUpdateQuery($aQueryParams); $sSql = $oFilter->MakeUpdateQuery($aQueryParams);
} }
$hResult = mysqli_query($hDBLink, $sSql); $hResult = mysqli_query($hDBLink, $sSql);
} } catch (Exception $e) {
catch(Exception $e)
{
IssueLog::Error($e->getMessage()); IssueLog::Error($e->getMessage());
throw $e; throw $e;
} } finally {
finally if ($bIsInsideTransaction) {
{
if ($bIsInsideTransaction)
{
mysqli_close($hDBLink); mysqli_close($hDBLink);
} }
$oiTopMutex->Unlock(); $oiTopMutex->Unlock();
@@ -157,8 +141,7 @@ final class ItopCounter
{ {
$sRootClass = MetaModel::GetRootClass($sLeafClass); $sRootClass = MetaModel::GetRootClass($sLeafClass);
$oNewObjectCallback = function() use ($sRootClass) $oNewObjectCallback = function () use ($sRootClass) {
{
$sRootTable = MetaModel::DBGetTable($sRootClass); $sRootTable = MetaModel::DBGetTable($sRootClass);
$sIdField = MetaModel::DBGetKey($sRootClass); $sIdField = MetaModel::DBGetKey($sRootClass);
@@ -186,17 +169,14 @@ final class ItopCounter
$hDBLink = CMDBSource::GetMysqliInstance($sDBHost, $sDBUser, $sDBPwd, $sDBName, $bDBTlsEnabled, $sDBTlsCA, false); $hDBLink = CMDBSource::GetMysqliInstance($sDBHost, $sDBUser, $sDBPwd, $sDBName, $bDBTlsEnabled, $sDBTlsCA, false);
if (!$hDBLink) if (!$hDBLink) {
{ throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), ['host' => $sDBHost, 'user' => $sDBUser]);
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser)); }
}
return $hDBLink; return $hDBLink;
} }
} }
/** /**
* Persistent classes for a CMDB * Persistent classes for a CMDB
* *
@@ -208,44 +188,43 @@ class KeyValueStore extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array( $aParams = [
'category' => '', 'category' => '',
'key_type' => 'autoincrement', 'key_type' => 'autoincrement',
'name_attcode' => array('key_name'), 'name_attcode' => ['key_name'],
'state_attcode' => '', 'state_attcode' => '',
'reconc_keys' => array(''), 'reconc_keys' => [''],
'db_table' => 'key_value_store', 'db_table' => 'key_value_store',
'db_key_field' => 'id', 'db_key_field' => 'id',
'db_finalclass_field' => '', 'db_finalclass_field' => '',
'indexes' => array ( 'indexes' => [
array ( [
0 => 'key_name', 0 => 'key_name',
1 => 'namespace', 1 => 'namespace',
), ],
),); ],];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("namespace", array("allowed_values"=>null, "sql"=>'namespace', "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false))); MetaModel::Init_AddAttribute(new AttributeString("namespace", ["allowed_values" => null, "sql" => 'namespace', "default_value" => null, "is_null_allowed" => true, "depends_on" => [], "always_load_in_tables" => false]));
MetaModel::Init_AddAttribute(new AttributeString("key_name", array("allowed_values"=>null, "sql"=>'key_name', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false))); MetaModel::Init_AddAttribute(new AttributeString("key_name", ["allowed_values" => null, "sql" => 'key_name', "default_value" => '', "is_null_allowed" => false, "depends_on" => [], "always_load_in_tables" => false]));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>'value', "default_value"=>'0', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false))); MetaModel::Init_AddAttribute(new AttributeString("value", ["allowed_values" => null, "sql" => 'value', "default_value" => '0', "is_null_allowed" => false, "depends_on" => [], "always_load_in_tables" => false]));
MetaModel::Init_SetZListItems('details', array ( MetaModel::Init_SetZListItems('details', [
0 => 'key_name', 0 => 'key_name',
1 => 'value', 1 => 'value',
2 => 'namespace', 2 => 'namespace',
)); ]);
MetaModel::Init_SetZListItems('standard_search', array ( MetaModel::Init_SetZListItems('standard_search', [
0 => 'key_name', 0 => 'key_name',
1 => 'value', 1 => 'value',
2 => 'namespace', 2 => 'namespace',
)); ]);
MetaModel::Init_SetZListItems('list', array ( MetaModel::Init_SetZListItems('list', [
0 => 'key_name', 0 => 'key_name',
1 => 'value', 1 => 'value',
2 => 'namespace', 2 => 'namespace',
)); ]);
; ;
} }
}
}

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -40,56 +41,48 @@ class CSVBulkExport extends TabularBulkExport
{ {
parent::ReadParameters(); parent::ReadParameters();
$this->aStatusInfo['separator'] = utils::ReadParam('separator', ',', true, 'raw_data'); $this->aStatusInfo['separator'] = utils::ReadParam('separator', ',', true, 'raw_data');
if (strtolower($this->aStatusInfo['separator']) == 'tab') if (strtolower($this->aStatusInfo['separator']) == 'tab') {
{
$this->aStatusInfo['separator'] = "\t"; $this->aStatusInfo['separator'] = "\t";
} } elseif (strtolower($this->aStatusInfo['separator']) == 'other') {
else if (strtolower($this->aStatusInfo['separator']) == 'other')
{
$this->aStatusInfo['separator'] = utils::ReadParam('other-separator', ',', true, 'raw_data'); $this->aStatusInfo['separator'] = utils::ReadParam('other-separator', ',', true, 'raw_data');
} }
$this->aStatusInfo['text_qualifier'] = utils::ReadParam('text-qualifier', '"', true, 'raw_data'); $this->aStatusInfo['text_qualifier'] = utils::ReadParam('text-qualifier', '"', true, 'raw_data');
if (strtolower($this->aStatusInfo['text_qualifier']) == 'other') if (strtolower($this->aStatusInfo['text_qualifier']) == 'other') {
{
$this->aStatusInfo['text_qualifier'] = utils::ReadParam('other-text-qualifier', '"', true, 'raw_data'); $this->aStatusInfo['text_qualifier'] = utils::ReadParam('other-text-qualifier', '"', true, 'raw_data');
} }
$this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data')); $this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data'));
$this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true); $this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true);
$sDateFormatRadio = utils::ReadParam('csv_date_format_radio', ''); $sDateFormatRadio = utils::ReadParam('csv_date_format_radio', '');
switch($sDateFormatRadio) switch ($sDateFormatRadio) {
{
case 'default': case 'default':
// Export from the UI => format = same as is the UI // Export from the UI => format = same as is the UI
$this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat();
break; break;
case 'custom': case 'custom':
// Custom format specified from the UI // Custom format specified from the UI
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
break; break;
default: default:
// Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data');
} }
} }
protected function SuggestField($sClass, $sAttCode) protected function SuggestField($sClass, $sAttCode)
{ {
switch($sAttCode) switch ($sAttCode) {
{
case 'id': // replace 'id' by 'friendlyname' case 'id': // replace 'id' by 'friendlyname'
$sAttCode = 'friendlyname'; $sAttCode = 'friendlyname';
break; break;
default: default:
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeExternalKey) if ($oAttDef instanceof AttributeExternalKey) {
{
$sAttCode .= '_friendlyname'; $sAttCode .= '_friendlyname';
} }
} }
@@ -99,7 +92,7 @@ class CSVBulkExport extends TabularBulkExport
public function EnumFormParts() public function EnumFormParts()
{ {
return array_merge(parent::EnumFormParts(), array('csv_options' => array('separator', 'charset', 'text-qualifier', 'no_localize', 'formatted_text'), 'interactive_fields_csv' => array('interactive_fields_csv'))); return array_merge(parent::EnumFormParts(), ['csv_options' => ['separator', 'charset', 'text-qualifier', 'no_localize', 'formatted_text'], 'interactive_fields_csv' => ['interactive_fields_csv']]);
} }
/** /**
@@ -128,11 +121,11 @@ class CSVBulkExport extends TabularBulkExport
$sRawSeparator = utils::ReadParam('separator', ',', true, 'raw_data'); $sRawSeparator = utils::ReadParam('separator', ',', true, 'raw_data');
$sCustomDateTimeFormat = utils::ReadParam('', ',', true, 'raw_data'); $sCustomDateTimeFormat = utils::ReadParam('', ',', true, 'raw_data');
$aSep = array( $aSep = [
';' => Dict::S('UI:CSVImport:SeparatorSemicolon+'), ';' => Dict::S('UI:CSVImport:SeparatorSemicolon+'),
',' => Dict::S('UI:CSVImport:SeparatorComma+'), ',' => Dict::S('UI:CSVImport:SeparatorComma+'),
'tab' => Dict::S('UI:CSVImport:SeparatorTab+'), 'tab' => Dict::S('UI:CSVImport:SeparatorTab+'),
); ];
$sOtherSeparator = ''; $sOtherSeparator = '';
if (!array_key_exists($sRawSeparator, $aSep)) { if (!array_key_exists($sRawSeparator, $aSep)) {
$sOtherSeparator = $sRawSeparator; $sOtherSeparator = $sRawSeparator;
@@ -155,10 +148,10 @@ class CSVBulkExport extends TabularBulkExport
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetTextQualifier)); $oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetTextQualifier));
$sRawQualifier = utils::ReadParam('text-qualifier', '"', true, 'raw_data'); $sRawQualifier = utils::ReadParam('text-qualifier', '"', true, 'raw_data');
$aQualifiers = array( $aQualifiers = [
'"' => Dict::S('UI:CSVImport:QualifierDoubleQuote+'), '"' => Dict::S('UI:CSVImport:QualifierDoubleQuote+'),
'\'' => Dict::S('UI:CSVImport:QualifierSimpleQuote+'), '\'' => Dict::S('UI:CSVImport:QualifierSimpleQuote+'),
); ];
$sOtherQualifier = ''; $sOtherQualifier = '';
if (!array_key_exists($sRawQualifier, $aQualifiers)) { if (!array_key_exists($sRawQualifier, $aQualifiers)) {
$sOtherQualifier = $sRawQualifier; $sOtherQualifier = $sRawQualifier;
@@ -230,7 +223,6 @@ class CSVBulkExport extends TabularBulkExport
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox'); $oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
$oFieldSetDate->AddSubBlock($oRadioCustom); $oFieldSetDate->AddSubBlock($oRadioCustom);
$oP->add_ready_script( $oP->add_ready_script(
<<<EOF <<<EOF
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); }); $('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
@@ -243,9 +235,8 @@ EOF
return $oPanel; return $oPanel;
break; break;
default: default:
return parent:: GetFormPart($oP, $sPartId); return parent::GetFormPart($oP, $sPartId);
} }
} }
@@ -253,8 +244,7 @@ EOF
{ {
if ($sAttCode != 'id') { if ($sAttCode != 'id') {
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime if ($oAttDef instanceof AttributeDateTime) { // AttributeDate is derived from AttributeDateTime
{
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date'; $sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>'; return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
@@ -266,14 +256,13 @@ EOF
protected function GetValue($oObj, $sAttCode) protected function GetValue($oObj, $sAttCode)
{ {
switch($sAttCode) switch ($sAttCode) {
{
case 'id': case 'id':
$sRet = $oObj->GetKey(); $sRet = $oObj->GetKey();
break; break;
default: default:
$sRet = trim($oObj->GetAsCSV($sAttCode), '"'); $sRet = trim($oObj->GetAsCSV($sAttCode), '"');
} }
return $sRet; return $sRet;
} }
@@ -285,20 +274,17 @@ EOF
$this->aStatusInfo['position'] = 0; $this->aStatusInfo['position'] = 0;
$this->aStatusInfo['total'] = $oSet->Count(); $this->aStatusInfo['total'] = $oSet->Count();
$aData = array(); $aData = [];
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) {
{
$aData[] = $aFieldSpec['sColLabel']; $aData[] = $aFieldSpec['sColLabel'];
} }
$sFrom = array("\r\n", $this->aStatusInfo['text_qualifier']); $sFrom = ["\r\n", $this->aStatusInfo['text_qualifier']];
$sTo = array("\n", $this->aStatusInfo['text_qualifier'].$this->aStatusInfo['text_qualifier']); $sTo = ["\n", $this->aStatusInfo['text_qualifier'].$this->aStatusInfo['text_qualifier']];
foreach($aData as $idx => $sData) foreach ($aData as $idx => $sData) {
{
// Escape and encode (if needed) the headers // Escape and encode (if needed) the headers
$sEscaped = str_replace($sFrom, $sTo, (string)$sData); $sEscaped = str_replace($sFrom, $sTo, (string)$sData);
$aData[$idx] = $this->aStatusInfo['text_qualifier'].$sEscaped.$this->aStatusInfo['text_qualifier']; $aData[$idx] = $this->aStatusInfo['text_qualifier'].$sEscaped.$this->aStatusInfo['text_qualifier'];
if ($this->aStatusInfo['charset'] != 'UTF-8') if ($this->aStatusInfo['charset'] != 'UTF-8') {
{
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string // Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
// and thus to convert field by field and not the whole row or file at once (see ticket N°991) // and thus to convert field by field and not the whole row or file at once (see ticket N°991)
$aData[$idx] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $aData[$idx]); $aData[$idx] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $aData[$idx]);
@@ -325,45 +311,37 @@ EOF
$sExportDateTimeFormat = $this->aStatusInfo['date_format']; $sExportDateTimeFormat = $this->aStatusInfo['date_format'];
$oPrevDateTimeFormat = AttributeDateTime::GetFormat(); $oPrevDateTimeFormat = AttributeDateTime::GetFormat();
$oPrevDateFormat = AttributeDate::GetFormat(); $oPrevDateFormat = AttributeDate::GetFormat();
if ($sExportDateTimeFormat !== (string)$oPrevDateTimeFormat) if ($sExportDateTimeFormat !== (string)$oPrevDateTimeFormat) {
{
// Change date & time formats // Change date & time formats
$oDateTimeFormat = new DateTimeFormat($sExportDateTimeFormat); $oDateTimeFormat = new DateTimeFormat($sExportDateTimeFormat);
$oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat()); $oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat());
AttributeDateTime::SetFormat($oDateTimeFormat); AttributeDateTime::SetFormat($oDateTimeFormat);
AttributeDate::SetFormat($oDateFormat); AttributeDate::SetFormat($oDateFormat);
} }
while($aRow = $oSet->FetchAssoc()) while ($aRow = $oSet->FetchAssoc()) {
{
set_time_limit(intval($iLoopTimeLimit)); set_time_limit(intval($iLoopTimeLimit));
$aData = array(); $aData = [];
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) {
{
$sAlias = $aFieldSpec['sAlias']; $sAlias = $aFieldSpec['sAlias'];
$sAttCode = $aFieldSpec['sAttCode']; $sAttCode = $aFieldSpec['sAttCode'];
$sField = ''; $sField = '';
$oObj = $aRow[$sAlias]; $oObj = $aRow[$sAlias];
if ($oObj != null) if ($oObj != null) {
{ switch ($sAttCode) {
switch($sAttCode)
{
case 'id': case 'id':
$sField = $oObj->GetKey(); $sField = $oObj->GetKey();
break; break;
default: default:
$sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']); $sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']);
} }
} }
if ($this->aStatusInfo['charset'] != 'UTF-8') if ($this->aStatusInfo['charset'] != 'UTF-8') {
{
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string // Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
// and thus to convert field by field and not the whole row or file at once (see ticket N°991) // and thus to convert field by field and not the whole row or file at once (see ticket N°991)
$aData[] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $sField); $aData[] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $sField);
} } else {
else
{
$aData[] = $sField; $aData[] = $sField;
} }
} }
@@ -375,27 +353,23 @@ EOF
AttributeDate::SetFormat($oPrevDateFormat); AttributeDate::SetFormat($oPrevDateFormat);
set_time_limit(intval($iPreviousTimeLimit)); set_time_limit(intval($iPreviousTimeLimit));
$this->aStatusInfo['position'] += $this->iChunkSize; $this->aStatusInfo['position'] += $this->iChunkSize;
if ($this->aStatusInfo['total'] == 0) if ($this->aStatusInfo['total'] == 0) {
{
$iPercentage = 100; $iPercentage = 100;
} } else {
else $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total']));
{
$iPercentage = floor(min(100.0, 100.0*$this->aStatusInfo['position']/$this->aStatusInfo['total']));
} }
if ($iCount < $this->iChunkSize) if ($iCount < $this->iChunkSize) {
{
$sRetCode = 'done'; $sRetCode = 'done';
} }
$aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); $aStatus = ['code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage];
return $sData; return $sData;
} }
public function GetSupportedFormats() public function GetSupportedFormats()
{ {
return array('csv' => Dict::S('Core:BulkExport:CSVFormat')); return ['csv' => Dict::S('Core:BulkExport:CSVFormat')];
} }
public function GetMimeType() public function GetMimeType()

View File

@@ -1,10 +1,10 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
define('stSTARTING', 1); //grey zone: the type is undetermined define('stSTARTING', 1); //grey zone: the type is undetermined
define('stRAW', 2); //building a non-qualified string define('stRAW', 2); //building a non-qualified string
define('stQUALIFIED', 3); //building qualified string define('stQUALIFIED', 3); //building qualified string
@@ -19,7 +19,6 @@ define('evEND', 5);
define('NULL_VALUE', '<NULL>'); define('NULL_VALUE', '<NULL>');
/** /**
* CSVParser * CSVParser
* *
@@ -41,9 +40,9 @@ class CSVParser
} }
protected $m_sCurrCell = ''; protected $m_sCurrCell = '';
protected $m_aCurrRow = array(); protected $m_aCurrRow = [];
protected $m_iToSkip = 0; protected $m_iToSkip = 0;
protected $m_aDataSet = array(); protected $m_aDataSet = [];
protected function __AddChar($c) protected function __AddChar($c)
{ {
@@ -55,27 +54,20 @@ class CSVParser
} }
protected function __AddCell($c = null, $aFieldMap = null, $bTrimSpaces = false) protected function __AddCell($c = null, $aFieldMap = null, $bTrimSpaces = false)
{ {
if ($bTrimSpaces) if ($bTrimSpaces) {
{
$sCell = trim($this->m_sCurrCell); $sCell = trim($this->m_sCurrCell);
} } else {
else
{
$sCell = $this->m_sCurrCell; $sCell = $this->m_sCurrCell;
} }
if ($sCell == NULL_VALUE) if ($sCell == NULL_VALUE) {
{
$sCell = null; $sCell = null;
} }
if (!is_null($aFieldMap)) if (!is_null($aFieldMap)) {
{
$iNextCol = count($this->m_aCurrRow); $iNextCol = count($this->m_aCurrRow);
$iNextName = $aFieldMap[$iNextCol]; $iNextName = $aFieldMap[$iNextCol];
$this->m_aCurrRow[$iNextName] = $sCell; $this->m_aCurrRow[$iNextName] = $sCell;
} } else {
else
{
$this->m_aCurrRow[] = $sCell; $this->m_aCurrRow[] = $sCell;
} }
$this->m_sCurrCell = ''; $this->m_sCurrCell = '';
@@ -84,33 +76,24 @@ class CSVParser
{ {
$this->__AddCell($c, $aFieldMap, $bTrimSpaces); $this->__AddCell($c, $aFieldMap, $bTrimSpaces);
if ($this->m_iToSkip > 0) if ($this->m_iToSkip > 0) {
{
$this->m_iToSkip--; $this->m_iToSkip--;
} } elseif (count($this->m_aCurrRow) > 1) {
elseif (count($this->m_aCurrRow) > 1)
{
$this->m_aDataSet[] = $this->m_aCurrRow; $this->m_aDataSet[] = $this->m_aCurrRow;
} } elseif (count($this->m_aCurrRow) == 1) {
elseif (count($this->m_aCurrRow) == 1)
{
// Get the unique value // Get the unique value
$aValues = array_values($this->m_aCurrRow); $aValues = array_values($this->m_aCurrRow);
$sValue = $aValues[0]; $sValue = $aValues[0];
if (strlen($sValue) > 0) if (strlen($sValue) > 0) {
{
$this->m_aDataSet[] = $this->m_aCurrRow; $this->m_aDataSet[] = $this->m_aCurrRow;
} }
} } else {
else
{
// blank line, skip silently // blank line, skip silently
} }
$this->m_aCurrRow = array(); $this->m_aCurrRow = [];
// More time for the next row // More time for the next row
if ($this->m_iTimeLimitPerRow !== null) if ($this->m_iTimeLimitPerRow !== null) {
{
set_time_limit(intval($this->m_iTimeLimitPerRow)); set_time_limit(intval($this->m_iTimeLimitPerRow));
} }
} }
@@ -124,87 +107,71 @@ class CSVParser
$this->__AddRow($c, $aFieldMap, true); $this->__AddRow($c, $aFieldMap, true);
} }
function ToArray($iToSkip = 1, $aFieldMap = null, $iMax = 0) public function ToArray($iToSkip = 1, $aFieldMap = null, $iMax = 0)
{ {
$aTransitions = array(); $aTransitions = [];
$aTransitions[stSTARTING][evBLANK] = array('', stSTARTING); $aTransitions[stSTARTING][evBLANK] = ['', stSTARTING];
$aTransitions[stSTARTING][evSEPARATOR] = array('__AddCell', stSTARTING); $aTransitions[stSTARTING][evSEPARATOR] = ['__AddCell', stSTARTING];
$aTransitions[stSTARTING][evNEWLINE] = array('__AddRow', stSTARTING); $aTransitions[stSTARTING][evNEWLINE] = ['__AddRow', stSTARTING];
$aTransitions[stSTARTING][evTEXTQUAL] = array('', stQUALIFIED); $aTransitions[stSTARTING][evTEXTQUAL] = ['', stQUALIFIED];
$aTransitions[stSTARTING][evOTHERCHAR] = array('__AddChar', stRAW); $aTransitions[stSTARTING][evOTHERCHAR] = ['__AddChar', stRAW];
$aTransitions[stSTARTING][evEND] = array('__AddRow', stSTARTING); $aTransitions[stSTARTING][evEND] = ['__AddRow', stSTARTING];
$aTransitions[stRAW][evBLANK] = array('__AddChar', stRAW); $aTransitions[stRAW][evBLANK] = ['__AddChar', stRAW];
$aTransitions[stRAW][evSEPARATOR] = array('__AddCellTrimmed', stSTARTING); $aTransitions[stRAW][evSEPARATOR] = ['__AddCellTrimmed', stSTARTING];
$aTransitions[stRAW][evNEWLINE] = array('__AddRowTrimmed', stSTARTING); $aTransitions[stRAW][evNEWLINE] = ['__AddRowTrimmed', stSTARTING];
$aTransitions[stRAW][evTEXTQUAL] = array('__AddChar', stRAW); $aTransitions[stRAW][evTEXTQUAL] = ['__AddChar', stRAW];
$aTransitions[stRAW][evOTHERCHAR] = array('__AddChar', stRAW); $aTransitions[stRAW][evOTHERCHAR] = ['__AddChar', stRAW];
$aTransitions[stRAW][evEND] = array('__AddRowTrimmed', stSTARTING); $aTransitions[stRAW][evEND] = ['__AddRowTrimmed', stSTARTING];
$aTransitions[stQUALIFIED][evBLANK] = array('__AddChar', stQUALIFIED); $aTransitions[stQUALIFIED][evBLANK] = ['__AddChar', stQUALIFIED];
$aTransitions[stQUALIFIED][evSEPARATOR] = array('__AddChar', stQUALIFIED); $aTransitions[stQUALIFIED][evSEPARATOR] = ['__AddChar', stQUALIFIED];
$aTransitions[stQUALIFIED][evNEWLINE] = array('__AddChar', stQUALIFIED); $aTransitions[stQUALIFIED][evNEWLINE] = ['__AddChar', stQUALIFIED];
$aTransitions[stQUALIFIED][evTEXTQUAL] = array('', stESCAPED); $aTransitions[stQUALIFIED][evTEXTQUAL] = ['', stESCAPED];
$aTransitions[stQUALIFIED][evOTHERCHAR] = array('__AddChar', stQUALIFIED); $aTransitions[stQUALIFIED][evOTHERCHAR] = ['__AddChar', stQUALIFIED];
$aTransitions[stQUALIFIED][evEND] = array('__AddRow', stSTARTING); $aTransitions[stQUALIFIED][evEND] = ['__AddRow', stSTARTING];
$aTransitions[stESCAPED][evBLANK] = array('', stESCAPED); $aTransitions[stESCAPED][evBLANK] = ['', stESCAPED];
$aTransitions[stESCAPED][evSEPARATOR] = array('__AddCell', stSTARTING); $aTransitions[stESCAPED][evSEPARATOR] = ['__AddCell', stSTARTING];
$aTransitions[stESCAPED][evNEWLINE] = array('__AddRow', stSTARTING); $aTransitions[stESCAPED][evNEWLINE] = ['__AddRow', stSTARTING];
$aTransitions[stESCAPED][evTEXTQUAL] = array('__AddChar', stQUALIFIED); $aTransitions[stESCAPED][evTEXTQUAL] = ['__AddChar', stQUALIFIED];
$aTransitions[stESCAPED][evOTHERCHAR] = array('__AddChar', stSTARTING); $aTransitions[stESCAPED][evOTHERCHAR] = ['__AddChar', stSTARTING];
$aTransitions[stESCAPED][evEND] = array('__AddRow', stSTARTING); $aTransitions[stESCAPED][evEND] = ['__AddRow', stSTARTING];
// Reset parser variables // Reset parser variables
$this->m_sCurrCell = ''; $this->m_sCurrCell = '';
$this->m_aCurrRow = array(); $this->m_aCurrRow = [];
$this->m_iToSkip = $iToSkip; $this->m_iToSkip = $iToSkip;
$this->m_aDataSet = array(); $this->m_aDataSet = [];
$iDataLength = strlen($this->m_sCSVData); $iDataLength = strlen($this->m_sCSVData);
$iState = stSTARTING; $iState = stSTARTING;
$iTimeLimit = null; $iTimeLimit = null;
if ($this->m_iTimeLimitPerRow !== null) if ($this->m_iTimeLimitPerRow !== null) {
{
// Give some time for the first row // Give some time for the first row
$iTimeLimit = ini_get('max_execution_time'); $iTimeLimit = ini_get('max_execution_time');
set_time_limit(intval($this->m_iTimeLimitPerRow)); set_time_limit(intval($this->m_iTimeLimitPerRow));
} }
for($i = 0; $i <= $iDataLength ; $i++) for ($i = 0; $i <= $iDataLength ; $i++) {
{ if ($i == $iDataLength) {
if ($i == $iDataLength)
{
$c = null; $c = null;
$iEvent = evEND; $iEvent = evEND;
} } else {
else
{
$c = $this->m_sCSVData[$i]; $c = $this->m_sCSVData[$i];
if ($c == $this->m_sSep) if ($c == $this->m_sSep) {
{
$iEvent = evSEPARATOR; $iEvent = evSEPARATOR;
} } elseif ($c == ' ') {
elseif ($c == ' ')
{
$iEvent = evBLANK; $iEvent = evBLANK;
} } elseif ($c == "\t") {
elseif ($c == "\t")
{
$iEvent = evBLANK; $iEvent = evBLANK;
} } elseif ($c == "\n") {
elseif ($c == "\n")
{
$iEvent = evNEWLINE; $iEvent = evNEWLINE;
} } elseif ($c == $this->m_sTextQualifier) {
elseif ($c == $this->m_sTextQualifier)
{
$iEvent = evTEXTQUAL; $iEvent = evTEXTQUAL;
} } else {
else
{
$iEvent = evOTHERCHAR; $iEvent = evOTHERCHAR;
} }
} }
@@ -212,24 +179,21 @@ class CSVParser
$sAction = $aTransitions[$iState][$iEvent][0]; $sAction = $aTransitions[$iState][$iEvent][0];
$iState = $aTransitions[$iState][$iEvent][1]; $iState = $aTransitions[$iState][$iEvent][1];
if (!empty($sAction)) if (!empty($sAction)) {
{ $aCallSpec = [$this, $sAction];
$aCallSpec = array($this, $sAction); if (is_callable($aCallSpec)) {
if (is_callable($aCallSpec))
{
call_user_func($aCallSpec, $c, $aFieldMap); call_user_func($aCallSpec, $c, $aFieldMap);
} } else {
else
{
throw new CSVParserException("CSVParser: unknown verb '$sAction'"); throw new CSVParserException("CSVParser: unknown verb '$sAction'");
} }
} }
$iLineCount = count($this->m_aDataSet); $iLineCount = count($this->m_aDataSet);
if (($iMax > 0) && ($iLineCount >= $iMax)) break; if (($iMax > 0) && ($iLineCount >= $iMax)) {
break;
}
} }
if ($iTimeLimit !== null) if ($iTimeLimit !== null) {
{
// Restore the previous time limit // Restore the previous time limit
set_time_limit(intval($iTimeLimit)); set_time_limit(intval($iTimeLimit));
} }
@@ -242,6 +206,3 @@ class CSVParser
return $aHeader[0]; return $aHeader[0];
} }
} }
?>

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2024 Combodo SAS // Copyright (C) 2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -23,7 +24,8 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
abstract class CustomFieldsHandler { abstract class CustomFieldsHandler
{
/** @var string $sAttCode */ /** @var string $sAttCode */
protected $sAttCode; protected $sAttCode;
/** @var array{ /** @var array{
@@ -47,7 +49,8 @@ abstract class CustomFieldsHandler {
* *
* @param $sAttCode * @param $sAttCode
*/ */
final public function __construct($sAttCode) { final public function __construct($sAttCode)
{
$this->sAttCode = $sAttCode; $this->sAttCode = $sAttCode;
$this->aValues = null; $this->aValues = null;
} }
@@ -59,7 +62,8 @@ abstract class CustomFieldsHandler {
* @throws \ApplicationException if {@link static::$oForm} attribute not initialized yet * @throws \ApplicationException if {@link static::$oForm} attribute not initialized yet
* @since 3.1.0 N°6322 N°1150 Add template_id checks * @since 3.1.0 N°6322 N°1150 Add template_id checks
*/ */
public function Validate(DBObject $oHostObject) { public function Validate(DBObject $oHostObject)
{
if (false === isset($this->oForm)) { if (false === isset($this->oForm)) {
throw new ApplicationException('oForm attribute not init yet. You must call BuildForm before this method !'); throw new ApplicationException('oForm attribute not init yet. You must call BuildForm before this method !');
} }
@@ -68,9 +72,8 @@ abstract class CustomFieldsHandler {
$this->oForm->Validate(); $this->oForm->Validate();
if ($this->oForm->GetValid()) { if ($this->oForm->GetValid()) {
$ret = true; $ret = true;
} } else {
else { $aMessages = [];
$aMessages = array();
foreach ($this->oForm->GetErrorMessages() as $sFieldId => $aFieldMessages) { foreach ($this->oForm->GetErrorMessages() as $sFieldId => $aFieldMessages) {
$aMessages[] = $sFieldId.': '.implode(', ', $aFieldMessages); $aMessages[] = $sFieldId.': '.implode(', ', $aFieldMessages);
} }
@@ -87,7 +90,8 @@ abstract class CustomFieldsHandler {
* *
* @return \Combodo\iTop\Form\Form * @return \Combodo\iTop\Form\Form
*/ */
public function GetForm() { public function GetForm()
{
return $this->oForm; return $this->oForm;
} }
@@ -96,15 +100,17 @@ abstract class CustomFieldsHandler {
$this->aValues = $aValues; $this->aValues = $aValues;
} }
public static function GetPrerequisiteAttributes($sClass = null) { public static function GetPrerequisiteAttributes($sClass = null)
return array(); {
return [];
} }
/** /**
* List the available verbs for 'GetForTemplate' * List the available verbs for 'GetForTemplate'
*/ */
public static function EnumTemplateVerbs() { public static function EnumTemplateVerbs()
return array(); {
return [];
} }
/** /**
@@ -169,7 +175,6 @@ abstract class CustomFieldsHandler {
return null; return null;
} }
/** /**
* @param DBObject $oHostObject * @param DBObject $oHostObject
* *

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,10 +17,9 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* data generator * data generator
* helps the consultants in creating dummy data sets, for various test purposes (validation, usability, scalability) * helps the consultants in creating dummy data sets, for various test purposes (validation, usability, scalability)
* *
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -37,60 +37,50 @@ class cmdbDataGenerator
protected $m_sOrganizationCode; protected $m_sOrganizationCode;
protected $m_sOrganizationName; protected $m_sOrganizationName;
protected $m_OrganizationDomains; protected $m_OrganizationDomains;
/** /**
* Constructor * Constructor
*/ */
public function __construct($sOrganizationId = "") public function __construct($sOrganizationId = "")
{ {
global $aCompanies, $aCompaniesCode; global $aCompanies, $aCompaniesCode;
if ($sOrganizationId == '') if ($sOrganizationId == '') {
{
// No organization provided, pick a random and unused one from our predefined list // No organization provided, pick a random and unused one from our predefined list
$retries = 5*count($aCompanies); $retries = 5 * count($aCompanies);
while ( ($retries > 0) && !isset($this->m_sOrganizationCode)) // Stupid algorithm, but I'm too lazy to do something bulletproof tonight while (($retries > 0) && !isset($this->m_sOrganizationCode)) { // Stupid algorithm, but I'm too lazy to do something bulletproof tonight
{
$index = rand(0, count($aCompanies) - 1); $index = rand(0, count($aCompanies) - 1);
if (!$this->OrganizationExists($aCompanies[$index]['code'])) if (!$this->OrganizationExists($aCompanies[$index]['code'])) {
{
$this->m_sOrganizationCode = $aCompanies[$index]['code']; $this->m_sOrganizationCode = $aCompanies[$index]['code'];
$this->m_sOrganizationName = $aCompanies[$index]['name']; $this->m_sOrganizationName = $aCompanies[$index]['name'];
$this->m_OrganizationDomains = $aCompanies[$index]['domain']; $this->m_OrganizationDomains = $aCompanies[$index]['domain'];
} }
$retries--; $retries--;
} }
} } else {
else
{
// A code has been provided, let's take the information we need from the organization itself // A code has been provided, let's take the information we need from the organization itself
$this->m_sOrganizationId = $sOrganizationId; $this->m_sOrganizationId = $sOrganizationId;
$oOrg = $this->GetOrganization($sOrganizationId); $oOrg = $this->GetOrganization($sOrganizationId);
if ($oOrg == null) if ($oOrg == null) {
{
echo "Unable to find the organization '$sOrganisationCode' in the database... can not add objects into this organization.<br/>\n"; echo "Unable to find the organization '$sOrganisationCode' in the database... can not add objects into this organization.<br/>\n";
exit(); exit();
} }
$this->m_sOrganizationCode = $oOrg->Get('code'); $this->m_sOrganizationCode = $oOrg->Get('code');
$this->m_sOrganizationName = $oOrg->Get('name'); $this->m_sOrganizationName = $oOrg->Get('name');
if (!isset($aCompaniesCode[$this->m_sOrganizationCode]['domain'])) if (!isset($aCompaniesCode[$this->m_sOrganizationCode]['domain'])) {
{
// Generate some probable domain names for this organization // Generate some probable domain names for this organization
$this->m_OrganizationDomains = array(strtolower($this->m_sOrganizationCode).".com", strtolower($this->m_sOrganizationCode).".org", strtolower($this->m_sOrganizationCode)."corp.net",); $this->m_OrganizationDomains = [strtolower($this->m_sOrganizationCode).".com", strtolower($this->m_sOrganizationCode).".org", strtolower($this->m_sOrganizationCode)."corp.net",];
} } else {
else
{
// Pick the domain names for this organization from the predefined list // Pick the domain names for this organization from the predefined list
$this->m_OrganizationDomains = $aCompaniesCode[$this->m_sOrganizationCode]['domain']; $this->m_OrganizationDomains = $aCompaniesCode[$this->m_sOrganizationCode]['domain'];
} }
} }
if (!isset($this->m_sOrganizationCode)) if (!isset($this->m_sOrganizationCode)) {
{
echo "Unable to find an organization code which is not already used... can not create a new organization. Enhance the list of fake organizations (\$aCompanies in data_sample.inc.php).<br/>\n"; echo "Unable to find an organization code which is not already used... can not create a new organization. Enhance the list of fake organizations (\$aCompanies in data_sample.inc.php).<br/>\n";
exit(); exit();
} }
} }
/** /**
* Get the current organization id used by the generator * Get the current organization id used by the generator
* *
@@ -100,7 +90,7 @@ class cmdbDataGenerator
{ {
return $this->m_sOrganizationId; return $this->m_sOrganizationId;
} }
/** /**
* Get the current organization id used by the generator * Get the current organization id used by the generator
* *
@@ -111,7 +101,7 @@ class cmdbDataGenerator
{ {
$this->m_sOrganizationId = $sId; $this->m_sOrganizationId = $sId;
} }
/** /**
* Get the current organization code used by the generator * Get the current organization code used by the generator
* *
@@ -127,69 +117,66 @@ class cmdbDataGenerator
* *
* @return string The organization name * @return string The organization name
*/ */
function GetOrganizationName() public function GetOrganizationName()
{ {
return $this->m_sOrganizationName; return $this->m_sOrganizationName;
} }
/** /**
* Get a pseudo random first name taken from a (big) prefedined list * Get a pseudo random first name taken from a (big) prefedined list
* *
* @return string A random first name * @return string A random first name
*/ */
function GenerateFirstName() public function GenerateFirstName()
{ {
global $aFirstNames; global $aFirstNames;
return $aFirstNames[rand(0, count($aFirstNames) - 1)]; return $aFirstNames[rand(0, count($aFirstNames) - 1)];
} }
/** /**
* Get a pseudo random last name taken from a (big) prefedined list * Get a pseudo random last name taken from a (big) prefedined list
* *
* @return string A random last name * @return string A random last name
*/ */
function GenerateLastName() public function GenerateLastName()
{ {
global $aNames; global $aNames;
return $aNames[rand(0, count($aNames) - 1)]; return $aNames[rand(0, count($aNames) - 1)];
} }
/** /**
* Get a pseudo random country name taken from a prefedined list * Get a pseudo random country name taken from a prefedined list
* *
* @return string A random city name * @return string A random city name
*/ */
function GenerateCountryName() public function GenerateCountryName()
{ {
global $aCountries; global $aCountries;
return $aCountries[rand(0, count($aCountries) - 1)]; return $aCountries[rand(0, count($aCountries) - 1)];
} }
/** /**
* Get a pseudo random city name taken from a (big) prefedined list * Get a pseudo random city name taken from a (big) prefedined list
* *
* @return string A random city name * @return string A random city name
*/ */
function GenerateCityName() public function GenerateCityName()
{ {
global $aCities; global $aCities;
return $aCities[rand(0, count($aCities) - 1)]; return $aCities[rand(0, count($aCities) - 1)];
} }
/** /**
* Get a pseudo random email address made of the first name, last name and organization's domain * Get a pseudo random email address made of the first name, last name and organization's domain
* *
* @return string A random email address * @return string A random email address
*/ */
function GenerateEmail($sFirstName, $sLastName) public function GenerateEmail($sFirstName, $sLastName)
{ {
if (rand(1, 20) > 18) if (rand(1, 20) > 18) {
{
// some people (let's say 5~10%) have an irregular email address // some people (let's say 5~10%) have an irregular email address
$sEmail = strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain()); $sEmail = strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain());
} } else {
else
{
$sEmail = strtolower($this->CleanForEmail($sFirstName)).".".strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain()); $sEmail = strtolower($this->CleanForEmail($sFirstName)).".".strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain());
} }
return $sEmail; return $sEmail;
@@ -203,7 +190,7 @@ class cmdbDataGenerator
* - domain() => returns a domain name for the current organization * - domain() => returns a domain name for the current organization
* - enum(aaa,bb,c,dddd) => returns randomly one of aaa,bb,c or dddd with the same * - enum(aaa,bb,c,dddd) => returns randomly one of aaa,bb,c or dddd with the same
* probability of occurence. If you want to change the probability you can repeat some values * probability of occurence. If you want to change the probability you can repeat some values
* i.e enum(most probable,most probable,most probable,most probable,most probable,rare) * i.e enum(most probable,most probable,most probable,most probable,most probable,rare)
* - number(xxx-yyy) => a random number between xxx and yyy (bounds included) * - number(xxx-yyy) => a random number between xxx and yyy (bounds included)
* note that if the first number (xxx) begins with a zero, then the result will zero padded * note that if the first number (xxx) begins with a zero, then the result will zero padded
* to the same number of digits as xxx. * to the same number of digits as xxx.
@@ -215,39 +202,28 @@ class cmdbDataGenerator
* @param string $sTemplate The template used for generating the string * @param string $sTemplate The template used for generating the string
* @return string The generated pseudo random the string * @return string The generated pseudo random the string
*/ */
function GenerateString($sTemplate) public function GenerateString($sTemplate)
{ {
$sResult = ""; $sResult = "";
$aParts = explode("\|", $sTemplate); $aParts = explode("\|", $sTemplate);
foreach($aParts as $sPart) foreach ($aParts as $sPart) {
{ if (preg_match("/domain\(\)/", $sPart, $aMatches)) {
if (preg_match("/domain\(\)/", $sPart, $aMatches))
{
$sResult .= strtolower($this->GenerateDomain()); $sResult .= strtolower($this->GenerateDomain());
} } elseif (preg_match("/enum\((.+)\)/", $sPart, $aMatches)) {
elseif (preg_match("/enum\((.+)\)/", $sPart, $aMatches))
{
$sEnumValues = $aMatches[1]; $sEnumValues = $aMatches[1];
$aEnumValues = explode(",", $sEnumValues); $aEnumValues = explode(",", $sEnumValues);
$sResult .= $aEnumValues[rand(0, count($aEnumValues) - 1)]; $sResult .= $aEnumValues[rand(0, count($aEnumValues) - 1)];
} } elseif (preg_match("/number\((\d+)-(\d+)\)/", $sPart, $aMatches)) {
elseif (preg_match("/number\((\d+)-(\d+)\)/", $sPart, $aMatches))
{
$sStartNumber = $aMatches[1]; $sStartNumber = $aMatches[1];
if ($sStartNumber[0] == '0') if ($sStartNumber[0] == '0') {
{
// number must be zero padded // number must be zero padded
$sFormat = "%0".strlen($sStartNumber)."d"; $sFormat = "%0".strlen($sStartNumber)."d";
} } else {
else
{
$sFormat = "%d"; $sFormat = "%d";
} }
$sEndNumber = $aMatches[2]; $sEndNumber = $aMatches[2];
$sResult .= sprintf($sFormat, rand($sStartNumber, $sEndNumber)); $sResult .= sprintf($sFormat, rand($sStartNumber, $sEndNumber));
} } else {
else
{
$sResult .= $sPart; $sResult .= $sPart;
} }
} }
@@ -264,27 +240,22 @@ class cmdbDataGenerator
* @param string $aFilterCriteria A hash array of filterCOde => FilterValue (the strict operator '=' is used ) * @param string $aFilterCriteria A hash array of filterCOde => FilterValue (the strict operator '=' is used )
* @return mixed The key to an object of the given class, or null if none are found * @return mixed The key to an object of the given class, or null if none are found
*/ */
function GenerateKey($sClass, $aFilterCriteria) public function GenerateKey($sClass, $aFilterCriteria)
{ {
$retKey = null; $retKey = null;
$oFilter = new DBObjectSearch($sClass); $oFilter = new DBObjectSearch($sClass);
foreach($aFilterCriteria as $sFilterCode => $filterValue) foreach ($aFilterCriteria as $sFilterCode => $filterValue) {
{
$oFilter->AddCondition($sFilterCode, $filterValue, '='); $oFilter->AddCondition($sFilterCode, $filterValue, '=');
} }
$oSet = new CMDBObjectSet($oFilter); $oSet = new CMDBObjectSet($oFilter);
if ($oSet->Count() > 0) if ($oSet->Count() > 0) {
{
$max_count = $index = rand(1, $oSet->Count()); $max_count = $index = rand(1, $oSet->Count());
do do {
{
$oObj = $oSet->Fetch(); $oObj = $oSet->Fetch();
$index--; $index--;
} } while ($index > 0);
while($index > 0);
if (!is_object($oObj)) {
if (!is_object($oObj))
{
echo "<pre>"; echo "<pre>";
echo "ERROR: non empty set, but invalid object picked! class='$sClass'\n"; echo "ERROR: non empty set, but invalid object picked! class='$sClass'\n";
echo "Index chosen: $max_count\n"; echo "Index chosen: $max_count\n";
@@ -292,9 +263,7 @@ class cmdbDataGenerator
echo "Filter criteria:\n"; echo "Filter criteria:\n";
print_r($aFilterCriteria); print_r($aFilterCriteria);
echo "</pre>"; echo "</pre>";
} } else {
else
{
$retKey = $oObj->GetKey(); $retKey = $oObj->GetKey();
} }
} }
@@ -305,7 +274,7 @@ class cmdbDataGenerator
// Protected methods // Protected methods
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/** /**
* Generate a (random) domain name consistent with the organization name & code * Generate a (random) domain name consistent with the organization name & code
* *
@@ -316,17 +285,14 @@ class cmdbDataGenerator
*/ */
protected function GenerateDomain() protected function GenerateDomain()
{ {
if (is_array($this->m_OrganizationDomains)) if (is_array($this->m_OrganizationDomains)) {
{ $sDomain = $this->m_OrganizationDomains[rand(0, count($this->m_OrganizationDomains) - 1)];
$sDomain = $this->m_OrganizationDomains[rand(0, count($this->m_OrganizationDomains)-1)]; } else {
}
else
{
$sDomain = $this->m_OrganizationDomains; $sDomain = $this->m_OrganizationDomains;
} }
return $sDomain; return $sDomain;
} }
/** /**
* Strips accented characters from a string in order to produce a suitable email address * Strips accented characters from a string in order to produce a suitable email address
* *
@@ -335,7 +301,7 @@ class cmdbDataGenerator
*/ */
protected function CleanForEmail($sText) protected function CleanForEmail($sText)
{ {
return str_replace(array("'", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>"), array("", "e", "e", "e", "c", "a", "a", "n", "oe", "ae"), $sText); return str_replace(["'", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>", "<EFBFBD>"], ["", "e", "e", "e", "c", "a", "a", "n", "oe", "ae"], $sText);
} }
/** /**
@@ -364,11 +330,9 @@ class cmdbDataGenerator
$oFilter = new DBObjectSearch('Organization'); $oFilter = new DBObjectSearch('Organization');
$oFilter->AddCondition('id', $sId, '='); $oFilter->AddCondition('id', $sId, '=');
$oSet = new CMDBObjectSet($oFilter); $oSet = new CMDBObjectSet($oFilter);
if ($oSet->Count() > 0) if ($oSet->Count() > 0) {
{
$oOrg = $oSet->Fetch(); // Let's take the first one found $oOrg = $oSet->Fetch(); // Let's take the first one found
} }
return $oOrg; return $oOrg;
} }
} }
?>

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2024 Combodo SAS // Copyright (C) 2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,24 +17,23 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Helper class to generate Date & Time formatting strings in the various conventions * Helper class to generate Date & Time formatting strings in the various conventions
* from the PHP DateTime::createFromFormat convention. * from the PHP DateTime::createFromFormat convention.
* *
* Example: * Example:
* *
* $oFormat = new DateTimeFormat('m/d/Y H:i'); * $oFormat = new DateTimeFormat('m/d/Y H:i');
* $oFormat->ToExcel(); * $oFormat->ToExcel();
* >> 'MM/dd/YYYY HH:mm' * >> 'MM/dd/YYYY HH:mm'
* *
* @author Denis Flaven <denis.flaven@combodo.com> * @author Denis Flaven <denis.flaven@combodo.com>
* *
*/ */
class DateTimeFormat class DateTimeFormat
{ {
protected $sPHPFormat; protected $sPHPFormat;
/** /**
* Constructs the DateTimeFormat object * Constructs the DateTimeFormat object
* @param string $sPHPFormat A format string using the PHP 'DateTime::createFromFormat' convention * @param string $sPHPFormat A format string using the PHP 'DateTime::createFromFormat' convention
@@ -42,7 +42,7 @@ class DateTimeFormat
{ {
$this->sPHPFormat = (string)$sPHPFormat; $this->sPHPFormat = (string)$sPHPFormat;
} }
/** /**
* @return string * @return string
*/ */
@@ -50,34 +50,34 @@ class DateTimeFormat
{ {
return $this->sPHPFormat; return $this->sPHPFormat;
} }
/** /**
* Return the mapping table for converting between various conventions for date/time formats * Return the mapping table for converting between various conventions for date/time formats
*/ */
protected static function GetFormatMapping() protected static function GetFormatMapping()
{ {
return array( return [
// Days // Days
'd' => array('regexpr' => '(0[1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'dd', 'excel' => 'dd', 'moment' => 'DD'), // Day of the month: 2 digits (with leading zero) 'd' => ['regexpr' => '(0[1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'dd', 'excel' => 'dd', 'moment' => 'DD'], // Day of the month: 2 digits (with leading zero)
'j' => array('regexpr' => '([1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'd', 'excel' => 'd', 'moment' => 'D'), // Day of the month: 1 or 2 digits (without leading zero) 'j' => ['regexpr' => '([1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'd', 'excel' => 'd', 'moment' => 'D'], // Day of the month: 1 or 2 digits (without leading zero)
// Months // Months
'm' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'mm', 'excel' => 'MM', 'moment' => 'MM' ), // Month on 2 digits i.e. 01-12 'm' => ['regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'mm', 'excel' => 'MM', 'moment' => 'MM' ], // Month on 2 digits i.e. 01-12
'n' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'm', 'excel' => 'm', 'moment' => 'M'), // Month on 1 or 2 digits 1-12 'n' => ['regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'm', 'excel' => 'm', 'moment' => 'M'], // Month on 1 or 2 digits 1-12
// Years // Years
'Y' => array('regexpr' => '([0-9]{4})', 'datepicker' => 'yy', 'excel' => 'YYYY', 'moment' => 'YYYY'), // Year on 4 digits 'Y' => ['regexpr' => '([0-9]{4})', 'datepicker' => 'yy', 'excel' => 'YYYY', 'moment' => 'YYYY'], // Year on 4 digits
'y' => array('regexpr' => '([0-9]{2})', 'datepicker' => 'y', 'excel' => 'YY', 'moment' => 'YY'), // Year on 2 digits 'y' => ['regexpr' => '([0-9]{2})', 'datepicker' => 'y', 'excel' => 'YY', 'moment' => 'YY'], // Year on 2 digits
// Hours // Hours
'H' => array('regexpr' => '([0-1][0-9]|2[0-3])', 'datepicker' => 'HH', 'excel' => 'HH', 'moment' => 'HH'), // Hour 00..23 'H' => ['regexpr' => '([0-1][0-9]|2[0-3])', 'datepicker' => 'HH', 'excel' => 'HH', 'moment' => 'HH'], // Hour 00..23
'h' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'hh', 'excel' => 'hh', 'moment' => 'hh'), // Hour 01..12 'h' => ['regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'hh', 'excel' => 'hh', 'moment' => 'hh'], // Hour 01..12
'G' => array('regexpr' => '([0-9]|1[0-9]|2[0-3])', 'datepicker' => 'H', 'excel' => 'H', 'moment' => 'H'), // Hour 0..23 'G' => ['regexpr' => '([0-9]|1[0-9]|2[0-3])', 'datepicker' => 'H', 'excel' => 'H', 'moment' => 'H'], // Hour 0..23
'g' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'h', 'excel' => 'h', 'moment' => 'h'), // Hour 1..12 'g' => ['regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'h', 'excel' => 'h', 'moment' => 'h'], // Hour 1..12
'a' => array('regexpr' => '(am|pm)', 'datepicker' => 'tt', 'excel' => 'am/pm', 'moment' => 'a'), 'a' => ['regexpr' => '(am|pm)', 'datepicker' => 'tt', 'excel' => 'am/pm', 'moment' => 'a'],
'A' => array('regexpr' => '(AM|PM)', 'datepicker' => 'TT', 'excel' => 'AM/PM', 'moment' => 'A'), 'A' => ['regexpr' => '(AM|PM)', 'datepicker' => 'TT', 'excel' => 'AM/PM', 'moment' => 'A'],
// Minutes // Minutes
'i' => array('regexpr' => '([0-5][0-9])', 'datepicker' => 'mm', 'excel' => 'mm', 'moment' => 'mm'), 'i' => ['regexpr' => '([0-5][0-9])', 'datepicker' => 'mm', 'excel' => 'mm', 'moment' => 'mm'],
// Seconds // Seconds
's' => array('regexpr' => '([0-5][0-9])', 'datepicker' => 'ss', 'excel' => 'ss', 'moment' => 'ss'), 's' => ['regexpr' => '([0-5][0-9])', 'datepicker' => 'ss', 'excel' => 'ss', 'moment' => 'ss'],
); ];
} }
/** /**
@@ -87,57 +87,44 @@ class DateTimeFormat
* @param string $sEscapePattern The replacement string for escaping characters in the output string. %s is the source char. * @param string $sEscapePattern The replacement string for escaping characters in the output string. %s is the source char.
* @param string $bEscapeAll True to systematically escape all litteral characters * @param string $bEscapeAll True to systematically escape all litteral characters
* @param array $sSpecialChars A string containing the only characters to escape in the output * @param array $sSpecialChars A string containing the only characters to escape in the output
* @return string The string in the requested format * @return string The string in the requested format
*/ */
protected function Transform($sOutputFormatCode, $sEscapePattern, $bEscapeAll = false, $sSpecialChars = '') protected function Transform($sOutputFormatCode, $sEscapePattern, $bEscapeAll = false, $sSpecialChars = '')
{ {
$aMappings = static::GetFormatMapping(); $aMappings = static::GetFormatMapping();
$sResult = ''; $sResult = '';
$bEscaping = false; $bEscaping = false;
for($i=0; $i < strlen($this->sPHPFormat); $i++) for ($i = 0; $i < strlen($this->sPHPFormat); $i++) {
{ if (($this->sPHPFormat[$i] == '\\')) {
if (($this->sPHPFormat[$i] == '\\'))
{
$bEscaping = true; $bEscaping = true;
continue; continue;
} }
if ($bEscaping) if ($bEscaping) {
{ if (($sSpecialChars === '') || (strpos($sSpecialChars, $this->sPHPFormat[$i]) !== false)) {
if (($sSpecialChars === '') || (strpos($sSpecialChars, $this->sPHPFormat[$i]) !== false))
{
$sResult .= sprintf($sEscapePattern, $this->sPHPFormat[$i]); $sResult .= sprintf($sEscapePattern, $this->sPHPFormat[$i]);
} } else {
else
{
$sResult .= $this->sPHPFormat[$i]; $sResult .= $this->sPHPFormat[$i];
} }
$bEscaping = false; $bEscaping = false;
} } elseif (array_key_exists($this->sPHPFormat[$i], $aMappings)) {
else if(array_key_exists($this->sPHPFormat[$i], $aMappings))
{
// Not a litteral value, must be replaced by its regular expression pattern // Not a litteral value, must be replaced by its regular expression pattern
$sResult .= $aMappings[$this->sPHPFormat[$i]][$sOutputFormatCode]; $sResult .= $aMappings[$this->sPHPFormat[$i]][$sOutputFormatCode];
} } else {
else if ($bEscapeAll || (strpos($sSpecialChars, $this->sPHPFormat[$i]) !== false)) {
{
if ($bEscapeAll || (strpos($sSpecialChars, $this->sPHPFormat[$i]) !== false))
{
$sResult .= sprintf($sEscapePattern, $this->sPHPFormat[$i]); $sResult .= sprintf($sEscapePattern, $this->sPHPFormat[$i]);
} } else {
else
{
// Normal char with no special meaning, no need to escape it // Normal char with no special meaning, no need to escape it
$sResult .= $this->sPHPFormat[$i]; $sResult .= $this->sPHPFormat[$i];
} }
} }
} }
return $sResult; return $sResult;
} }
/** /**
* Format a date into the supplied format string * Format a date into the supplied format string
* @param mixed $date An int, string, DateTime object or null !! * @param mixed $date An int, string, DateTime object or null !!
@@ -146,38 +133,27 @@ class DateTimeFormat
*/ */
public function Format($date) public function Format($date)
{ {
if ($date == null) if ($date == null) {
{
$sDate = ''; $sDate = '';
} } elseif (($date === '0000-00-00') || ($date === '0000-00-00 00:00:00')) {
else if (($date === '0000-00-00') || ($date === '0000-00-00 00:00:00'))
{
$sDate = ''; $sDate = '';
} } elseif ($date instanceof DateTime) {
else if ($date instanceof DateTime)
{
// Parameter is a DateTime // Parameter is a DateTime
$sDate = $date->format($this->sPHPFormat); $sDate = $date->format($this->sPHPFormat);
} } elseif (is_int($date)) {
else if (is_int($date))
{
// Parameter is a Unix timestamp // Parameter is a Unix timestamp
$oDate = new DateTime(); $oDate = new DateTime();
$oDate->setTimestamp($date); $oDate->setTimestamp($date);
$sDate = $oDate->format($this->sPHPFormat); $sDate = $oDate->format($this->sPHPFormat);
} } elseif (is_string($date)) {
else if (is_string($date))
{
$oDate = new DateTime($date); $oDate = new DateTime($date);
$sDate = $oDate->format($this->sPHPFormat); $sDate = $oDate->format($this->sPHPFormat);
} } else {
else
{
throw new Exception(__CLASS__."::Format: Unexpected date value: ".print_r($date, true)); throw new Exception(__CLASS__."::Format: Unexpected date value: ".print_r($date, true));
} }
return $sDate; return $sDate;
} }
/** /**
* Parse a date in the supplied format and return the date as a string in the internal format * Parse a date in the supplied format and return the date as a string in the internal format
* @param string $sDate The string to parse * @param string $sDate The string to parse
@@ -187,22 +163,18 @@ class DateTimeFormat
*/ */
public function Parse($sDate) public function Parse($sDate)
{ {
if (($sDate == null) || ($sDate == '0000-00-00 00:00:00') || ($sDate == '0000-00-00')) if (($sDate == null) || ($sDate == '0000-00-00 00:00:00') || ($sDate == '0000-00-00')) {
{ return null;
return null; } else {
}
else
{
$sFormat = preg_replace('/\\?/', '', $this->sPHPFormat); // replace escaped characters by a wildcard for parsing $sFormat = preg_replace('/\\?/', '', $this->sPHPFormat); // replace escaped characters by a wildcard for parsing
$oDate = DateTime::createFromFormat($this->sPHPFormat, $sDate); $oDate = DateTime::createFromFormat($this->sPHPFormat, $sDate);
if ($oDate === false) if ($oDate === false) {
{
throw new Exception(__CLASS__."::Parse: Unable to parse the date: '$sDate' using the format: '{$this->sPHPFormat}'"); throw new Exception(__CLASS__."::Parse: Unable to parse the date: '$sDate' using the format: '{$this->sPHPFormat}'");
} }
return $oDate; return $oDate;
} }
} }
/** /**
* Get the date or datetime format string in the jQuery UI date picker format * Get the date or datetime format string in the jQuery UI date picker format
* @return string The format string using the date picker convention * @return string The format string using the date picker convention
@@ -211,7 +183,7 @@ class DateTimeFormat
{ {
return $this->Transform('datepicker', "'%s'"); return $this->Transform('datepicker', "'%s'");
} }
/** /**
* Get a date or datetime format string in the Excel format * Get a date or datetime format string in the Excel format
* @return string The format string using the Excel convention * @return string The format string using the Excel convention
@@ -220,7 +192,7 @@ class DateTimeFormat
{ {
return $this->Transform('excel', "%s"); return $this->Transform('excel', "%s");
} }
/** /**
* Get a date or datetime format string in the moment.js format * Get a date or datetime format string in the moment.js format
* @return string The format string using the moment.js convention * @return string The format string using the moment.js convention
@@ -229,16 +201,15 @@ class DateTimeFormat
{ {
return $this->Transform('moment', "[%s]", true /* escape all */); return $this->Transform('moment', "[%s]", true /* escape all */);
} }
public static function GetJSSQLToCustomFormat() public static function GetJSSQLToCustomFormat()
{ {
$aPHPToMoment = array(); $aPHPToMoment = [];
foreach(self::GetFormatMapping() as $sPHPCode => $aMapping) foreach (self::GetFormatMapping() as $sPHPCode => $aMapping) {
{
$aPHPToMoment[$sPHPCode] = $aMapping['moment']; $aPHPToMoment[$sPHPCode] = $aMapping['moment'];
} }
$sJSMapping = json_encode($aPHPToMoment); $sJSMapping = json_encode($aPHPToMoment);
$sFunction = $sFunction =
<<<EOF <<<EOF
function PHPDateTimeFormatToSubFormat(sPHPFormat, sPlaceholders) function PHPDateTimeFormatToSubFormat(sPHPFormat, sPlaceholders)
@@ -325,7 +296,7 @@ EOF
; ;
return $sFunction; return $sFunction;
} }
/** /**
* Get a placeholder text for a date or datetime format string * Get a placeholder text for a date or datetime format string
* @return string The placeholder text (localized) * @return string The placeholder text (localized)
@@ -334,34 +305,27 @@ EOF
{ {
$aMappings = static::GetFormatMapping(); $aMappings = static::GetFormatMapping();
$sResult = ''; $sResult = '';
$bEscaping = false; $bEscaping = false;
for($i=0; $i < strlen($this->sPHPFormat); $i++) for ($i = 0; $i < strlen($this->sPHPFormat); $i++) {
{ if (($this->sPHPFormat[$i] == '\\')) {
if (($this->sPHPFormat[$i] == '\\'))
{
$bEscaping = true; $bEscaping = true;
continue; continue;
} }
if ($bEscaping) if ($bEscaping) {
{
$sResult .= $this->sPHPFormat[$i]; // No need to escape characters in the placeholder $sResult .= $this->sPHPFormat[$i]; // No need to escape characters in the placeholder
$bEscaping = false; $bEscaping = false;
} } elseif (array_key_exists($this->sPHPFormat[$i], $aMappings)) {
else if(array_key_exists($this->sPHPFormat[$i], $aMappings))
{
// Not a litteral value, must be replaced by Dict equivalent // Not a litteral value, must be replaced by Dict equivalent
$sResult .= Dict::S('Core:DateTime:Placeholder_'.$this->sPHPFormat[$i]); $sResult .= Dict::S('Core:DateTime:Placeholder_'.$this->sPHPFormat[$i]);
} } else {
else
{
// Normal char with no special meaning // Normal char with no special meaning
$sResult .= $this->sPHPFormat[$i]; $sResult .= $this->sPHPFormat[$i];
} }
} }
return $sResult; return $sResult;
} }
@@ -373,14 +337,11 @@ EOF
{ {
$iStart = 999; $iStart = 999;
$iEnd = 0; $iEnd = 0;
foreach($aPlaceholders as $sChar) foreach ($aPlaceholders as $sChar) {
{
$iPos = strpos($this->sPHPFormat, $sChar); $iPos = strpos($this->sPHPFormat, $sChar);
if ($iPos !== false) if ($iPos !== false) {
{ if (($iPos > 0) && ($this->sPHPFormat[$iPos - 1] == '\\')) {
if (($iPos > 0) && ($this->sPHPFormat[$iPos-1] == '\\'))
{
// The placeholder is actually escaped, it's a litteral character, ignore it // The placeholder is actually escaped, it's a litteral character, ignore it
continue; continue;
} }
@@ -391,25 +352,25 @@ EOF
$sFormat = substr($this->sPHPFormat, $iStart, $iEnd - $iStart + 1); $sFormat = substr($this->sPHPFormat, $iStart, $iEnd - $iStart + 1);
return $sFormat; return $sFormat;
} }
/** /**
* Produces the Date format string by extracting only the date part of the date and time format string * Produces the Date format string by extracting only the date part of the date and time format string
* @return string * @return string
*/ */
public function ToDateFormat() public function ToDateFormat()
{ {
return $this->ToSubFormat(array('Y', 'y', 'd', 'j', 'm', 'n')); return $this->ToSubFormat(['Y', 'y', 'd', 'j', 'm', 'n']);
} }
/** /**
* Produces the Time format string by extracting only the time part of the date and time format string * Produces the Time format string by extracting only the time part of the date and time format string
* @return string * @return string
*/ */
public function ToTimeFormat() public function ToTimeFormat()
{ {
return $this->ToSubFormat(array('H', 'h', 'G', 'g', 'i', 's', 'a', 'A')); return $this->ToSubFormat(['H', 'h', 'G', 'g', 'i', 's', 'a', 'A']);
} }
/** /**
* Get the regular expression to (approximately) validate a date/time for the current format * Get the regular expression to (approximately) validate a date/time for the current format
* The validation does not take into account the number of days in a month (i.e. June 31st will pass, as well as Feb 30th!) * The validation does not take into account the number of days in a month (i.e. June 31st will pass, as well as Feb 30th!)
@@ -419,8 +380,7 @@ EOF
public function ToRegExpr($sDelimiter = null) public function ToRegExpr($sDelimiter = null)
{ {
$sRet = '^'.$this->Transform('regexpr', "\\%s", false /* escape all */, '.?*$^()[]:').'$'; $sRet = '^'.$this->Transform('regexpr', "\\%s", false /* escape all */, '.?*$^()[]:').'$';
if ($sDelimiter !== null) if ($sDelimiter !== null) {
{
$sRet = $sDelimiter.str_replace($sDelimiter, '\\'.$sDelimiter, $sRet).$sDelimiter; $sRet = $sDelimiter.str_replace($sDelimiter, '\\'.$sDelimiter, $sRet).$sDelimiter;
} }
return $sRet; return $sRet;

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,9 +17,8 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* A set of persistent objects, could be heterogeneous as long as the objects in the set have a common ancestor class * A set of persistent objects, could be heterogeneous as long as the objects in the set have a common ancestor class
* *
* @package iTopORM * @package iTopORM
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Database properties - manage database instances in a complex installation * Database properties - manage database instances in a complex installation
* *
@@ -24,9 +24,8 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
/** /**
* A database property * A database property
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -34,40 +33,37 @@ class DBProperty extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams =
( [
"category" => "cloud", "category" => "cloud",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => [],
"db_table" => "priv_db_properties", "db_table" => "priv_db_properties",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); ];
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>"value", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("value", ["allowed_values" => null, "sql" => "value", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", array("allowed_values"=>null, "sql"=>"change_date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", ["allowed_values" => null, "sql" => "change_date", "default_value" => "NOW()", "is_null_allowed" => false, "depends_on" => []]));
MetaModel::Init_AddAttribute(new AttributeString("change_comment", array("allowed_values"=>null, "sql"=>"change_comment", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("change_comment", ["allowed_values" => null, "sql" => "change_comment", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
} }
/** /**
* Helper to check wether the table has been created into the DB * Helper to check wether the table has been created into the DB
* (this table did not exist in 1.0.1 and older versions) * (this table did not exist in 1.0.1 and older versions)
*/ */
public static function IsInstalled() public static function IsInstalled()
{ {
$sTable = MetaModel::DBGetTable(__CLASS__); $sTable = MetaModel::DBGetTable(__CLASS__);
if (CMDBSource::IsTable($sTable)) if (CMDBSource::IsTable($sTable)) {
{
return true; return true;
} } else {
else
{
return false; return false;
} }
return false; return false;
@@ -75,12 +71,10 @@ class DBProperty extends DBObject
public static function SetProperty($sName, $sValue, $sComment = '', $sDescription = null) public static function SetProperty($sName, $sValue, $sComment = '', $sDescription = null)
{ {
try try {
{
$oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name'); $oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name');
$oSet = new DBObjectSet($oSearch, array(), array('name' => $sName)); $oSet = new DBObjectSet($oSearch, [], ['name' => $sName]);
if ($oSet->Count() == 0) if ($oSet->Count() == 0) {
{
$oProp = new DBProperty(); $oProp = new DBProperty();
$oProp->Set('name', $sName); $oProp->Set('name', $sName);
$oProp->Set('description', $sDescription); $oProp->Set('description', $sDescription);
@@ -88,31 +82,23 @@ class DBProperty extends DBObject
$oProp->Set('change_date', time()); $oProp->Set('change_date', time());
$oProp->Set('change_comment', $sComment); $oProp->Set('change_comment', $sComment);
$oProp->DBInsert(); $oProp->DBInsert();
} } elseif ($oSet->Count() == 1) {
elseif ($oSet->Count() == 1)
{
$oProp = $oSet->fetch(); $oProp = $oSet->fetch();
if (!is_null($sDescription)) if (!is_null($sDescription)) {
{
$oProp->Set('description', $sDescription); $oProp->Set('description', $sDescription);
} }
$oProp->Set('value', $sValue); $oProp->Set('value', $sValue);
$oProp->Set('change_date', time()); $oProp->Set('change_date', time());
$oProp->Set('change_comment', $sComment); $oProp->Set('change_comment', $sComment);
$oProp->DBUpdate(); $oProp->DBUpdate();
} } else {
else
{
// Houston... // Houston...
throw new CoreException('duplicate db property'); throw new CoreException('duplicate db property');
} }
} } catch (MySQLException $e) {
catch (MySQLException $e)
{
// This might be because the table could not be found, // This might be because the table could not be found,
// let's check it and discard silently if this is really the case // let's check it and discard silently if this is really the case
if (self::IsInstalled()) if (self::IsInstalled()) {
{
throw $e; throw $e;
} }
IssueLog::Error('Attempting to write a DBProperty while the module has not been installed'); IssueLog::Error('Attempting to write a DBProperty while the module has not been installed');
@@ -121,34 +107,25 @@ class DBProperty extends DBObject
public static function GetProperty($sName, $default = null) public static function GetProperty($sName, $default = null)
{ {
try try {
{
$oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name'); $oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name');
$oSet = new DBObjectSet($oSearch, array(), array('name' => $sName)); $oSet = new DBObjectSet($oSearch, [], ['name' => $sName]);
$iCount = $oSet->Count(); $iCount = $oSet->Count();
if ($iCount == 0) if ($iCount == 0) {
{
//throw new CoreException('unknown db property', array('name' => $sName)); //throw new CoreException('unknown db property', array('name' => $sName));
$sValue = $default; $sValue = $default;
} } elseif ($iCount == 1) {
elseif ($iCount == 1)
{
$oProp = $oSet->fetch(); $oProp = $oSet->fetch();
$sValue = $oProp->Get('value'); $sValue = $oProp->Get('value');
} } else {
else
{
// $iCount > 1 // $iCount > 1
// Houston... // Houston...
throw new CoreException('duplicate db property', array('name' => $sName, 'count' => $iCount)); throw new CoreException('duplicate db property', ['name' => $sName, 'count' => $iCount]);
} }
} } catch (MySQLException $e) {
catch (MySQLException $e)
{
// This might be because the table could not be found, // This might be because the table could not be found,
// let's check it and discard silently if this is really the case // let's check it and discard silently if this is really the case
if (self::IsInstalled()) if (self::IsInstalled()) {
{
throw $e; throw $e;
} }
$sValue = $default; $sValue = $default;
@@ -156,5 +133,3 @@ class DBProperty extends DBObject
return $sValue; return $sValue;
} }
} }
?>

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,7 +10,7 @@
*/ */
/** /**
* Deletion plan (other objects to be deleted/modified, eventual issues, etc.) * Deletion plan (other objects to be deleted/modified, eventual issues, etc.)
* *
* @package iTopORM * @package iTopORM
*/ */
@@ -25,34 +26,34 @@ class DeletionPlan
protected $m_iToDelete; protected $m_iToDelete;
protected $m_iToUpdate; protected $m_iToUpdate;
protected $m_aToDelete; protected $m_aToDelete;
protected $m_aToUpdate; protected $m_aToUpdate;
protected static $m_aModeUpdate = array( protected static $m_aModeUpdate = [
DEL_SILENT => array( DEL_SILENT => [
DEL_SILENT => DEL_SILENT, DEL_SILENT => DEL_SILENT,
DEL_AUTO => DEL_AUTO, DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL DEL_MANUAL => DEL_MANUAL,
), ],
DEL_MANUAL => array( DEL_MANUAL => [
DEL_SILENT => DEL_MANUAL, DEL_SILENT => DEL_MANUAL,
DEL_AUTO => DEL_AUTO, DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL DEL_MANUAL => DEL_MANUAL,
), ],
DEL_AUTO => array( DEL_AUTO => [
DEL_SILENT => DEL_AUTO, DEL_SILENT => DEL_AUTO,
DEL_AUTO => DEL_AUTO, DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_AUTO DEL_MANUAL => DEL_AUTO,
) ],
); ];
public function __construct() public function __construct()
{ {
$this->m_iToDelete = 0; $this->m_iToDelete = 0;
$this->m_iToUpdate = 0; $this->m_iToUpdate = 0;
$this->m_aToDelete = array(); $this->m_aToDelete = [];
$this->m_aToUpdate = array(); $this->m_aToUpdate = [];
$this->m_bFoundStopper = false; $this->m_bFoundStopper = false;
$this->m_bFoundSecurityIssue = false; $this->m_bFoundSecurityIssue = false;
@@ -65,22 +66,17 @@ class DeletionPlan
$this->m_iToDelete = 0; $this->m_iToDelete = 0;
$this->m_iToUpdate = 0; $this->m_iToUpdate = 0;
foreach($this->m_aToDelete as $sClass => $aToDelete) foreach ($this->m_aToDelete as $sClass => $aToDelete) {
{ foreach ($aToDelete as $iId => $aData) {
foreach($aToDelete as $iId => $aData)
{
$this->m_iToDelete++; $this->m_iToDelete++;
if (isset($aData['issue'])) if (isset($aData['issue'])) {
{
$this->m_bFoundStopper = true; $this->m_bFoundStopper = true;
$this->m_bFoundManualOperation = true; $this->m_bFoundManualOperation = true;
if (isset($aData['issue_security'])) if (isset($aData['issue_security'])) {
{
$this->m_bFoundSecurityIssue = true; $this->m_bFoundSecurityIssue = true;
} }
} }
if ($aData['mode'] == DEL_MANUAL) if ($aData['mode'] == DEL_MANUAL) {
{
$this->m_aToDelete[$sClass][$iId]['issue'] = $sClass.'::'.$iId.' '.Dict::S('UI:Delete:MustBeDeletedManually'); $this->m_aToDelete[$sClass][$iId]['issue'] = $sClass.'::'.$iId.' '.Dict::S('UI:Delete:MustBeDeletedManually');
$this->m_bFoundStopper = true; $this->m_bFoundStopper = true;
$this->m_bFoundManualDelete = true; $this->m_bFoundManualDelete = true;
@@ -92,30 +88,25 @@ class DeletionPlan
// www.php.net/manual/fr/function.set-time-limit.php#72305 // www.php.net/manual/fr/function.set-time-limit.php#72305
$iPreviousTimeLimit = ini_get('max_execution_time'); $iPreviousTimeLimit = ini_get('max_execution_time');
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
foreach($this->m_aToUpdate as $sClass => $aToUpdate) foreach ($this->m_aToUpdate as $sClass => $aToUpdate) {
{ foreach ($aToUpdate as $iId => $aData) {
foreach($aToUpdate as $iId => $aData)
{
set_time_limit(intval($iLoopTimeLimit)); set_time_limit(intval($iLoopTimeLimit));
$this->m_iToUpdate++; $this->m_iToUpdate++;
$oObject = $aData['to_reset']; $oObject = $aData['to_reset'];
$aExtKeyLabels = array(); $aExtKeyLabels = [];
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) {
{
$oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]); $oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
$aExtKeyLabels[] = $aRemoteAttDef->GetLabel(); $aExtKeyLabels[] = $aRemoteAttDef->GetLabel();
} }
$this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels); $this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels);
list($bRes, $aIssues, $bSecurityIssues) = $oObject->CheckToWrite(); list($bRes, $aIssues, $bSecurityIssues) = $oObject->CheckToWrite();
if (!$bRes) if (!$bRes) {
{
$this->m_aToUpdate[$sClass][$iId]['issue'] = implode(', ', $aIssues); $this->m_aToUpdate[$sClass][$iId]['issue'] = implode(', ', $aIssues);
$this->m_bFoundStopper = true; $this->m_bFoundStopper = true;
if ($bSecurityIssues) if ($bSecurityIssues) {
{
$this->m_aToUpdate[$sClass][$iId]['issue_security'] = true; $this->m_aToUpdate[$sClass][$iId]['issue_security'] = true;
$this->m_bFoundSecurityIssue = true; $this->m_bFoundSecurityIssue = true;
} }
@@ -127,23 +118,17 @@ class DeletionPlan
public function GetIssues() public function GetIssues()
{ {
$aIssues = array(); $aIssues = [];
foreach ($this->m_aToDelete as $sClass => $aToDelete) foreach ($this->m_aToDelete as $sClass => $aToDelete) {
{ foreach ($aToDelete as $iId => $aData) {
foreach ($aToDelete as $iId => $aData) if (isset($aData['issue'])) {
{
if (isset($aData['issue']))
{
$aIssues[] = $aData['issue']; $aIssues[] = $aData['issue'];
} }
} }
} }
foreach ($this->m_aToUpdate as $sClass => $aToUpdate) foreach ($this->m_aToUpdate as $sClass => $aToUpdate) {
{ foreach ($aToUpdate as $iId => $aData) {
foreach ($aToUpdate as $iId => $aData) if (isset($aData['issue'])) {
{
if (isset($aData['issue']))
{
$aIssues[] = $aData['issue']; $aIssues[] = $aData['issue'];
} }
} }
@@ -192,63 +177,50 @@ class DeletionPlan
public function AddToDelete($oObject, $iDeletionMode = null) public function AddToDelete($oObject, $iDeletionMode = null)
{ {
if (is_null($iDeletionMode)) if (is_null($iDeletionMode)) {
{
$bRequestedExplicitely = true; $bRequestedExplicitely = true;
$iDeletionMode = DEL_AUTO; $iDeletionMode = DEL_AUTO;
} } else {
else
{
$bRequestedExplicitely = false; $bRequestedExplicitely = false;
} }
$sClass = get_class($oObject); $sClass = get_class($oObject);
$iId = $oObject->GetKey(); $iId = $oObject->GetKey();
if (isset($this->m_aToUpdate[$sClass][$iId])) if (isset($this->m_aToUpdate[$sClass][$iId])) {
{
unset($this->m_aToUpdate[$sClass][$iId]); unset($this->m_aToUpdate[$sClass][$iId]);
} }
if (isset($this->m_aToDelete[$sClass][$iId])) if (isset($this->m_aToDelete[$sClass][$iId])) {
{ if ($this->m_aToDelete[$sClass][$iId]['requested_explicitely']) {
if ($this->m_aToDelete[$sClass][$iId]['requested_explicitely'])
{
// No change: let it in mode DEL_AUTO // No change: let it in mode DEL_AUTO
} } else {
else
{
$iPrevDeletionMode = $this->m_aToDelete[$sClass][$iId]['mode']; $iPrevDeletionMode = $this->m_aToDelete[$sClass][$iId]['mode'];
$iNewDeletionMode = self::$m_aModeUpdate[$iPrevDeletionMode][$iDeletionMode]; $iNewDeletionMode = self::$m_aModeUpdate[$iPrevDeletionMode][$iDeletionMode];
$this->m_aToDelete[$sClass][$iId]['mode'] = $iNewDeletionMode; $this->m_aToDelete[$sClass][$iId]['mode'] = $iNewDeletionMode;
if ($bRequestedExplicitely) if ($bRequestedExplicitely) {
{
// This object was in the root list // This object was in the root list
$this->m_aToDelete[$sClass][$iId]['requested_explicitely'] = true; $this->m_aToDelete[$sClass][$iId]['requested_explicitely'] = true;
$this->m_aToDelete[$sClass][$iId]['mode'] = DEL_AUTO; $this->m_aToDelete[$sClass][$iId]['mode'] = DEL_AUTO;
} }
} }
} } else {
else $this->m_aToDelete[$sClass][$iId] = [
{
$this->m_aToDelete[$sClass][$iId] = array(
'to_delete' => $oObject, 'to_delete' => $oObject,
'mode' => $iDeletionMode, 'mode' => $iDeletionMode,
'requested_explicitely' => $bRequestedExplicitely, 'requested_explicitely' => $bRequestedExplicitely,
); ];
} }
} }
public function SetDeletionIssues($oObject, $aIssues, $bSecurityIssue) public function SetDeletionIssues($oObject, $aIssues, $bSecurityIssue)
{ {
if (count($aIssues ?? []) > 0) if (count($aIssues ?? []) > 0) {
{
$sClass = get_class($oObject); $sClass = get_class($oObject);
$iId = $oObject->GetKey(); $iId = $oObject->GetKey();
$this->m_aToDelete[$sClass][$iId]['issue'] = implode(', ', $aIssues); $this->m_aToDelete[$sClass][$iId]['issue'] = implode(', ', $aIssues);
if ($bSecurityIssue) if ($bSecurityIssue) {
{
$this->m_aToDelete[$sClass][$iId]['issue_security'] = true; $this->m_aToDelete[$sClass][$iId]['issue_security'] = true;
} }
} }
@@ -258,21 +230,16 @@ class DeletionPlan
{ {
$sClass = get_class($oObject); $sClass = get_class($oObject);
$iId = $oObject->GetKey(); $iId = $oObject->GetKey();
if (isset($this->m_aToDelete[$sClass][$iId])) if (isset($this->m_aToDelete[$sClass][$iId])) {
{
// skip... it should be deleted anyhow ! // skip... it should be deleted anyhow !
} } else {
else if (!isset($this->m_aToUpdate[$sClass][$iId])) {
{ $this->m_aToUpdate[$sClass][$iId] = [
if (!isset($this->m_aToUpdate[$sClass][$iId]))
{
$this->m_aToUpdate[$sClass][$iId] = array(
'to_reset' => $oObject, 'to_reset' => $oObject,
); ];
} }
$this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef; $this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef;
$this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value; $this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value;
} }
} }
} }
?>

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* Copyright (c) 2010-2024 Combodo SAS * Copyright (c) 2010-2024 Combodo SAS
* *
@@ -46,11 +47,9 @@ use utils;
*/ */
class DesignDocument extends DOMDocument class DesignDocument extends DOMDocument
{ {
/** To fix DOMNode::getLineNo() ref https://www.php.net/manual/en/domnode.getlineno.php */ /** To fix DOMNode::getLineNo() ref https://www.php.net/manual/en/domnode.getlineno.php */
public const XML_PARSE_BIG_LINES = 4194304; public const XML_PARSE_BIG_LINES = 4194304;
/** /**
* @throws \Exception * @throws \Exception
*/ */
@@ -135,13 +134,10 @@ class DesignDocument extends DOMDocument
*/ */
public static function XPathQuote($sValue) public static function XPathQuote($sValue)
{ {
if (strpos($sValue, '"') !== false) if (strpos($sValue, '"') !== false) {
{
$aParts = explode('"', $sValue); $aParts = explode('"', $sValue);
$sRet = 'concat("'.implode('", \'"\', "', $aParts).'")'; $sRet = 'concat("'.implode('", \'"\', "', $aParts).'")';
} } else {
else
{
$sRet = '"'.$sValue.'"'; $sRet = '"'.$sValue.'"';
} }
return $sRet; return $sRet;
@@ -156,12 +152,9 @@ class DesignDocument extends DOMDocument
public function GetNodes($sXPath, $oContextNode = null) public function GetNodes($sXPath, $oContextNode = null)
{ {
$oXPath = new \DOMXPath($this); $oXPath = new \DOMXPath($this);
if (is_null($oContextNode)) if (is_null($oContextNode)) {
{
$oResult = $oXPath->query($sXPath); $oResult = $oXPath->query($sXPath);
} } else {
else
{
$oResult = $oXPath->query($sXPath, $oContextNode); $oResult = $oXPath->query($sXPath, $oContextNode);
} }
return $oResult; return $oResult;
@@ -174,8 +167,12 @@ class DesignDocument extends DOMDocument
*/ */
public static function GetItopNodePath($oNode) public static function GetItopNodePath($oNode)
{ {
if ($oNode instanceof \DOMDocument) return ''; if ($oNode instanceof \DOMDocument) {
if (is_null($oNode)) return ''; return '';
}
if (is_null($oNode)) {
return '';
}
$sId = $oNode->getAttribute('id'); $sId = $oNode->getAttribute('id');
$sNodeDesc = ($sId != '') ? $oNode->nodeName.'['.$sId.']' : $oNode->nodeName; $sNodeDesc = ($sId != '') ? $oNode->nodeName.'['.$sId.']' : $oNode->nodeName;
@@ -303,16 +300,13 @@ class DesignElement extends \DOMElement
public function GetUniqueElement($sTagName, $bMustExist = true) public function GetUniqueElement($sTagName, $bMustExist = true)
{ {
$oNode = null; $oNode = null;
foreach($this->childNodes as $oChildNode) foreach ($this->childNodes as $oChildNode) {
{ if ($oChildNode->nodeName == $sTagName) {
if ($oChildNode->nodeName == $sTagName)
{
$oNode = $oChildNode; $oNode = $oChildNode;
break; break;
} }
} }
if ($bMustExist && is_null($oNode)) if ($bMustExist && is_null($oNode)) {
{
throw new DOMFormatException('Missing unique tag: '.$sTagName); throw new DOMFormatException('Missing unique tag: '.$sTagName);
} }
return $oNode; return $oNode;
@@ -337,20 +331,17 @@ class DesignElement extends \DOMElement
public function GetText($sDefault = null) public function GetText($sDefault = null)
{ {
$sText = null; $sText = null;
foreach($this->childNodes as $oChildNode) foreach ($this->childNodes as $oChildNode) {
{ if ($oChildNode instanceof \DOMText) {
if ($oChildNode instanceof \DOMText) if (is_null($sText)) {
{ $sText = '';
if (is_null($sText)) $sText = ''; }
$sText .= $oChildNode->wholeText; $sText .= $oChildNode->wholeText;
} }
} }
if (is_null($sText)) if (is_null($sText)) {
{
return $sDefault; return $sDefault;
} } else {
else
{
return $sText; return $sText;
} }
} }
@@ -367,8 +358,7 @@ class DesignElement extends \DOMElement
public function GetChildText($sTagName, $sDefault = null) public function GetChildText($sTagName, $sDefault = null)
{ {
$sRet = $sDefault; $sRet = $sDefault;
if ($oChild = $this->GetOptionalElement($sTagName)) if ($oChild = $this->GetOptionalElement($sTagName)) {
{
$sRet = $oChild->GetText($sDefault); $sRet = $oChild->GetText($sDefault);
} }
return $sRet; return $sRet;
@@ -427,7 +417,6 @@ class DesignElement extends \DOMElement
return self::_FindNode($this, $oRefNode, $sSearchId); return self::_FindNode($this, $oRefNode, $sSearchId);
} }
/** /**
* Find the child node matching the given node. * Find the child node matching the given node.
* UNSAFE: may return nodes marked as _alteration="removed" * UNSAFE: may return nodes marked as _alteration="removed"
@@ -482,32 +471,25 @@ class DesignElement extends \DOMElement
*/ */
public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null) public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null)
{ {
if ($oParent instanceof DOMDocument) if ($oParent instanceof DOMDocument) {
{
$oDoc = $oParent->firstChild->ownerDocument; $oDoc = $oParent->firstChild->ownerDocument;
$oRoot = $oParent; $oRoot = $oParent;
} } else {
else
{
$oDoc = $oParent->ownerDocument; $oDoc = $oParent->ownerDocument;
$oRoot = $oParent; $oRoot = $oParent;
} }
$oXPath = new DOMXPath($oDoc); $oXPath = new DOMXPath($oDoc);
if ($oRefNode->hasAttribute('id')) if ($oRefNode->hasAttribute('id')) {
{
// Find the elements having the same tag name and id // Find the elements having the same tag name and id
if (!$sSearchId) if (!$sSearchId) {
{
$sSearchId = $oRefNode->getAttribute('id'); $sSearchId = $oRefNode->getAttribute('id');
} }
$sQuotedId = DesignDocument::XPathQuote($sSearchId); $sQuotedId = DesignDocument::XPathQuote($sSearchId);
$sXPath = './'.$oRefNode->tagName."[@id=$sQuotedId]"; $sXPath = './'.$oRefNode->tagName."[@id=$sQuotedId]";
$oRes = $oXPath->query($sXPath, $oRoot); $oRes = $oXPath->query($sXPath, $oRoot);
} } else {
else
{
// Get the elements having the same tag name // Get the elements having the same tag name
$sXPath = './'.$oRefNode->tagName; $sXPath = './'.$oRefNode->tagName;

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -16,12 +17,10 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
define('DICT_ERR_STRING', 1); // when a string is missing, return the identifier define('DICT_ERR_STRING', 1); // when a string is missing, return the identifier
define('DICT_ERR_EXCEPTION', 2); // when a string is missing, throw an exception define('DICT_ERR_EXCEPTION', 2); // when a string is missing, throw an exception
//define('DICT_ERR_LOG', 3); // when a string is missing, log an error //define('DICT_ERR_LOG', 3); // when a string is missing, log an error
/** /**
* Class Dict * Class Dict
* Management of localizable strings * Management of localizable strings
@@ -32,8 +31,8 @@ class Dict
protected static $m_sDefaultLanguage = 'EN US'; protected static $m_sDefaultLanguage = 'EN US';
protected static $m_sCurrentLanguage = null; // No language selected by default protected static $m_sCurrentLanguage = null; // No language selected by default
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...) protected static $m_aLanguages = []; // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
protected static $m_aData = array(); protected static $m_aData = [];
protected static $m_sApplicationPrefix = null; protected static $m_sApplicationPrefix = null;
/** @var \ApcService $m_oApcService */ /** @var \ApcService $m_oApcService */
protected static $m_oApcService = null; protected static $m_oApcService = null;
@@ -45,8 +44,7 @@ class Dict
*/ */
public static function SetDefaultLanguage($sLanguageCode) public static function SetDefaultLanguage($sLanguageCode)
{ {
if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) {
{
throw new DictExceptionUnknownLanguage($sLanguageCode); throw new DictExceptionUnknownLanguage($sLanguageCode);
} }
self::$m_sDefaultLanguage = $sLanguageCode; self::$m_sDefaultLanguage = $sLanguageCode;
@@ -60,18 +58,15 @@ class Dict
*/ */
public static function SetUserLanguage($sLanguageCode = null) public static function SetUserLanguage($sLanguageCode = null)
{ {
if (!is_null($sLanguageCode) && !array_key_exists($sLanguageCode, self::$m_aLanguages)) if (!is_null($sLanguageCode) && !array_key_exists($sLanguageCode, self::$m_aLanguages)) {
{
throw new DictExceptionUnknownLanguage($sLanguageCode); throw new DictExceptionUnknownLanguage($sLanguageCode);
} }
self::$m_sCurrentLanguage = $sLanguageCode; self::$m_sCurrentLanguage = $sLanguageCode;
} }
public static function GetUserLanguage() public static function GetUserLanguage()
{ {
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e. login screen, non-authenticated page) if (self::$m_sCurrentLanguage == null) { // May happen when no user is logged in (i.e. login screen, non-authenticated page)
{
// In which case let's use the default language // In which case let's use the default language
return self::$m_sDefaultLanguage; return self::$m_sDefaultLanguage;
} }
@@ -99,8 +94,7 @@ class Dict
public static function Exists($sStringCode) public static function Exists($sStringCode)
{ {
$sImpossibleString = 'aVlHYKEI3TZuDV5o0pghv7fvhYNYuzYkTk7WL0Zoqw8rggE7aq'; $sImpossibleString = 'aVlHYKEI3TZuDV5o0pghv7fvhYNYuzYkTk7WL0Zoqw8rggE7aq';
if (static::S($sStringCode, $sImpossibleString) === $sImpossibleString) if (static::S($sStringCode, $sImpossibleString) === $sImpossibleString) {
{
return false; return false;
} }
return true; return true;
@@ -139,26 +133,22 @@ class Dict
$sLangCode = self::GetUserLanguage(); $sLangCode = self::GetUserLanguage();
self::InitLangIfNeeded($sLangCode); self::InitLangIfNeeded($sLangCode);
if (! array_key_exists($sLangCode, self::$m_aData)) if (! array_key_exists($sLangCode, self::$m_aData)) {
{
IssueLog::Warning("Cannot find $sLangCode in all registered dictionaries."); IssueLog::Warning("Cannot find $sLangCode in all registered dictionaries.");
// It may happen, when something happens before the dictionaries get loaded // It may happen, when something happens before the dictionaries get loaded
return [ 'label' => $sStringCode, 'lang' => $sLangCode ]; return [ 'label' => $sStringCode, 'lang' => $sLangCode ];
} }
$aCurrentDictionary = self::$m_aData[$sLangCode]; $aCurrentDictionary = self::$m_aData[$sLangCode];
if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary)) if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary)) {
{
return [ 'label' => $aCurrentDictionary[$sStringCode], 'lang' => $sLangCode ]; return [ 'label' => $aCurrentDictionary[$sStringCode], 'lang' => $sLangCode ];
} }
if (!$bUserLanguageOnly) if (!$bUserLanguageOnly) {
{
// Attempt to find the string in the default language // Attempt to find the string in the default language
// //
self::InitLangIfNeeded(self::$m_sDefaultLanguage); self::InitLangIfNeeded(self::$m_sDefaultLanguage);
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage]; $aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary)) if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary)) {
{
return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => self::$m_sDefaultLanguage ]; return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => self::$m_sDefaultLanguage ];
} }
// Attempt to find the string in english // Attempt to find the string in english
@@ -166,22 +156,19 @@ class Dict
self::InitLangIfNeeded('EN US'); self::InitLangIfNeeded('EN US');
$aDefaultDictionary = self::$m_aData['EN US']; $aDefaultDictionary = self::$m_aData['EN US'];
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary)) if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary)) {
{
return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => 'EN US' ]; return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => 'EN US' ];
} }
} }
// Could not find the string... // Could not find the string...
// //
if (is_null($sDefault)) if (is_null($sDefault)) {
{
return [ 'label' => $sStringCode, 'lang' => null ]; return [ 'label' => $sStringCode, 'lang' => null ];
} }
return [ 'label' => $sDefault, 'lang' => null ]; return [ 'label' => $sDefault, 'lang' => null ];
} }
/** /**
* Formats a localized string with numbered placeholders (%1$s...) for the additional arguments * Formats a localized string with numbered placeholders (%1$s...) for the additional arguments
* See vsprintf for more information about the syntax of the placeholders * See vsprintf for more information about the syntax of the placeholders
@@ -199,15 +186,14 @@ class Dict
$aArguments = func_get_args(); $aArguments = func_get_args();
array_shift($aArguments); array_shift($aArguments);
if ($sLocalizedFormat == $sFormatCode) if ($sLocalizedFormat == $sFormatCode) {
{
// Make sure the information will be displayed (ex: an error occurring before the dictionary gets loaded) // Make sure the information will be displayed (ex: an error occurring before the dictionary gets loaded)
return $sFormatCode.' - '.implode(', ', $aArguments); return $sFormatCode.' - '.implode(', ', $aArguments);
} }
try{ try {
return utils::VSprintf($sLocalizedFormat, $aArguments); return utils::VSprintf($sLocalizedFormat, $aArguments);
} catch(\Throwable $e){ } catch (\Throwable $e) {
\IssueLog::Error("Cannot format dict key", null, ["sFormatCode" => $sFormatCode, "sLangCode" => $sLangCode, 'exception_msg' => $e->getMessage() ]); \IssueLog::Error("Cannot format dict key", null, ["sFormatCode" => $sFormatCode, "sLangCode" => $sLangCode, 'exception_msg' => $e->getMessage() ]);
return $sFormatCode.' - '.implode(', ', $aArguments); return $sFormatCode.' - '.implode(', ', $aArguments);
} }
@@ -236,8 +222,9 @@ class Dict
* @since 2.7.6 N°4125 * @since 2.7.6 N°4125
* @return \ApcService * @return \ApcService
*/ */
public static function GetApcService() { public static function GetApcService()
if (self::$m_oApcService === null){ {
if (self::$m_oApcService === null) {
self::$m_oApcService = new ApcService(); self::$m_oApcService = new ApcService();
} }
return self::$m_oApcService; return self::$m_oApcService;
@@ -247,7 +234,8 @@ class Dict
* @since 2.7.6 N°4125 * @since 2.7.6 N°4125
* @param \ApcService $m_oApcService * @param \ApcService $m_oApcService
*/ */
public static function SetApcService($oApcService) { public static function SetApcService($oApcService)
{
self::$m_oApcService = $oApcService; self::$m_oApcService = $oApcService;
} }
@@ -258,19 +246,20 @@ class Dict
*/ */
public static function InitLangIfNeeded($sLangCode) public static function InitLangIfNeeded($sLangCode)
{ {
if (array_key_exists($sLangCode, self::$m_aData)) return true; if (array_key_exists($sLangCode, self::$m_aData)) {
return true;
}
$bResult = false; $bResult = false;
if (self::GetApcService()->function_exists('apc_fetch') if (self::GetApcService()->function_exists('apc_fetch')
&& (self::$m_sApplicationPrefix !== null)) && (self::$m_sApplicationPrefix !== null)) {
{
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter // Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
// //
self::$m_aData[$sLangCode] = self::GetApcService()->apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode); self::$m_aData[$sLangCode] = self::GetApcService()->apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode);
if (self::$m_aData[$sLangCode] === false) { if (self::$m_aData[$sLangCode] === false) {
unset(self::$m_aData[$sLangCode]); unset(self::$m_aData[$sLangCode]);
} else if (! is_array(self::$m_aData[$sLangCode])) { } elseif (! is_array(self::$m_aData[$sLangCode])) {
// N°4125: we don't fix dictionary corrupted cache (on iTop side). // N°4125: we don't fix dictionary corrupted cache (on iTop side).
// but we log an error in a dedicated channel to let itop administrator be aware of a potential APCu issue to fix. // but we log an error in a dedicated channel to let itop administrator be aware of a potential APCu issue to fix.
IssueLog::Error("APCu corrupted data (with $sLangCode dictionary). APCu configuration and running version should be troubleshooted...", LogChannels::APC); IssueLog::Error("APCu corrupted data (with $sLangCode dictionary). APCu configuration and running version should be troubleshooted...", LogChannels::APC);
@@ -279,14 +268,12 @@ class Dict
$bResult = true; $bResult = true;
} }
} }
if (!$bResult) if (!$bResult) {
{
$sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php'; $sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php';
require_once($sDictFile); require_once($sDictFile);
if (self::GetApcService()->function_exists('apc_store') if (self::GetApcService()->function_exists('apc_store')
&& (self::$m_sApplicationPrefix !== null)) && (self::$m_sApplicationPrefix !== null)) {
{
self::GetApcService()->apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]); self::GetApcService()->apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]);
} }
$bResult = true; $bResult = true;
@@ -309,10 +296,8 @@ class Dict
*/ */
public static function ResetCache($sApplicationPrefix) public static function ResetCache($sApplicationPrefix)
{ {
if (function_exists('apc_delete')) if (function_exists('apc_delete')) {
{ foreach (self::$m_aLanguages as $sLang => $void) {
foreach(self::$m_aLanguages as $sLang => $void)
{
apc_delete($sApplicationPrefix.'-dict-'.$sLang); apc_delete($sApplicationPrefix.'-dict-'.$sLang);
} }
} }
@@ -320,7 +305,6 @@ class Dict
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
/** /**
* Clone a string in every language (if it exists in that language) * Clone a string in every language (if it exists in that language)
* *
@@ -330,8 +314,8 @@ class Dict
*/ */
public static function CloneString($sSourceCode, $sDestCode) public static function CloneString($sSourceCode, $sDestCode)
{ {
foreach(self::$m_aLanguages as $sLanguageCode => $foo) { foreach (self::$m_aLanguages as $sLanguageCode => $foo) {
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]) && !isset(self::$m_aData[$sLanguageCode][$sDestCode] )) { if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]) && !isset(self::$m_aData[$sLanguageCode][$sDestCode])) {
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode]; self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
} }
} }
@@ -339,40 +323,31 @@ class Dict
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US') public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{ {
$aMissing = array(); // Strings missing for the target language $aMissing = []; // Strings missing for the target language
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary $aUnexpected = []; // Strings defined for the target language, but not found in the reference dictionary
$aNotTranslated = array(); // Strings having the same value in both dictionaries $aNotTranslated = []; // Strings having the same value in both dictionaries
$aOK = array(); // Strings having different values in both dictionaries $aOK = []; // Strings having different values in both dictionaries
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue) foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue) {
{ if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode])) {
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
{
$aMissing[$sStringCode] = $sValue; $aMissing[$sStringCode] = $sValue;
} }
} }
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue) foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue) {
{ if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef])) {
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
{
$aUnexpected[$sStringCode] = $sValue; $aUnexpected[$sStringCode] = $sValue;
} } else {
else
{
// The value exists in the reference // The value exists in the reference
$sRefValue = self::$m_aData[$sLanguageRef][$sStringCode]; $sRefValue = self::$m_aData[$sLanguageRef][$sStringCode];
if ($sValue == $sRefValue) if ($sValue == $sRefValue) {
{
$aNotTranslated[$sStringCode] = $sValue; $aNotTranslated[$sStringCode] = $sValue;
} } else {
else
{
$aOK[$sStringCode] = $sValue; $aOK[$sStringCode] = $sValue;
} }
} }
} }
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK); return [$aMissing, $aUnexpected, $aNotTranslated, $aOK];
} }
public static function Dump() public static function Dump()
@@ -389,10 +364,9 @@ class Dict
// ~~ or ~* can be used to indicate entries still to be translated. // ~~ or ~* can be used to indicate entries still to be translated.
public static function Add($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries) public static function Add($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
{ {
if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) {
{ self::$m_aLanguages[$sLanguageCode] = ['description' => $sEnglishLanguageDesc, 'localized_description' => $sLocalizedLanguageDesc];
self::$m_aLanguages[$sLanguageCode] = array('description' => $sEnglishLanguageDesc, 'localized_description' => $sLocalizedLanguageDesc); self::$m_aData[$sLanguageCode] = [];
self::$m_aData[$sLanguageCode] = array();
} }
// No need to actually load the strings since it's only used to know the list of languages // No need to actually load the strings since it's only used to know the list of languages
// at setup time !! // at setup time !!
@@ -408,27 +382,22 @@ class Dict
{ {
self::InitLangIfNeeded(self::GetUserLanguage()); self::InitLangIfNeeded(self::GetUserLanguage());
self::InitLangIfNeeded(self::$m_sDefaultLanguage); self::InitLangIfNeeded(self::$m_sDefaultLanguage);
$aEntries = array(); $aEntries = [];
$iLength = strlen($sStartingWith); $iLength = strlen($sStartingWith);
// First prefill the array with entries from the default language // First prefill the array with entries from the default language
foreach(self::$m_aData[self::$m_sDefaultLanguage] as $sCode => $sEntry) foreach (self::$m_aData[self::$m_sDefaultLanguage] as $sCode => $sEntry) {
{ if (substr($sCode, 0, $iLength) == $sStartingWith) {
if (substr($sCode, 0, $iLength) == $sStartingWith)
{
$aEntries[$sCode] = $sEntry; $aEntries[$sCode] = $sEntry;
} }
} }
// Now put (overwrite) the entries for the user language // Now put (overwrite) the entries for the user language
foreach(self::$m_aData[self::GetUserLanguage()] as $sCode => $sEntry) foreach (self::$m_aData[self::GetUserLanguage()] as $sCode => $sEntry) {
{ if (substr($sCode, 0, $iLength) == $sStartingWith) {
if (substr($sCode, 0, $iLength) == $sStartingWith)
{
$aEntries[$sCode] = $sEntry; $aEntries[$sCode] = $sEntry;
} }
} }
return $aEntries; return $aEntries;
} }
} }
?>

View File

@@ -1,9 +1,10 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -16,7 +17,6 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Send an email (abstraction for synchronous/asynchronous modes) * Send an email (abstraction for synchronous/asynchronous modes)
* *
@@ -27,9 +27,9 @@
use Combodo\iTop\Core\Email\EmailFactory; use Combodo\iTop\Core\Email\EmailFactory;
use Combodo\iTop\Core\Email\iEMail; use Combodo\iTop\Core\Email\iEMail;
define ('EMAIL_SEND_OK', 0); define('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1); define('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2); define('EMAIL_SEND_ERROR', 2);
class EMail implements iEMail class EMail implements iEMail
{ {
@@ -43,18 +43,18 @@ class EMail implements iEMail
protected $oMailer; protected $oMailer;
// Serialization formats // Serialization formats
const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object. public const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object.
// Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string // Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed) public const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed)
/** @var int ENUM_SEND_DEFAULT This option can be used when sending an e-mail to respect the default configuration parameter. */ /** @var int ENUM_SEND_DEFAULT This option can be used when sending an e-mail to respect the default configuration parameter. */
const ENUM_SEND_DEFAULT = 0; public const ENUM_SEND_DEFAULT = 0;
/** @var int ENUM_SEND_FORCE_SYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: instant e-mail test. */ /** @var int ENUM_SEND_FORCE_SYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: instant e-mail test. */
const ENUM_SEND_FORCE_SYNCHRONOUS = 1; public const ENUM_SEND_FORCE_SYNCHRONOUS = 1;
/** @var int ENUM_SEND_FORCE_ASYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: Bulk mails. */ /** @var int ENUM_SEND_FORCE_ASYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: Bulk mails. */
const ENUM_SEND_FORCE_ASYNCHRONOUS = 2; public const ENUM_SEND_FORCE_ASYNCHRONOUS = 2;
public function __construct() public function __construct()
{ {
@@ -157,7 +157,7 @@ class EMail implements iEMail
public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null) public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null)
{ {
$this->oMailer->SetBody($sBody, $sMimeType, $sCustomStyles); $this->oMailer->SetBody($sBody, $sMimeType, $sCustomStyles);
} }
public function AddPart($sText, $sMimeType = 'text/html') public function AddPart($sText, $sMimeType = 'text/html')
{ {
@@ -208,4 +208,4 @@ class EMail implements iEMail
{ {
$this->oMailer->SetRecipientReplyTo($sAddress); $this->oMailer->SetRecipientReplyTo($sAddress);
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -45,19 +46,18 @@ class ExcelBulkExport extends TabularBulkExport
{ {
parent::ReadParameters(); parent::ReadParameters();
$this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true); $this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true);
$sDateFormatRadio = utils::ReadParam('excel_date_format_radio', ''); $sDateFormatRadio = utils::ReadParam('excel_date_format_radio', '');
switch($sDateFormatRadio) switch ($sDateFormatRadio) {
{
case 'default': case 'default':
// Export from the UI => format = same as is the UI // Export from the UI => format = same as is the UI
$this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat();
break; break;
case 'custom': case 'custom':
// Custom format specified from the UI // Custom format specified from the UI
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
break; break;
default: default:
// Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise
@@ -67,7 +67,7 @@ class ExcelBulkExport extends TabularBulkExport
public function EnumFormParts() public function EnumFormParts()
{ {
return array_merge(parent::EnumFormParts(), array('xlsx_options' => array('formatted_text'), 'interactive_fields_xlsx' => array('interactive_fields_xlsx'))); return array_merge(parent::EnumFormParts(), ['xlsx_options' => ['formatted_text'], 'interactive_fields_xlsx' => ['interactive_fields_xlsx']]);
} }
/** /**
@@ -121,7 +121,6 @@ class ExcelBulkExport extends TabularBulkExport
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox'); $oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
$oFieldSetDate->AddSubBlock($oRadioCustom); $oFieldSetDate->AddSubBlock($oRadioCustom);
$oP->add_ready_script( $oP->add_ready_script(
<<<EOF <<<EOF
$('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); }); $('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); });
@@ -141,16 +140,14 @@ EOF
protected function SuggestField($sClass, $sAttCode) protected function SuggestField($sClass, $sAttCode)
{ {
switch($sAttCode) switch ($sAttCode) {
{
case 'id': // replace 'id' by 'friendlyname' case 'id': // replace 'id' by 'friendlyname'
$sAttCode = 'friendlyname'; $sAttCode = 'friendlyname';
break; break;
default: default:
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeExternalKey) if ($oAttDef instanceof AttributeExternalKey) {
{
$sAttCode .= '_friendlyname'; $sAttCode .= '_friendlyname';
} }
} }
@@ -162,8 +159,7 @@ EOF
{ {
if ($sAttCode != 'id') { if ($sAttCode != 'id') {
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime if ($oAttDef instanceof AttributeDateTime) { // AttributeDate is derived from AttributeDateTime
{
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date'; $sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>'; return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
@@ -175,74 +171,50 @@ EOF
protected function GetValue($oObj, $sAttCode) protected function GetValue($oObj, $sAttCode)
{ {
switch($sAttCode) switch ($sAttCode) {
{
case 'id': case 'id':
$sRet = $oObj->GetKey(); $sRet = $oObj->GetKey();
break; break;
default: default:
$value = $oObj->Get($sAttCode); $value = $oObj->Get($sAttCode);
if ($value instanceOf ormCaseLog) if ($value instanceof ormCaseLog) {
{ if (array_key_exists('formatted_text', $this->aStatusInfo) && $this->aStatusInfo['formatted_text']) {
if (array_key_exists('formatted_text', $this->aStatusInfo) && $this->aStatusInfo['formatted_text']) $sText = $value->GetText();
{ } else {
$sText = $value->GetText(); $sText = $value->GetAsPlainText();
}
else
{
$sText = $value->GetAsPlainText();
}
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
$sRet = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $sText));
}
else if ($value instanceOf DBObjectSet)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else if ($value instanceOf ormDocument)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else if ($value instanceOf ormSet)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeDateTime)
{
// Date and times are formatted using the ISO encoding, not the localized format
if ($oAttDef->IsNull($value))
{
// NOt a valid date
$sRet = '';
} }
else // Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
{ $sRet = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $sText));
$sRet = $value; } elseif ($value instanceof DBObjectSet) {
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
} elseif ($value instanceof ormDocument) {
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
} elseif ($value instanceof ormSet) {
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
} else {
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeDateTime) {
// Date and times are formatted using the ISO encoding, not the localized format
if ($oAttDef->IsNull($value)) {
// NOt a valid date
$sRet = '';
} else {
$sRet = $value;
}
} elseif (array_key_exists('formatted_text', $this->aStatusInfo) && $this->aStatusInfo['formatted_text']) {
if ($oAttDef instanceof AttributeText && $oAttDef->GetFormat() == 'html') {
$sRet = str_replace("&gt;", ">", $value);
} else {
$sRet = $oAttDef->GetEditValue($value, $oObj);
}
} else {
$sRet = $oAttDef->GetAsPlainText($value, $oObj);
} }
} }
else if (array_key_exists('formatted_text', $this->aStatusInfo) && $this->aStatusInfo['formatted_text'])
{
if ($oAttDef instanceof AttributeText && $oAttDef->GetFormat()=='html')
{
$sRet = str_replace("&gt;", ">", $value);
}
else
{
$sRet = $oAttDef->GetEditValue($value, $oObj);
}
}
else
{
$sRet = $oAttDef->GetAsPlainText($value, $oObj);
}
}
} }
return $sRet; return $sRet;
} }
@@ -255,14 +227,12 @@ EOF
$this->aStatusInfo['position'] = 0; $this->aStatusInfo['position'] = 0;
$this->aStatusInfo['total'] = $oSet->Count(); $this->aStatusInfo['total'] = $oSet->Count();
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) {
{
$sExtendedAttCode = $aFieldSpec['sFieldSpec']; $sExtendedAttCode = $aFieldSpec['sFieldSpec'];
$sAttCode = $aFieldSpec['sAttCode']; $sAttCode = $aFieldSpec['sAttCode'];
$sColLabel = $aFieldSpec['sColLabel']; $sColLabel = $aFieldSpec['sColLabel'];
switch($sAttCode) switch ($sAttCode) {
{
case 'id': case 'id':
$sType = '0'; $sType = '0';
break; break;
@@ -270,22 +240,18 @@ EOF
default: default:
$oAttDef = MetaModel::GetAttributeDef($aFieldSpec['sClass'], $aFieldSpec['sAttCode']); $oAttDef = MetaModel::GetAttributeDef($aFieldSpec['sClass'], $aFieldSpec['sAttCode']);
$sType = 'string'; $sType = 'string';
if($oAttDef instanceof AttributeDate) if ($oAttDef instanceof AttributeDate) {
{
$sType = 'date'; $sType = 'date';
} } elseif ($oAttDef instanceof AttributeDateTime) {
else if($oAttDef instanceof AttributeDateTime)
{
$sType = 'datetime'; $sType = 'datetime';
} }
} }
$aTableHeaders[] = array('label' => $sColLabel, 'type' => $sType); $aTableHeaders[] = ['label' => $sColLabel, 'type' => $sType];
} }
$sRow = json_encode($aTableHeaders); $sRow = json_encode($aTableHeaders);
$hFile = @fopen($this->aStatusInfo['tmp_file'], 'ab'); $hFile = @fopen($this->aStatusInfo['tmp_file'], 'ab');
if ($hFile === false) if ($hFile === false) {
{
throw new Exception('ExcelBulkExport: Failed to open temporary data file: "'.$this->aStatusInfo['tmp_file'].'" for writing.'); throw new Exception('ExcelBulkExport: Failed to open temporary data file: "'.$this->aStatusInfo['tmp_file'].'" for writing.');
} }
fwrite($hFile, $sRow."\n"); fwrite($hFile, $sRow."\n");
@@ -307,19 +273,16 @@ EOF
$iCount = 0; $iCount = 0;
$iPreviousTimeLimit = ini_get('max_execution_time'); $iPreviousTimeLimit = ini_get('max_execution_time');
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
while($aRow = $oSet->FetchAssoc()) while ($aRow = $oSet->FetchAssoc()) {
{
set_time_limit(intval($iLoopTimeLimit)); set_time_limit(intval($iLoopTimeLimit));
$aData = array(); $aData = [];
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) {
{
$sAlias = $aFieldSpec['sAlias']; $sAlias = $aFieldSpec['sAlias'];
$sAttCode = $aFieldSpec['sAttCode']; $sAttCode = $aFieldSpec['sAttCode'];
$oObj = $aRow[$sAlias]; $oObj = $aRow[$sAlias];
$sField = ''; $sField = '';
if ($oObj) if ($oObj) {
{
$sField = $this->GetValue($oObj, $sAttCode); $sField = $this->GetValue($oObj, $sAttCode);
} }
$aData[] = $sField; $aData[] = $sField;
@@ -329,41 +292,35 @@ EOF
} }
set_time_limit(intval($iPreviousTimeLimit)); set_time_limit(intval($iPreviousTimeLimit));
$this->aStatusInfo['position'] += $this->iChunkSize; $this->aStatusInfo['position'] += $this->iChunkSize;
if ($this->aStatusInfo['total'] == 0) if ($this->aStatusInfo['total'] == 0) {
{
$iPercentage = 100; $iPercentage = 100;
$sRetCode = 'done'; // Next phase (GetFooter) will be to build the xlsx file $sRetCode = 'done'; // Next phase (GetFooter) will be to build the xlsx file
} else {
$iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total']));
} }
else if ($iCount < $this->iChunkSize) {
{
$iPercentage = floor(min(100.0, 100.0*$this->aStatusInfo['position']/$this->aStatusInfo['total']));
}
if ($iCount < $this->iChunkSize)
{
$sRetCode = 'done'; $sRetCode = 'done';
} }
$aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); $aStatus = ['code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage];
return ''; // The actual XLSX file is built in GetFooter(); return ''; // The actual XLSX file is built in GetFooter();
} }
public function GetFooter() public function GetFooter()
{ {
$hFile = @fopen($this->aStatusInfo['tmp_file'], 'rb'); $hFile = @fopen($this->aStatusInfo['tmp_file'], 'rb');
if ($hFile === false) if ($hFile === false) {
{
throw new Exception('ExcelBulkExport: Failed to open temporary data file: "'.$this->aStatusInfo['tmp_file'].'" for reading.'); throw new Exception('ExcelBulkExport: Failed to open temporary data file: "'.$this->aStatusInfo['tmp_file'].'" for reading.');
} }
$sHeaders = fgets($hFile); $sHeaders = fgets($hFile);
$aHeaders = json_decode($sHeaders, true); $aHeaders = json_decode($sHeaders, true);
$aData = array(); $aData = [];
while($sLine = fgets($hFile)) while ($sLine = fgets($hFile)) {
{
$aRow = json_decode($sLine); $aRow = json_decode($sLine);
$aData[] = $aRow; $aData[] = $aRow;
} }
fclose($hFile); fclose($hFile);
$fStartExcel = microtime(true); $fStartExcel = microtime(true);
$writer = new XLSXWriter(); $writer = new XLSXWriter();
$sDateFormat = isset($this->aStatusInfo['date_format']) ? $this->aStatusInfo['date_format'] : (string)AttributeDateTime::GetFormat(); $sDateFormat = isset($this->aStatusInfo['date_format']) ? $this->aStatusInfo['date_format'] : (string)AttributeDateTime::GetFormat();
@@ -372,14 +329,13 @@ EOF
$oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat()); $oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat());
$writer->setDateFormat($oDateFormat->ToExcel()); $writer->setDateFormat($oDateFormat->ToExcel());
$writer->setAuthor(UserRights::GetUserFriendlyName()); $writer->setAuthor(UserRights::GetUserFriendlyName());
$aHeaderTypes = array(); $aHeaderTypes = [];
$aHeaderNames = array(); $aHeaderNames = [];
foreach($aHeaders as $Header) foreach ($aHeaders as $Header) {
{
$aHeaderNames[] = $Header['label']; $aHeaderNames[] = $Header['label'];
$aHeaderTypes[] = $Header['type']; $aHeaderTypes[] = $Header['type'];
} }
$writer->writeSheet($aData,'Sheet1', $aHeaderTypes, $aHeaderNames); $writer->writeSheet($aData, 'Sheet1', $aHeaderTypes, $aHeaderNames);
$fExcelTime = microtime(true) - $fStartExcel; $fExcelTime = microtime(true) - $fStartExcel;
//$this->aStatistics['excel_build_duration'] = $fExcelTime; //$this->aStatistics['excel_build_duration'] = $fExcelTime;
@@ -405,6 +361,6 @@ EOF
public function GetSupportedFormats() public function GetSupportedFormats()
{ {
return array('xlsx' => Dict::S('Core:BulkExport:XLSXFormat')); return ['xlsx' => Dict::S('Core:BulkExport:XLSXFormat')];
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2024 Combodo SAS // Copyright (C) 2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -35,7 +36,7 @@ class HTMLBulkExport extends TabularBulkExport
public function EnumFormParts() public function EnumFormParts()
{ {
return array_merge(parent::EnumFormParts(), array('interactive_fields_html' => array('interactive_fields_html'))); return array_merge(parent::EnumFormParts(), ['interactive_fields_html' => ['interactive_fields_html']]);
} }
/** /**
@@ -52,17 +53,15 @@ class HTMLBulkExport extends TabularBulkExport
break; break;
default: default:
return parent:: GetFormPart($oP, $sPartId); return parent::GetFormPart($oP, $sPartId);
} }
} }
protected function GetSampleData($oObj, $sAttCode) protected function GetSampleData($oObj, $sAttCode)
{ {
if ($sAttCode != 'id') if ($sAttCode != 'id') {
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime if ($oAttDef instanceof AttributeDateTime) { // AttributeDate is derived from AttributeDateTime
{
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date'; $sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>'; return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
@@ -73,24 +72,18 @@ class HTMLBulkExport extends TabularBulkExport
protected function GetValue($oObj, $sAttCode) protected function GetValue($oObj, $sAttCode)
{ {
switch($sAttCode) switch ($sAttCode) {
{
case 'id': case 'id':
$sRet = $oObj->GetHyperlink(); $sRet = $oObj->GetHyperlink();
break; break;
default: default:
$value = $oObj->Get($sAttCode); $value = $oObj->Get($sAttCode);
if ($value instanceof ormCaseLog) if ($value instanceof ormCaseLog) {
{
$sRet = $value->GetAsSimpleHtml(); $sRet = $value->GetAsSimpleHtml();
} } elseif ($value instanceof ormStopWatch) {
elseif ($value instanceof ormStopWatch)
{
$sRet = $value->GetTimeSpent(); $sRet = $value->GetTimeSpent();
} } else {
else
{
$sRet = $oObj->GetAsHtml($sAttCode); $sRet = $oObj->GetAsHtml($sAttCode);
} }
} }
@@ -100,7 +93,7 @@ class HTMLBulkExport extends TabularBulkExport
public function GetHeader() public function GetHeader()
{ {
$sData = ''; $sData = '';
$oSet = new DBObjectSet($this->oSearch); $oSet = new DBObjectSet($this->oSearch);
$this->aStatusInfo['status'] = 'running'; $this->aStatusInfo['status'] = 'running';
$this->aStatusInfo['position'] = 0; $this->aStatusInfo['position'] = 0;
@@ -109,8 +102,7 @@ class HTMLBulkExport extends TabularBulkExport
$sData .= "<table class=\"listResults\">\n"; $sData .= "<table class=\"listResults\">\n";
$sData .= "<thead>\n"; $sData .= "<thead>\n";
$sData .= "<tr>\n"; $sData .= "<tr>\n";
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) {
{
$sData .= "<th>".$aFieldSpec['sColLabel']."</th>\n"; $sData .= "<th>".$aFieldSpec['sColLabel']."</th>\n";
} }
$sData .= "</tr>\n"; $sData .= "</tr>\n";
@@ -135,32 +127,25 @@ class HTMLBulkExport extends TabularBulkExport
$sData = ''; $sData = '';
$iPreviousTimeLimit = ini_get('max_execution_time'); $iPreviousTimeLimit = ini_get('max_execution_time');
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
while($aRow = $oSet->FetchAssoc()) while ($aRow = $oSet->FetchAssoc()) {
{
set_time_limit(intval($iLoopTimeLimit)); set_time_limit(intval($iLoopTimeLimit));
$oMainObj = $aRow[$sFirstAlias]; $oMainObj = $aRow[$sFirstAlias];
$sHilightClass = ''; $sHilightClass = '';
if ($oMainObj) if ($oMainObj) {
{
$sHilightClass = MetaModel::GetHilightClass($sClass, $aRow[$sFirstAlias]); $sHilightClass = MetaModel::GetHilightClass($sClass, $aRow[$sFirstAlias]);
} }
if ($sHilightClass != '') if ($sHilightClass != '') {
{
$sData .= "<tr class=\"$sHilightClass\">"; $sData .= "<tr class=\"$sHilightClass\">";
} } else {
else
{
$sData .= "<tr>"; $sData .= "<tr>";
} }
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) {
{
$sAlias = $aFieldSpec['sAlias']; $sAlias = $aFieldSpec['sAlias'];
$sAttCode = $aFieldSpec['sAttCode']; $sAttCode = $aFieldSpec['sAttCode'];
$oObj = $aRow[$sAlias]; $oObj = $aRow[$sAlias];
$sField = ''; $sField = '';
if ($oObj) if ($oObj) {
{
$sField = $this->GetValue($oObj, $sAttCode); $sField = $this->GetValue($oObj, $sAttCode);
} }
$sValue = ($sField === '') ? '&nbsp;' : $sField; $sValue = ($sField === '') ? '&nbsp;' : $sField;
@@ -171,21 +156,17 @@ class HTMLBulkExport extends TabularBulkExport
} }
set_time_limit(intval($iPreviousTimeLimit)); set_time_limit(intval($iPreviousTimeLimit));
$this->aStatusInfo['position'] += $this->iChunkSize; $this->aStatusInfo['position'] += $this->iChunkSize;
if ($this->aStatusInfo['total'] == 0) if ($this->aStatusInfo['total'] == 0) {
{
$iPercentage = 100; $iPercentage = 100;
} } else {
else $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total']));
{
$iPercentage = floor(min(100.0, 100.0*$this->aStatusInfo['position']/$this->aStatusInfo['total']));
} }
if ($iCount < $this->iChunkSize) if ($iCount < $this->iChunkSize) {
{
$sRetCode = 'done'; $sRetCode = 'done';
} }
$aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); $aStatus = ['code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage];
return $sData; return $sData;
} }
@@ -198,7 +179,7 @@ class HTMLBulkExport extends TabularBulkExport
public function GetSupportedFormats() public function GetSupportedFormats()
{ {
return array('html' => Dict::S('Core:BulkExport:HTMLFormat')); return ['html' => Dict::S('Core:BulkExport:HTMLFormat')];
} }
public function GetMimeType() public function GetMimeType()

View File

@@ -1,4 +1,5 @@
<?php <?php
// Copyright (C) 2016-2024 Combodo SAS // Copyright (C) 2016-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -48,7 +49,7 @@ abstract class HTMLSanitizer
if (!class_exists($sSanitizerClass)) { if (!class_exists($sSanitizerClass)) {
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a valid class. Will use HTMLDOMSanitizer as the default sanitizer.'); IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a valid class. Will use HTMLDOMSanitizer as the default sanitizer.');
$sSanitizerClass = 'HTMLDOMSanitizer'; $sSanitizerClass = 'HTMLDOMSanitizer';
} else if (!is_subclass_of($sSanitizerClass, 'HTMLSanitizer')) { } elseif (!is_subclass_of($sSanitizerClass, 'HTMLSanitizer')) {
if ($sConfigKey === 'html_sanitizer') { if ($sConfigKey === 'html_sanitizer') {
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of '.HTMLSanitizer::class.'. Will use HTMLDOMSanitizer as the default sanitizer.'); IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of '.HTMLSanitizer::class.'. Will use HTMLDOMSanitizer as the default sanitizer.');
$sSanitizerClass = 'HTMLDOMSanitizer'; $sSanitizerClass = 'HTMLDOMSanitizer';
@@ -62,17 +63,14 @@ abstract class HTMLSanitizer
try { try {
$oSanitizer = new $sSanitizerClass(); $oSanitizer = new $sSanitizerClass();
$sCleanHTML = $oSanitizer->DoSanitize($sHTML); $sCleanHTML = $oSanitizer->DoSanitize($sHTML);
} } catch (Exception $e) {
catch (Exception $e) {
if ($sSanitizerClass != 'HTMLDOMSanitizer') { if ($sSanitizerClass != 'HTMLDOMSanitizer') {
IssueLog::Warning('Failed to sanitize an HTML string with "'.$sSanitizerClass.'". The following exception occured: '.$e->getMessage()); IssueLog::Warning('Failed to sanitize an HTML string with "'.$sSanitizerClass.'". The following exception occured: '.$e->getMessage());
IssueLog::Warning('Will try to sanitize with HTMLDOMSanitizer.'); IssueLog::Warning('Will try to sanitize with HTMLDOMSanitizer.');
// try again with the HTMLDOMSanitizer // try again with the HTMLDOMSanitizer
$oSanitizer = new HTMLDOMSanitizer(); $oSanitizer = new HTMLDOMSanitizer();
$sCleanHTML = $oSanitizer->DoSanitize($sHTML); $sCleanHTML = $oSanitizer->DoSanitize($sHTML);
} } else {
else
{
IssueLog::Error('Failed to sanitize an HTML string with "HTMLDOMSanitizer". The following exception occured: '.$e->getMessage()); IssueLog::Error('Failed to sanitize an HTML string with "HTMLDOMSanitizer". The following exception occured: '.$e->getMessage());
IssueLog::Error('The HTML will NOT be sanitized.'); IssueLog::Error('The HTML will NOT be sanitized.');
$sCleanHTML = $sHTML; $sCleanHTML = $sHTML;
@@ -104,8 +102,6 @@ class HTMLNullSanitizer extends HTMLSanitizer
} }
} }
/** /**
* Common implementation for sanitizer using DOM parsing * Common implementation for sanitizer using DOM parsing
*/ */
@@ -166,7 +162,7 @@ abstract class DOMSanitizer extends HTMLSanitizer
protected function CleanNode(DOMNode $oElement) protected function CleanNode(DOMNode $oElement)
{ {
$aAttrToRemove = array(); $aAttrToRemove = [];
// Gather the attributes to remove // Gather the attributes to remove
if ($oElement->hasAttributes()) { if ($oElement->hasAttributes()) {
foreach ($oElement->attributes as $oAttr) { foreach ($oElement->attributes as $oAttr) {
@@ -174,13 +170,13 @@ abstract class DOMSanitizer extends HTMLSanitizer
if ((false === empty($this->GetAttrsBlackList())) if ((false === empty($this->GetAttrsBlackList()))
&& (in_array($sAttr, $this->GetAttrsBlackList(), true))) { && (in_array($sAttr, $this->GetAttrsBlackList(), true))) {
$aAttrToRemove[] = $oAttr->name; $aAttrToRemove[] = $oAttr->name;
} else if ((false === empty($this->GetTagsWhiteList())) } elseif ((false === empty($this->GetTagsWhiteList()))
&& (false === in_array($sAttr, $this->GetTagsWhiteList()[strtolower($oElement->tagName)]))) { && (false === in_array($sAttr, $this->GetTagsWhiteList()[strtolower($oElement->tagName)]))) {
$aAttrToRemove[] = $oAttr->name; $aAttrToRemove[] = $oAttr->name;
} else if (!$this->IsValidAttributeContent($sAttr, $oAttr->value)) { } elseif (!$this->IsValidAttributeContent($sAttr, $oAttr->value)) {
// Invalid content // Invalid content
$aAttrToRemove[] = $oAttr->name; $aAttrToRemove[] = $oAttr->name;
} else if ($sAttr == 'style') { } elseif ($sAttr == 'style') {
// Special processing for style tags // Special processing for style tags
$sCleanStyle = $this->CleanStyle($oAttr->value); $sCleanStyle = $this->CleanStyle($oAttr->value);
if ($sCleanStyle == '') { if ($sCleanStyle == '') {
@@ -192,17 +188,15 @@ abstract class DOMSanitizer extends HTMLSanitizer
} }
} }
// Now remove them // Now remove them
foreach($aAttrToRemove as $sName) foreach ($aAttrToRemove as $sName) {
{
$oElement->removeAttribute($sName); $oElement->removeAttribute($sName);
} }
} }
if ($oElement->hasChildNodes()) if ($oElement->hasChildNodes()) {
{ $aChildElementsToRemove = [];
$aChildElementsToRemove = array();
// Gather the child noes to remove // Gather the child noes to remove
foreach($oElement->childNodes as $oNode) { foreach ($oElement->childNodes as $oNode) {
if ($oNode instanceof DOMElement) { if ($oNode instanceof DOMElement) {
$sNodeTagName = strtolower($oNode->tagName); $sNodeTagName = strtolower($oNode->tagName);
} }
@@ -210,11 +204,11 @@ abstract class DOMSanitizer extends HTMLSanitizer
&& (false === empty($this->GetTagsBlackList())) && (false === empty($this->GetTagsBlackList()))
&& (in_array($sNodeTagName, $this->GetTagsBlackList(), true))) { && (in_array($sNodeTagName, $this->GetTagsBlackList(), true))) {
$aChildElementsToRemove[] = $oNode; $aChildElementsToRemove[] = $oNode;
} else if (($oNode instanceof DOMElement) } elseif (($oNode instanceof DOMElement)
&& (false === empty($this->GetTagsWhiteList())) && (false === empty($this->GetTagsWhiteList()))
&& (false === array_key_exists($sNodeTagName, $this->GetTagsWhiteList()))) { && (false === array_key_exists($sNodeTagName, $this->GetTagsWhiteList()))) {
$aChildElementsToRemove[] = $oNode; $aChildElementsToRemove[] = $oNode;
} else if ($oNode instanceof DOMComment) { } elseif ($oNode instanceof DOMComment) {
$aChildElementsToRemove[] = $oNode; $aChildElementsToRemove[] = $oNode;
} else { } else {
// Recurse // Recurse
@@ -225,8 +219,7 @@ abstract class DOMSanitizer extends HTMLSanitizer
} }
} }
// Now remove them // Now remove them
foreach($aChildElementsToRemove as $oDomElement) foreach ($aChildElementsToRemove as $oDomElement) {
{
$oElement->removeChild($oDomElement); $oElement->removeChild($oDomElement);
} }
} }
@@ -252,7 +245,7 @@ abstract class DOMSanitizer extends HTMLSanitizer
return $sStyle; return $sStyle;
} }
$aAllowedStyles = array(); $aAllowedStyles = [];
$aItems = explode(';', $sStyle); $aItems = explode(';', $sStyle);
{ {
foreach ($aItems as $sItem) { foreach ($aItems as $sItem) {
@@ -267,78 +260,76 @@ abstract class DOMSanitizer extends HTMLSanitizer
} }
} }
class HTMLDOMSanitizer extends DOMSanitizer class HTMLDOMSanitizer extends DOMSanitizer
{ {
/** /**
* @var array * @var array
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations * @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
*/ */
protected static $aTagsWhiteList = array( protected static $aTagsWhiteList = [
'html' => array(), 'html' => [],
'body' => array(), 'body' => [],
'a' => array('href', 'name', 'style', 'class', 'target', 'title', 'data-role', 'data-object-class', 'data-object-id', 'data-object-key'), 'a' => ['href', 'name', 'style', 'class', 'target', 'title', 'data-role', 'data-object-class', 'data-object-id', 'data-object-key'],
'p' => array('style', 'class'), 'p' => ['style', 'class'],
'blockquote' => array('style', 'class'), 'blockquote' => ['style', 'class'],
'br' => array(), 'br' => [],
'span' => array('style', 'class'), 'span' => ['style', 'class'],
'div' => array('style', 'class'), 'div' => ['style', 'class'],
'b' => array('class'), 'b' => ['class'],
'i' => array('class'), 'i' => ['class'],
'u' => array('class'), 'u' => ['class'],
'em' => array('class'), 'em' => ['class'],
'strong' => array('class'), 'strong' => ['class'],
'img' => array('src', 'style', 'class', 'alt', 'title', 'width', 'height'), 'img' => ['src', 'style', 'class', 'alt', 'title', 'width', 'height'],
'ul' => array('style', 'class'), 'ul' => ['style', 'class'],
'ol' => array('reversed', 'start', 'style', 'class', 'type'), 'ol' => ['reversed', 'start', 'style', 'class', 'type'],
'li' => array('style', 'class', 'value'), 'li' => ['style', 'class', 'value'],
'h1' => array('style', 'class'), 'h1' => ['style', 'class'],
'h2' => array('style', 'class'), 'h2' => ['style', 'class'],
'h3' => array('style', 'class'), 'h3' => ['style', 'class'],
'h4' => array('style', 'class'), 'h4' => ['style', 'class'],
'nav' => array('style', 'class'), 'nav' => ['style', 'class'],
'section' => array('style', 'class'), 'section' => ['style', 'class'],
'code' => array('style', 'class'), 'code' => ['style', 'class'],
'table' => array('style', 'class', 'width', 'summary', 'align', 'border', 'cellpadding', 'cellspacing'), 'table' => ['style', 'class', 'width', 'summary', 'align', 'border', 'cellpadding', 'cellspacing'],
'colgroup' => array(), 'colgroup' => [],
'col' => array('style'), 'col' => ['style'],
'thead' => array('style', 'class'), 'thead' => ['style', 'class'],
'tbody' => array('style', 'class'), 'tbody' => ['style', 'class'],
'tr' => array('style', 'class', 'colspan', 'rowspan'), 'tr' => ['style', 'class', 'colspan', 'rowspan'],
'td' => array('style', 'class', 'colspan', 'rowspan'), 'td' => ['style', 'class', 'colspan', 'rowspan'],
'th' => array('style', 'class', 'colspan', 'rowspan'), 'th' => ['style', 'class', 'colspan', 'rowspan'],
'fieldset' => array('style', 'class'), 'fieldset' => ['style', 'class'],
'legend' => array('style', 'class'), 'legend' => ['style', 'class'],
'font' => array('face', 'color', 'style', 'class', 'size'), 'font' => ['face', 'color', 'style', 'class', 'size'],
'big' => array(), 'big' => [],
'small' => array(), 'small' => [],
'tt' => array(), 'tt' => [],
'kbd' => array(), 'kbd' => [],
'samp' => array(), 'samp' => [],
'var' => array(), 'var' => [],
'del' => array(), 'del' => [],
's' => array(), // strikethrough 's' => [], // strikethrough
'ins' => array(), 'ins' => [],
'cite' => array(), 'cite' => [],
'q' => array(), 'q' => [],
'hr' => array('style', 'class'), 'hr' => ['style', 'class'],
'pre' => array('class'), 'pre' => ['class'],
'center' => array(), 'center' => [],
'figure' => array('style', 'class'), // Ckeditor 5 puts images in figures 'figure' => ['style', 'class'], // Ckeditor 5 puts images in figures
'figcaption' => array('class'), 'figcaption' => ['class'],
'mark' => array('class') 'mark' => ['class'],
); ];
protected static $aAttrsWhiteList = array( protected static $aAttrsWhiteList = [
'src' => '/^(http:|https:|data:)/i', 'src' => '/^(http:|https:|data:)/i',
); ];
/** /**
* @var array * @var array
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations * @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
*/ */
protected static $aStylesWhiteList = array( protected static $aStylesWhiteList = [
'aspect-ratio', 'aspect-ratio',
'background-color', 'background-color',
'border', 'border',
@@ -361,7 +352,7 @@ class HTMLDOMSanitizer extends DOMSanitizer
'vertical-align', 'vertical-align',
'width', 'width',
'white-space', 'white-space',
); ];
public function __construct($sInlineImageClassName = InlineImage::class) public function __construct($sInlineImageClassName = InlineImage::class)
{ {
@@ -431,15 +422,13 @@ class HTMLDOMSanitizer extends DOMSanitizer
// Export only the content of the body tag // Export only the content of the body tag
$sCleanHtml = $this->oDoc->saveHTML($oNodesList->item(0)); $sCleanHtml = $this->oDoc->saveHTML($oNodesList->item(0));
// remove the body tag itself // remove the body tag itself
$sCleanHtml = str_replace(array('<body>', '</body>'), '', $sCleanHtml); $sCleanHtml = str_replace(['<body>', '</body>'], '', $sCleanHtml);
} }
return $sCleanHtml; return $sCleanHtml;
} }
} }
/** /**
* @since 2.6.5 2.7.6 3.0.0 N°4360 * @since 2.6.5 2.7.6 3.0.0 N°4360
*/ */

Some files were not shown because too many files have changed in this diff Show More