From a553616ea2b7049b0639eba3b8fcd9de3e399d30 Mon Sep 17 00:00:00 2001
From: Molkobain
Date: Thu, 10 Nov 2022 10:44:51 +0100
Subject: [PATCH] =?UTF-8?q?N=C2=B05655=20-=20Introduce=20auto-routing=20me?=
=?UTF-8?q?chanism=20for=20backoffice=20pages=20(Part=201)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/composer/autoload_classmap.php | 2 +
lib/composer/autoload_static.php | 2 +
pages/UI.php | 2794 +++++------
pages/ajax.render.php | 4391 ++++++++---------
sources/Controller/AbstractController.php | 10 +-
.../Base/Layout/ObjectController.php | 13 +-
sources/Controller/iController.php | 30 +
sources/Router/Router.php | 183 +
test/sources/Router/RouterTest.php | 205 +
9 files changed, 3965 insertions(+), 3665 deletions(-)
create mode 100644 sources/Controller/iController.php
create mode 100644 sources/Router/Router.php
create mode 100644 test/sources/Router/RouterTest.php
diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php
index e43f2704e..4880cf5a7 100644
--- a/lib/composer/autoload_classmap.php
+++ b/lib/composer/autoload_classmap.php
@@ -352,6 +352,7 @@ return array(
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => $baseDir . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\OAuth\\OAuthLandingController' => $baseDir . '/sources/Controller/OAuth/OAuthLandingController.php',
'Combodo\\iTop\\Controller\\PreferencesController' => $baseDir . '/sources/Controller/PreferencesController.php',
+ 'Combodo\\iTop\\Controller\\iController' => $baseDir . '/sources/Controller/iController.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\IOAuthClientProvider' => $baseDir . '/sources/Core/Authentication/Client/OAuth/IOAuthClientProvider.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\OAuthClientProviderAbstract' => $baseDir . '/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAbstract.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\OAuthClientProviderAzure' => $baseDir . '/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAzure.php',
@@ -415,6 +416,7 @@ return array(
'Combodo\\iTop\\Renderer\\FieldRenderer' => $baseDir . '/sources/Renderer/FieldRenderer.php',
'Combodo\\iTop\\Renderer\\FormRenderer' => $baseDir . '/sources/Renderer/FormRenderer.php',
'Combodo\\iTop\\Renderer\\RenderingOutput' => $baseDir . '/sources/Renderer/RenderingOutput.php',
+ 'Combodo\\iTop\\Router\\Router' => $baseDir . '/sources/Router/Router.php',
'Combodo\\iTop\\Service\\EventData' => $baseDir . '/sources/Application/Service/EventData.php',
'Combodo\\iTop\\Service\\EventHelper' => $baseDir . '/sources/Application/Service/EventHelper.php',
'Combodo\\iTop\\Service\\EventService' => $baseDir . '/sources/Application/Service/EventService.php',
diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php
index cca9b11d4..4a4902037 100644
--- a/lib/composer/autoload_static.php
+++ b/lib/composer/autoload_static.php
@@ -717,6 +717,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\OAuth\\OAuthLandingController' => __DIR__ . '/../..' . '/sources/Controller/OAuth/OAuthLandingController.php',
'Combodo\\iTop\\Controller\\PreferencesController' => __DIR__ . '/../..' . '/sources/Controller/PreferencesController.php',
+ 'Combodo\\iTop\\Controller\\iController' => __DIR__ . '/../..' . '/sources/Controller/iController.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\IOAuthClientProvider' => __DIR__ . '/../..' . '/sources/Core/Authentication/Client/OAuth/IOAuthClientProvider.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\OAuthClientProviderAbstract' => __DIR__ . '/../..' . '/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAbstract.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\OAuthClientProviderAzure' => __DIR__ . '/../..' . '/sources/Core/Authentication/Client/OAuth/OAuthClientProviderAzure.php',
@@ -780,6 +781,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Renderer\\FieldRenderer' => __DIR__ . '/../..' . '/sources/Renderer/FieldRenderer.php',
'Combodo\\iTop\\Renderer\\FormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/FormRenderer.php',
'Combodo\\iTop\\Renderer\\RenderingOutput' => __DIR__ . '/../..' . '/sources/Renderer/RenderingOutput.php',
+ 'Combodo\\iTop\\Router\\Router' => __DIR__ . '/../..' . '/sources/Router/Router.php',
'Combodo\\iTop\\Service\\EventData' => __DIR__ . '/../..' . '/sources/Application/Service/EventData.php',
'Combodo\\iTop\\Service\\EventHelper' => __DIR__ . '/../..' . '/sources/Application/Service/EventHelper.php',
'Combodo\\iTop\\Service\\EventService' => __DIR__ . '/../..' . '/sources/Application/Service/EventService.php',
diff --git a/pages/UI.php b/pages/UI.php
index 90b4a54b2..c1e503e42 100644
--- a/pages/UI.php
+++ b/pages/UI.php
@@ -20,6 +20,7 @@ use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Controller\Base\Layout\ObjectController;
+use Combodo\iTop\Router\Router;
/**
* Displays a popup welcome message, once per session at maximum
@@ -299,15 +300,12 @@ require_once(APPROOT.'/application/wizardhelper.class.inc.php');
require_once(APPROOT.'/application/startup.inc.php');
-
try
{
- $operation = utils::ReadParam('operation', '', false, utils::ENUM_SANITIZATION_FILTER_OPERATION);
- $bPrintable = (utils::ReadParam('printable', 0) == '1');
-
$oKPI = new ExecutionKPI();
$oKPI->ComputeAndReport('Data model loaded');
+ $oKPI = new ExecutionKPI();
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
$sLoginMessage = LoginWebPage::DoLogin(); // Check user rights and prompt if needed
@@ -315,1527 +313,1549 @@ try
$oKPI->ComputeAndReport('User login');
- $oP = new iTopWebPage(Dict::S('UI:WelcomeToITop'), $bPrintable);
- $oP->SetMessage($sLoginMessage);
+ // First check if we can redirect the route to a dedicated controller
+ $sRoute = utils::ReadParam('route', '', false, utils::ENUM_SANITIZATION_FILTER_ROUTE);
+ $oRouter = Router::GetInstance();
+ if ($oRouter->CanDispatchRoute($sRoute)) {
+ $mResponse = $oRouter->DispatchRoute($sRoute);
- // All the following actions use advanced forms that require more javascript to be loaded
- switch($operation)
- {
- case 'new': // Form to create a new object
- case 'apply_new': // Creation of a new object
- case 'apply_modify': // Applying the modifications to an existing object
- case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
- case 'bulk_stimulus': // For to apply a stimulus to multiple objects
- case 'stimulus': // Form displayed when applying a stimulus (state change)
- case 'apply_stimulus': // Form displayed when applying a stimulus (state change)
- foreach (ObjectController::EnumRequiredForModificationJsFilesRelPaths() as $sJsFileRelPath) {
- $oP->add_linked_script("../$sJsFileRelPath");
- }
- break;
+ // If response isn't a \WebPage, it is most likely that the output already occured, stop the script.
+ // Note that this is done here and not directly in the Router::DispatchRoute() so custom endpoint can handle null responses their own way.
+ if (false === ($mResponse instanceof WebPage)) {
+ die();
+ }
+
+ // Response is a \WebPage, let's handle it like legacy operations
+ $oP = $mResponse;
+ // TODO 3.1: If no route match, die instead of fallback to legacy operation dispatch and dump available routes if in dev env.
}
-
- switch($operation)
- {
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'details': // Details of an object
- $sClass = utils::ReadParam('class', '', false, 'class');
+ // Otherwise, use legacy operation
+ else {
+ $operation = utils::ReadParam('operation', '', false, utils::ENUM_SANITIZATION_FILTER_OPERATION);
+ $bPrintable = (utils::ReadParam('printable', 0) == '1');
- if (empty($sClass)) {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
- }
+ $oP = new iTopWebPage(Dict::S('UI:WelcomeToITop'), $bPrintable);
+ $oP->SetMessage($sLoginMessage);
- $id = utils::ReadParam('id', null);
- if (false === is_null($id)) {
- if (is_numeric($id)) {
- $oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
+ // All the following actions use advanced forms that require more javascript to be loaded
+ switch($operation)
+ {
+ case 'new': // Form to create a new object
+ case 'apply_new': // Creation of a new object
+ case 'apply_modify': // Applying the modifications to an existing object
+ case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
+ case 'bulk_stimulus': // For to apply a stimulus to multiple objects
+ case 'stimulus': // Form displayed when applying a stimulus (state change)
+ case 'apply_stimulus': // Form displayed when applying a stimulus (state change)
+ foreach (ObjectController::EnumRequiredForModificationJsFilesRelPaths() as $sJsFileRelPath) {
+ $oP->add_linked_script("../$sJsFileRelPath");
+ }
+ break;
+ }
+
+ switch($operation)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'details': // Details of an object
+ $sClass = utils::ReadParam('class', '', false, 'class');
+
+ if (empty($sClass)) {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
+ }
+
+ $id = utils::ReadParam('id', null);
+ if (false === is_null($id)) {
+ if (is_numeric($id)) {
+ $oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
+ } else {
+ $oObj = MetaModel::GetObjectByName($sClass, $id, false /* MustBeFound */);
+ }
} else {
- $oObj = MetaModel::GetObjectByName($sClass, $id, false /* MustBeFound */);
- }
- } else {
- $sAttCode = utils::ReadParam('attcode', '', false, utils::ENUM_SANITIZATION_FILTER_FIELD_NAME);
- $sAttValue = utils::ReadParam('attvalue', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
+ $sAttCode = utils::ReadParam('attcode', '', false, utils::ENUM_SANITIZATION_FILTER_FIELD_NAME);
+ $sAttValue = utils::ReadParam('attvalue', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
- if ((strlen($sAttCode) === 0) || (strlen($sAttValue) === 0)) {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'id'));
+ if ((strlen($sAttCode) === 0) || (strlen($sAttValue) === 0)) {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'id'));
+ }
+
+ $oObj = MetaModel::GetObjectByColumn($sClass, $sAttCode, $sAttValue, true);
}
- $oObj = MetaModel::GetObjectByColumn($sClass, $sAttCode, $sAttValue, true);
- }
-
- if (is_null($oObj)) {
- // Check anyhow if there is a message for this object (like you've just created it)
- $sMessageKey = $sClass.'::'.$id;
- DisplayMessages($sMessageKey, $oP);
- $oP->set_title(Dict::S('UI:ErrorPageTitle'));
-
- // Attempt to load the object in archive mode
- utils::PushArchiveMode(true);
- if (is_numeric($id)) {
- $oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
- }
- else
- {
- $oObj = MetaModel::GetObjectByName($sClass, $id, false /* MustBeFound */);
- }
- utils::PopArchiveMode();
- if (is_null($oObj))
- {
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
- }
- else
- {
- SetObjectBreadCrumbEntry($oObj, $oP);
- $oP->P(Dict::S('UI:ObjectArchived'));
- }
- }
- else
- {
- try
- {
- $oObj->Reload();
- }
- catch(Exception $e)
- {
- // Probably not allowed to see this instance of a derived class
-
+ if (is_null($oObj)) {
// Check anyhow if there is a message for this object (like you've just created it)
$sMessageKey = $sClass.'::'.$id;
DisplayMessages($sMessageKey, $oP);
-
- $oObj = null;
$oP->set_title(Dict::S('UI:ErrorPageTitle'));
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
- }
- if (!is_null($oObj))
- {
- SetObjectBreadCrumbEntry($oObj, $oP);
- // The object could be listed, check if it is actually allowed to view it
- $oSet = CMDBObjectSet::FromObject($oObj);
- if (UserRights::IsActionAllowed($sClass, UR_ACTION_READ, $oSet) == UR_ALLOWED_NO) {
- throw new SecurityException('User not allowed to view this object', array('class' => $sClass, 'id' => $id));
+ // Attempt to load the object in archive mode
+ utils::PushArchiveMode(true);
+ if (is_numeric($id)) {
+ $oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
}
-
- $sClassLabel = MetaModel::GetName($sClass);
- $oP->set_title(Dict::Format('UI:DetailsPageTitle', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
- $oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObj, $oP->IsPrintableVersion() ? cmdbAbstractObject::ENUM_DISPLAY_MODE_PRINT : cmdbAbstractObject::ENUM_DISPLAY_MODE_VIEW));
- $oObj->DisplayDetails($oP);
- }
- }
- break;
-
- case 'release_lock_and_details':
- $oP->DisableBreadCrumb();
-
- // Retrieve object
- $sClass = utils::ReadParam('class', '', false, 'class');
- $id = utils::ReadParam('id', '');
- $oObj = MetaModel::GetObject($sClass, $id);
-
- // Retrieve ownership token
- $sToken = utils::ReadParam('token', '');
- if ($sToken != '')
- {
- iTopOwnershipLock::ReleaseLock($sClass, $id, $sToken);
- }
-
- $oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObj, cmdbAbstractObject::ENUM_DISPLAY_MODE_VIEW));
- cmdbAbstractObject::ReloadAndDisplay($oP, $oObj, array('operation' => 'details'));
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'search_oql': // OQL query
- $sOQLClass = utils::ReadParam('oql_class', '', false, 'class');
- $sBaseClass = utils::ReadParam('base_class', $sOQLClass, false, 'class');
- $sOQLClause = utils::ReadParam('oql_clause', '', false, 'raw_data');
- $sFormat = utils::ReadParam('format', '');
- $bSearchForm = utils::ReadParam('search_form', true);
- $sTitle = utils::ReadParam('title', 'UI:SearchResultsPageTitle');
- if (empty($sOQLClass))
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'oql_class'));
- }
- $oP->set_title(Dict::S($sTitle));
- $oP->add(''.Dict::S($sTitle).' ');
- $sOQL = "SELECT $sOQLClass $sOQLClause";
- try
- {
- $oFilter = DBObjectSearch::FromOQL($sOQL);
- DisplaySearchSet($oP, $oFilter, $bSearchForm, $sBaseClass, $sFormat);
- }
- catch(CoreException $e)
- {
- $oFilter = new DBObjectSearch($sOQLClass);
- $oSet = new DBObjectSet($oFilter);
- if ($bSearchForm)
- {
- $oBlock = new DisplayBlock($oFilter, 'search', false);
- $oBlock->Display($oP, 0, array('table_id' => 'search-widget-result-outer'));
- }
- $oP->add('');
- }
- catch(Exception $e)
- {
- $oP->P(''.Dict::Format('UI:Error:AnErrorOccuredWhileRunningTheQuery_Message', $e->getMessage()).' ');
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'search_form': // Search form
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sFormat = utils::ReadParam('format', 'html');
- $bSearchForm = utils::ReadParam('search_form', true);
- $bDoSearch = utils::ReadParam('do_search', true);
- if (empty($sClass))
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
- }
- $oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
- $oFilter = new DBObjectSearch($sClass);
- DisplaySearchSet($oP, $oFilter, $bSearchForm, '' /* sBaseClass */, $sFormat, $bDoSearch, true /* Search Form Expanded */);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'search': // Serialized DBSearch
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $sFormat = utils::ReadParam('format', '');
- $bSearchForm = utils::ReadParam('search_form', true);
- if (empty($sFilter))
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
- }
- $oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
- $oFilter = DBSearch::unserialize($sFilter); // TO DO : check that the filter is valid
- $oFilter->UpdateContextFromUser();
- DisplaySearchSet($oP, $oFilter, $bSearchForm, '' /* sBaseClass */, $sFormat);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'full_text': // Global "google-like" search
- $oP->DisableBreadCrumb();
- $sQuery = trim(utils::ReadParam('text', '', false, 'raw_data'));
- $iTune = utils::ReadParam('tune', 0);
- if (empty($sQuery))
- {
- $oP->p(Dict::S('UI:Search:NoSearch'));
- }
- else
- {
- $iErrors = 0;
- $sFullText = $sQuery;
-
- // Check if a class name/label is supplied to limit the search
- $sClassName = '';
- if (preg_match('/^([^\"]+):(.+)$/', $sFullText, $aMatches))
- {
- $sClassName = $aMatches[1];
- if (MetaModel::IsValidClass($sClassName))
+ else
{
- $sFullText = trim($aMatches[2]);
+ $oObj = MetaModel::GetObjectByName($sClass, $id, false /* MustBeFound */);
}
- elseif ($sClassName = MetaModel::GetClassFromLabel($sClassName, false /* => not case sensitive */))
+ utils::PopArchiveMode();
+ if (is_null($oObj))
{
- $sFullText = trim($aMatches[2]);
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
+ }
+ else
+ {
+ SetObjectBreadCrumbEntry($oObj, $oP);
+ $oP->P(Dict::S('UI:ObjectArchived'));
}
- }
- if (preg_match('/^"(.*)"$/', $sFullText, $aMatches))
- {
- // The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
- $aFullTextNeedles = array($aMatches[1]);
}
else
- {
- // Split the text on the blanks and treat this as a search for AND AND
- $aExplodedFullTextNeedles = explode(' ', $sFullText);
- $aFullTextNeedles = [];
- foreach ($aExplodedFullTextNeedles as $sValue) {
- if (strlen($sValue) > 0) {
- $aFullTextNeedles[] = $sValue;
- }
- }
- }
-
- // Save search to history
- // - Prepare icon
- $sQueryIconUrl = null;
- if(!empty($sClassName)) {
- $sQueryIconUrl = MetaModel::GetClassIcon($sClassName, false);
- }
- // - Prepare label
- $sQueryLabel = null;
- if ($sQuery !== $sFullText) {
- $sQueryLabel = $sFullText;
- }
- GlobalSearchHelper::AddQueryToHistory($sQuery, $sQueryIconUrl, $sQueryLabel);
- $oP->SetBlockParam('ibo-global-search.sQuery', $sQuery);
-
- // Check the needle length
- $iMinLenth = MetaModel::GetConfig()->Get('full_text_needle_min');
- foreach ($aFullTextNeedles as $sNeedle) {
- if (strlen($sNeedle) < $iMinLenth) {
- $oP->p(Dict::Format('UI:Search:NeedleTooShort', $sNeedle, $iMinLenth));
- $key = array_search($sNeedle, $aFullTextNeedles);
- if ($key !== false)
- {
- unset($aFullTextNeedles[$key]);
- }
- }
- }
- if(empty($aFullTextNeedles))
- {
- $oP->p(Dict::S('UI:Search:NoSearch'));
- break;
- }
- $sFullText = implode(' ', $aFullTextNeedles);
-
- // Sanity check of the accelerators
- /** @var array $aAccelerators */
- $aAccelerators = MetaModel::GetConfig()->Get('full_text_accelerators');
- foreach ($aAccelerators as $sClass => $aAccelerator)
{
try
{
- $bSkip = array_key_exists('skip', $aAccelerator) ? $aAccelerator['skip'] : false;
- if (!$bSkip)
+ $oObj->Reload();
+ }
+ catch(Exception $e)
+ {
+ // Probably not allowed to see this instance of a derived class
+
+ // Check anyhow if there is a message for this object (like you've just created it)
+ $sMessageKey = $sClass.'::'.$id;
+ DisplayMessages($sMessageKey, $oP);
+
+ $oObj = null;
+ $oP->set_title(Dict::S('UI:ErrorPageTitle'));
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
+ }
+ if (!is_null($oObj))
+ {
+ SetObjectBreadCrumbEntry($oObj, $oP);
+
+ // The object could be listed, check if it is actually allowed to view it
+ $oSet = CMDBObjectSet::FromObject($oObj);
+ if (UserRights::IsActionAllowed($sClass, UR_ACTION_READ, $oSet) == UR_ALLOWED_NO) {
+ throw new SecurityException('User not allowed to view this object', array('class' => $sClass, 'id' => $id));
+ }
+
+ $sClassLabel = MetaModel::GetName($sClass);
+ $oP->set_title(Dict::Format('UI:DetailsPageTitle', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
+ $oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObj, $oP->IsPrintableVersion() ? cmdbAbstractObject::ENUM_DISPLAY_MODE_PRINT : cmdbAbstractObject::ENUM_DISPLAY_MODE_VIEW));
+ $oObj->DisplayDetails($oP);
+ }
+ }
+ break;
+
+ case 'release_lock_and_details':
+ $oP->DisableBreadCrumb();
+
+ // Retrieve object
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $id = utils::ReadParam('id', '');
+ $oObj = MetaModel::GetObject($sClass, $id);
+
+ // Retrieve ownership token
+ $sToken = utils::ReadParam('token', '');
+ if ($sToken != '')
+ {
+ iTopOwnershipLock::ReleaseLock($sClass, $id, $sToken);
+ }
+
+ $oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObj, cmdbAbstractObject::ENUM_DISPLAY_MODE_VIEW));
+ cmdbAbstractObject::ReloadAndDisplay($oP, $oObj, array('operation' => 'details'));
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'search_oql': // OQL query
+ $sOQLClass = utils::ReadParam('oql_class', '', false, 'class');
+ $sBaseClass = utils::ReadParam('base_class', $sOQLClass, false, 'class');
+ $sOQLClause = utils::ReadParam('oql_clause', '', false, 'raw_data');
+ $sFormat = utils::ReadParam('format', '');
+ $bSearchForm = utils::ReadParam('search_form', true);
+ $sTitle = utils::ReadParam('title', 'UI:SearchResultsPageTitle');
+ if (empty($sOQLClass))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'oql_class'));
+ }
+ $oP->set_title(Dict::S($sTitle));
+ $oP->add(''.Dict::S($sTitle).' ');
+ $sOQL = "SELECT $sOQLClass $sOQLClause";
+ try
+ {
+ $oFilter = DBObjectSearch::FromOQL($sOQL);
+ DisplaySearchSet($oP, $oFilter, $bSearchForm, $sBaseClass, $sFormat);
+ }
+ catch(CoreException $e)
+ {
+ $oFilter = new DBObjectSearch($sOQLClass);
+ $oSet = new DBObjectSet($oFilter);
+ if ($bSearchForm)
+ {
+ $oBlock = new DisplayBlock($oFilter, 'search', false);
+ $oBlock->Display($oP, 0, array('table_id' => 'search-widget-result-outer'));
+ }
+ $oP->add('');
+ }
+ catch(Exception $e)
+ {
+ $oP->P(''.Dict::Format('UI:Error:AnErrorOccuredWhileRunningTheQuery_Message', $e->getMessage()).' ');
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'search_form': // Search form
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sFormat = utils::ReadParam('format', 'html');
+ $bSearchForm = utils::ReadParam('search_form', true);
+ $bDoSearch = utils::ReadParam('do_search', true);
+ if (empty($sClass))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
+ }
+ $oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
+ $oFilter = new DBObjectSearch($sClass);
+ DisplaySearchSet($oP, $oFilter, $bSearchForm, '' /* sBaseClass */, $sFormat, $bDoSearch, true /* Search Form Expanded */);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'search': // Serialized DBSearch
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ $sFormat = utils::ReadParam('format', '');
+ $bSearchForm = utils::ReadParam('search_form', true);
+ if (empty($sFilter))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
+ }
+ $oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
+ $oFilter = DBSearch::unserialize($sFilter); // TO DO : check that the filter is valid
+ $oFilter->UpdateContextFromUser();
+ DisplaySearchSet($oP, $oFilter, $bSearchForm, '' /* sBaseClass */, $sFormat);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'full_text': // Global "google-like" search
+ $oP->DisableBreadCrumb();
+ $sQuery = trim(utils::ReadParam('text', '', false, 'raw_data'));
+ $iTune = utils::ReadParam('tune', 0);
+ if (empty($sQuery))
+ {
+ $oP->p(Dict::S('UI:Search:NoSearch'));
+ }
+ else
+ {
+ $iErrors = 0;
+ $sFullText = $sQuery;
+
+ // Check if a class name/label is supplied to limit the search
+ $sClassName = '';
+ if (preg_match('/^([^\"]+):(.+)$/', $sFullText, $aMatches))
+ {
+ $sClassName = $aMatches[1];
+ if (MetaModel::IsValidClass($sClassName))
{
- $oSearch = DBObjectSearch::FromOQL($aAccelerator['query']);
- if ($sClass != $oSearch->GetClass())
- {
- $oP->p("Full text accelerator for class '$sClass': searched class mismatch (".$oSearch->GetClass().")");
- $iErrors++;
+ $sFullText = trim($aMatches[2]);
+ }
+ elseif ($sClassName = MetaModel::GetClassFromLabel($sClassName, false /* => not case sensitive */))
+ {
+ $sFullText = trim($aMatches[2]);
+ }
+ }
+ if (preg_match('/^"(.*)"$/', $sFullText, $aMatches))
+ {
+ // The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
+ $aFullTextNeedles = array($aMatches[1]);
+ }
+ else
+ {
+ // Split the text on the blanks and treat this as a search for AND AND
+ $aExplodedFullTextNeedles = explode(' ', $sFullText);
+ $aFullTextNeedles = [];
+ foreach ($aExplodedFullTextNeedles as $sValue) {
+ if (strlen($sValue) > 0) {
+ $aFullTextNeedles[] = $sValue;
}
}
}
- catch (OqlException $e)
+
+ // Save search to history
+ // - Prepare icon
+ $sQueryIconUrl = null;
+ if(!empty($sClassName)) {
+ $sQueryIconUrl = MetaModel::GetClassIcon($sClassName, false);
+ }
+ // - Prepare label
+ $sQueryLabel = null;
+ if ($sQuery !== $sFullText) {
+ $sQueryLabel = $sFullText;
+ }
+ GlobalSearchHelper::AddQueryToHistory($sQuery, $sQueryIconUrl, $sQueryLabel);
+ $oP->SetBlockParam('ibo-global-search.sQuery', $sQuery);
+
+ // Check the needle length
+ $iMinLenth = MetaModel::GetConfig()->Get('full_text_needle_min');
+ foreach ($aFullTextNeedles as $sNeedle) {
+ if (strlen($sNeedle) < $iMinLenth) {
+ $oP->p(Dict::Format('UI:Search:NeedleTooShort', $sNeedle, $iMinLenth));
+ $key = array_search($sNeedle, $aFullTextNeedles);
+ if ($key !== false)
+ {
+ unset($aFullTextNeedles[$key]);
+ }
+ }
+ }
+ if(empty($aFullTextNeedles))
{
- $oP->p("Full text accelerator for class '$sClass': ".$e->getHtmlDesc());
- $iErrors++;
+ $oP->p(Dict::S('UI:Search:NoSearch'));
+ break;
+ }
+ $sFullText = implode(' ', $aFullTextNeedles);
+
+ // Sanity check of the accelerators
+ /** @var array $aAccelerators */
+ $aAccelerators = MetaModel::GetConfig()->Get('full_text_accelerators');
+ foreach ($aAccelerators as $sClass => $aAccelerator)
+ {
+ try
+ {
+ $bSkip = array_key_exists('skip', $aAccelerator) ? $aAccelerator['skip'] : false;
+ if (!$bSkip)
+ {
+ $oSearch = DBObjectSearch::FromOQL($aAccelerator['query']);
+ if ($sClass != $oSearch->GetClass())
+ {
+ $oP->p("Full text accelerator for class '$sClass': searched class mismatch (".$oSearch->GetClass().")");
+ $iErrors++;
+ }
+ }
+ }
+ catch (OqlException $e)
+ {
+ $oP->p("Full text accelerator for class '$sClass': ".$e->getHtmlDesc());
+ $iErrors++;
+ }
+ }
+
+ if ($iErrors == 0)
+ {
+ $oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
+ $sPageId = "ui-global-search";
+ $sLabel = Dict::S('UI:SearchResultsTitle');
+ $sDescription = Dict::S('UI:SearchResultsTitle+');
+ $oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription, '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
+ $oP->add("\n");
+ $oP->add("\n");
+ $oP->add("
\n");
+ $oP->add("
\n");
+ $oP->add("
".Dict::Format('UI:FullTextSearchTitle_Text', utils::EscapeHtml($sFullText))." ");
+ $oP->add("
\n");
+ $oP->add("
\n");
+ $sJSClass = addslashes($sClassName);
+ $sJSNeedles = json_encode($aFullTextNeedles);
+ $oP->add_ready_script(
+ << 0)
+ {
+ $oP->add_script("var oTimeStatistics = {};");
+ }
}
}
+ break;
- if ($iErrors == 0)
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ /** @deprecated 3.1.0 Use the "object.modify" route instead */
+ // Kept for backward compatibility with notification URLs, don't remove
+ case 'modify': // Legacy operation
+ $oController = new ObjectController();
+ $oP = $oController->OperationModify();
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'select_for_modify_all': // Select the list of objects to be modified (bulk modify)
+ UI::OperationSelectForModifyAll($oP);
+ break;
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
+ UI::OperationFormForModifyAll($oP, $oAppContext);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'preview_or_modify_all': // Preview or apply bulk modify
+ UI::OperationPreviewOrModifyAll($oP, $oAppContext);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'new': // Form to create a new object
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sStateCode = utils::ReadParam('state', '');
+ $bCheckSubClass = utils::ReadParam('checkSubclass', true);
+ if ( empty($sClass) )
{
- $oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
- $sPageId = "ui-global-search";
- $sLabel = Dict::S('UI:SearchResultsTitle');
- $sDescription = Dict::S('UI:SearchResultsTitle+');
- $oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription, '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
- $oP->add("\n");
- $oP->add("\n");
- $oP->add("
\n");
- $oP->add("
\n");
- $oP->add("
".Dict::Format('UI:FullTextSearchTitle_Text', utils::EscapeHtml($sFullText))." ");
- $oP->add("
\n");
- $oP->add("
\n");
- $sJSClass = addslashes($sClassName);
- $sJSNeedles = json_encode($aFullTextNeedles);
- $oP->add_ready_script(
- <<GetAsHash();
+ foreach( $oAppContext->GetNames() as $key)
+ {
+ $aArgs[$key] = $oAppContext->GetCurrentValue($key);
+ }
+ */
+ // If the specified class has subclasses, ask the user an instance of which class to create
+ $aSubClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
+ $aPossibleClasses = array();
+ $sRealClass = '';
+ if ($bCheckSubClass)
+ {
+ foreach($aSubClasses as $sCandidateClass)
+ {
+ if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
+ {
+ $aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
+ }
+ }
+ // Only one of the subclasses can be instantiated...
+ if (count($aPossibleClasses) == 1)
+ {
+ $aKeys = array_keys($aPossibleClasses);
+ $sRealClass = $aKeys[0];
+ }
+ }
+ else
+ {
+ $sRealClass = $sClass;
+ }
+
+ if (!empty($sRealClass))
+ {
+ // Set all the default values in an object and clone this "default" object
+ $oObjToClone = MetaModel::NewObject($sRealClass);
+ // 1st - set context values
+ $oAppContext->InitObjectFromContext($oObjToClone);
+ // 2nd - set values from the page argument 'default'
+ $oObjToClone->UpdateObjectFromArg('default');
+ $aPrefillFormParam = array(
+ 'user' => Session::Get('auth_user'),
+ 'context' => $oAppContext->GetAsHash(),
+ 'default' => utils::ReadParam('default', array(), '', 'raw_data'),
+ 'origin' => 'console',
);
- if ($iTune > 0)
+ // 3rd - prefill API
+ $oObjToClone->PrefillForm('creation_from_0', $aPrefillFormParam);
+
+ // Display the creation form
+ $sClassLabel = MetaModel::GetName($sRealClass);
+ $sClassIcon = MetaModel::GetClassIcon($sRealClass);
+ $sObjectTmpKey = $oObjToClone->GetKey();
+ $sHeaderTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
+ // Note: some code has been duplicated to the case 'apply_new' when a data integrity issue has been found
+ $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
+ $oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObjToClone, cmdbAbstractObject::ENUM_DISPLAY_MODE_CREATE));
+ cmdbAbstractObject::DisplayCreationForm($oP, $sRealClass, $oObjToClone, array(), array('wizard_container' => 1, 'keep_source_object' => true)); // wizard_container: Display the title above the form
+ } else {
+ // Select the derived class to create
+ cmdbAbstractObject::DisplaySelectClassToCreate($sClass, $oP, $oAppContext, $aPossibleClasses,['state' => $sStateCode]);
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'apply_modify': // Applying the modifications to an existing object
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadPostedParam('class', '', 'class');
+ $sClassLabel = MetaModel::GetName($sClass);
+ $id = utils::ReadPostedParam('id', '');
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
+ if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
+ {
+ IssueLog::Trace('Object not updated (empty class or id)', $sClass, array(
+ '$operation' => $operation,
+ '$id' => $id,
+ '$sTransactionId' => $sTransactionId,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+
+ throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
+ }
+ $bDisplayDetails = true;
+ $oObj = MetaModel::GetObject($sClass, $id, false);
+ if ($oObj == null)
+ {
+ $bDisplayDetails = false;
+ $oP->set_title(Dict::S('UI:ErrorPageTitle'));
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
+
+ IssueLog::Trace('Object not updated (id not found)', $sClass, array(
+ '$operation' => $operation,
+ '$id' => $id,
+ '$sTransactionId' => $sTransactionId,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+ }
+ elseif (!utils::IsTransactionValid($sTransactionId, false))
+ {
+ //TODO: since $bDisplayDetails= true, there will be an redirection, thus, the content generated here is ignored, only the $sMessage and $sSeverity are used afeter the redirection
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
+ $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
+ $oP->p("".Dict::S('UI:Error:ObjectAlreadyUpdated')." \n");
+ $sMessage = Dict::Format('UI:Error:ObjectAlreadyUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'error';
+
+ IssueLog::Trace('Object not updated (invalid transaction_id)', $sClass, array(
+ '$operation' => $operation,
+ '$id' => $id,
+ '$sTransactionId' => $sTransactionId,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+ }
+ else
+ {
+ $aErrors = $oObj->UpdateObjectFromPostedForm();
+ $sMessage = '';
+ $sSeverity = 'ok';
+
+ if (!$oObj->IsModified() && empty($aErrors))
{
- $oP->add_script("var oTimeStatistics = {};");
+ $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
+ $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'info';
+
+ IssueLog::Trace('Object not updated (see either $aErrors or IsModified)', $sClass, array(
+ '$operation' => $operation,
+ '$id' => $id,
+ '$sTransactionId' => $sTransactionId,
+ '$aErrors' => $aErrors,
+ 'IsModified' => $oObj->IsModified(),
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+ }
+ else
+ {
+ IssueLog::Trace('Object updated', $sClass, array(
+ '$operation' => $operation,
+ '$id' => $id,
+ '$sTransactionId' => $sTransactionId,
+ '$aErrors' => $aErrors,
+ 'IsModified' => $oObj->IsModified(),
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+
+ try
+ {
+ if (!empty($aErrors))
+ {
+ throw new CoreCannotSaveObjectException(array('id' => $oObj->GetKey(), 'class' => $sClass, 'issues' => $aErrors));
+ }
+ // Transactions are now handled in DBUpdate
+ $oObj->DBUpdate();
+ $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'ok';
+ }
+ catch (CoreCannotSaveObjectException $e)
+ {
+ // Found issues, explain and give the user a second chance
+ //
+ $bDisplayDetails = false;
+ $aIssues = $e->getIssues();
+ $oP->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
+ $oObj->DisplayModifyForm($oP,
+ array('wizard_container' => true)); // wizard_container: display the wizard border and the title
+ }
+ catch (DeleteException $e)
+ {
+ // Say two things:
+ // - 1) Don't be afraid nothing was modified
+ $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'info';
+ cmdbAbstractObject::SetSessionMessage(get_class($oObj), $oObj->GetKey(), 'UI:Class_Object_NotUpdated', $sMessage,
+ $sSeverity, 0, true /* must not exist */);
+ // - 2) Ok, there was some trouble indeed
+ $sMessage = $e->getMessage();
+ $sSeverity = 'error';
+ }
+ utils::RemoveTransaction($sTransactionId);
}
}
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'modify': // Legacy operation
- /** @internal */
- case 'object.modify': // New operation
- $oController = new ObjectController();
- $oP = $oController->Modify();
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'select_for_modify_all': // Select the list of objects to be modified (bulk modify)
- UI::OperationSelectForModifyAll($oP);
- break;
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
- UI::OperationFormForModifyAll($oP, $oAppContext);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'preview_or_modify_all': // Preview or apply bulk modify
- UI::OperationPreviewOrModifyAll($oP, $oAppContext);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'new': // Form to create a new object
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sStateCode = utils::ReadParam('state', '');
- $bCheckSubClass = utils::ReadParam('checkSubclass', true);
- if ( empty($sClass) )
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
- }
-
-/*
- $aArgs = utils::ReadParam('default', array(), false, 'raw_data');
- $aContext = $oAppContext->GetAsHash();
- foreach( $oAppContext->GetNames() as $key)
- {
- $aArgs[$key] = $oAppContext->GetCurrentValue($key);
- }
-*/
- // If the specified class has subclasses, ask the user an instance of which class to create
- $aSubClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
- $aPossibleClasses = array();
- $sRealClass = '';
- if ($bCheckSubClass)
- {
- foreach($aSubClasses as $sCandidateClass)
+ if ($bDisplayDetails)
{
- if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
+ $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey()); //Workaround: reload the object so that the linkedset are displayed properly
+ $sNextAction = utils::ReadPostedParam('next_action', '');
+ if (!empty($sNextAction))
{
- $aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
+ try
+ {
+ ApplyNextAction($oP, $oObj, $sNextAction);
+ }
+ catch (ApplicationException $e)
+ {
+ $sMessage = $e->getMessage();
+ $sSeverity = 'info';
+ ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
+ }
+ }
+ else
+ {
+ // Nothing more to do
+ $sMessage = isset($sMessage) ? $sMessage : '';
+ $sSeverity = isset($sSeverity) ? $sSeverity : null;
+ ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
+ }
+
+ $bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
+ if ($bLockEnabled)
+ {
+ // Release the concurrent lock, if any
+ $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
+ if ($sOwnershipToken !== null)
+ {
+ // We're done, let's release the lock
+ iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
+ }
}
}
- // Only one of the subclasses can be instantiated...
- if (count($aPossibleClasses) == 1)
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'select_for_deletion': // Select multiple objects for deletion
+ $oP->DisableBreadCrumb();
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ if (empty($sFilter))
{
- $aKeys = array_keys($aPossibleClasses);
- $sRealClass = $aKeys[0];
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
}
- }
- else
- {
- $sRealClass = $sClass;
- }
-
- if (!empty($sRealClass))
- {
- // Set all the default values in an object and clone this "default" object
- $oObjToClone = MetaModel::NewObject($sRealClass);
- // 1st - set context values
- $oAppContext->InitObjectFromContext($oObjToClone);
- // 2nd - set values from the page argument 'default'
- $oObjToClone->UpdateObjectFromArg('default');
- $aPrefillFormParam = array(
- 'user' => Session::Get('auth_user'),
- 'context' => $oAppContext->GetAsHash(),
- 'default' => utils::ReadParam('default', array(), '', 'raw_data'),
- 'origin' => 'console',
- );
- // 3rd - prefill API
- $oObjToClone->PrefillForm('creation_from_0', $aPrefillFormParam);
+ $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
- // Display the creation form
- $sClassLabel = MetaModel::GetName($sRealClass);
- $sClassIcon = MetaModel::GetClassIcon($sRealClass);
- $sObjectTmpKey = $oObjToClone->GetKey();
- $sHeaderTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
- // Note: some code has been duplicated to the case 'apply_new' when a data integrity issue has been found
- $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
- $oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObjToClone, cmdbAbstractObject::ENUM_DISPLAY_MODE_CREATE));
- cmdbAbstractObject::DisplayCreationForm($oP, $sRealClass, $oObjToClone, array(), array('wizard_container' => 1, 'keep_source_object' => true)); // wizard_container: Display the title above the form
- } else {
- // Select the derived class to create
- cmdbAbstractObject::DisplaySelectClassToCreate($sClass, $oP, $oAppContext, $aPossibleClasses,['state' => $sStateCode]);
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
+ $oFilter = DBSearch::unserialize($sFilter); // TO DO : check that the filter is valid
+ $oFilter->UpdateContextFromUser();
- case 'apply_modify': // Applying the modifications to an existing object
+ $sClass = $oFilter->GetClass();
+
+ $aDisplayParams = [
+ 'icon' => MetaModel::GetClassIcon($sClass, false),
+ 'title' => Dict::S('UI:BulkDeleteTitle'),
+ ];
+ $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_DELETE);
+ DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_delete', $oChecker, [], $aDisplayParams);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'bulk_delete_confirmed': // Confirm bulk deletion of objects
+ $oP->DisableBreadCrumb();
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
+ if (!utils::IsTransactionValid($sTransactionId))
+ {
+ $sUser = UserRights::GetUser();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
+ throw new ApplicationException(Dict::S('UI:Error:ObjectsAlreadyDeleted'));
+ }
+ // Fall through
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'delete':
+ case 'bulk_delete': // Actual bulk deletion (if confirmed)
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sClassLabel = MetaModel::GetName($sClass);
+ $aObjects = array();
+ if ($operation == 'delete')
+ {
+ // Single object
+ $id = utils::ReadParam('id', '');
+ $oObj = MetaModel::GetObject($sClass, $id);
+ $aObjects[] = $oObj;
+ if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromObject($oObj)))
+ {
+ throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClassLabel));
+ }
+ }
+ else
+ {
+ // Several objects
+ $sFilter = utils::ReadPostedParam('filter', '', 'raw_data');
+ $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
+ // Add user filter
+ $oFullSetFilter->UpdateContextFromUser();
+ $aSelectObject = utils::ReadMultipleSelection($oFullSetFilter);
+ if ( empty($sClass) || empty($aSelectObject)) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObject[]'));
+ }
+ foreach($aSelectObject as $iId)
+ {
+ $aObjects[] = MetaModel::GetObject($sClass, $iId);
+ }
+ if (count($aObjects) == 1)
+ {
+ if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
+ {
+ throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
+ }
+ }
+ else
+ {
+ if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
+ {
+ throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
+ }
+ $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
+ }
+ }
+ // Go for the common part... (delete single, delete bulk, delete confirmed)
+ cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed');
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'apply_new': // Creation of a new object
$oP->DisableBreadCrumb();
$sClass = utils::ReadPostedParam('class', '', 'class');
$sClassLabel = MetaModel::GetName($sClass);
- $id = utils::ReadPostedParam('id', '');
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
- if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
+ $aErrors = array();
+ $aWarnings = array();
+ if ( empty($sClass) ) // TO DO: check that the class name is valid !
{
- IssueLog::Trace('Object not updated (empty class or id)', $sClass, array(
- '$operation' => $operation,
- '$id' => $id,
- '$sTransactionId' => $sTransactionId,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
+ IssueLog::Trace('Object not created (empty class)', $sClass, array(
+ '$operation' => $operation,
+ '$sTransactionId' => $sTransactionId,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
- throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
}
- $bDisplayDetails = true;
- $oObj = MetaModel::GetObject($sClass, $id, false);
- if ($oObj == null)
+ if (!utils::IsTransactionValid($sTransactionId, false))
{
- $bDisplayDetails = false;
- $oP->set_title(Dict::S('UI:ErrorPageTitle'));
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
-
- IssueLog::Trace('Object not updated (id not found)', $sClass, array(
- '$operation' => $operation,
- '$id' => $id,
- '$sTransactionId' => $sTransactionId,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
- }
- elseif (!utils::IsTransactionValid($sTransactionId, false))
- {
- //TODO: since $bDisplayDetails= true, there will be an redirection, thus, the content generated here is ignored, only the $sMessage and $sSeverity are used afeter the redirection
$sUser = UserRights::GetUser();
IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
- $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
- $oP->p("".Dict::S('UI:Error:ObjectAlreadyUpdated')." \n");
- $sMessage = Dict::Format('UI:Error:ObjectAlreadyUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'error';
+ $oP->p("".Dict::S('UI:Error:ObjectAlreadyCreated')." \n");
- IssueLog::Trace('Object not updated (invalid transaction_id)', $sClass, array(
- '$operation' => $operation,
- '$id' => $id,
- '$sTransactionId' => $sTransactionId,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
+ IssueLog::Trace('Object not created (invalid transaction_id)', $sClass, array(
+ '$operation' => $operation,
+ '$sTransactionId' => $sTransactionId,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
}
else
{
- $aErrors = $oObj->UpdateObjectFromPostedForm();
- $sMessage = '';
- $sSeverity = 'ok';
-
- if (!$oObj->IsModified() && empty($aErrors))
+ /** @var \cmdbAbstractObject $oObj */
+ $oObj = MetaModel::NewObject($sClass);
+ if (MetaModel::HasLifecycle($sClass))
{
- $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
- $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'info';
-
- IssueLog::Trace('Object not updated (see either $aErrors or IsModified)', $sClass, array(
- '$operation' => $operation,
- '$id' => $id,
- '$sTransactionId' => $sTransactionId,
- '$aErrors' => $aErrors,
- 'IsModified' => $oObj->IsModified(),
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
- }
- else
- {
- IssueLog::Trace('Object updated', $sClass, array(
- '$operation' => $operation,
- '$id' => $id,
- '$sTransactionId' => $sTransactionId,
- '$aErrors' => $aErrors,
- 'IsModified' => $oObj->IsModified(),
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
-
- try
+ $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
+ $sTargetState = utils::ReadPostedParam('obj_state', '');
+ if ($sTargetState != '')
{
- if (!empty($aErrors))
+ $sOrigState = utils::ReadPostedParam('obj_state_orig', '');
+ if ($sTargetState != $sOrigState)
{
- throw new CoreCannotSaveObjectException(array('id' => $oObj->GetKey(), 'class' => $sClass, 'issues' => $aErrors));
+ $aWarnings[] = Dict::S('UI:StateChanged');
}
- // Transactions are now handled in DBUpdate
- $oObj->DBUpdate();
- $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'ok';
+ $oObj->Set($sStateAttCode, $sTargetState);
}
- catch (CoreCannotSaveObjectException $e)
+ }
+ $aErrors = $oObj->UpdateObjectFromPostedForm();
+ }
+ if (isset($oObj) && is_object($oObj))
+ {
+ $sClass = get_class($oObj);
+ $sClassLabel = MetaModel::GetName($sClass);
+
+ try
+ {
+ if (!empty($aErrors) || !empty($aWarnings))
{
- // Found issues, explain and give the user a second chance
- //
- $bDisplayDetails = false;
- $aIssues = $e->getIssues();
- $oP->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
- $oObj->DisplayModifyForm($oP,
- array('wizard_container' => true)); // wizard_container: display the wizard border and the title
- }
- catch (DeleteException $e)
- {
- // Say two things:
- // - 1) Don't be afraid nothing was modified
- $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'info';
- cmdbAbstractObject::SetSessionMessage(get_class($oObj), $oObj->GetKey(), 'UI:Class_Object_NotUpdated', $sMessage,
- $sSeverity, 0, true /* must not exist */);
- // - 2) Ok, there was some trouble indeed
- $sMessage = $e->getMessage();
- $sSeverity = 'error';
+ IssueLog::Trace('Object not created (see $aErrors)', $sClass, array(
+ '$operation' => $operation,
+ '$sTransactionId' => $sTransactionId,
+ '$aErrors' => $aErrors,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+
+ throw new CoreCannotSaveObjectException(array('id' => $oObj->GetKey(), 'class' => $sClass, 'issues' => $aErrors));
}
+
+ $oObj->DBInsertNoReload();// No need to reload
+
+ IssueLog::Trace('Object created', $sClass, array(
+ '$operation' => $operation,
+ '$id' => $oObj->GetKey(),
+ '$sTransactionId' => $sTransactionId,
+ '$aErrors' => $aErrors,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+
utils::RemoveTransaction($sTransactionId);
+ $oP->set_title(Dict::S('UI:PageTitle:ObjectCreated'));
+ QuickCreateHelper::AddClassToHistory($sClass);
+
+ // Compute the name, by reloading the object, even if it disappeared from the silo
+ $oObj = MetaModel::GetObject($sClass, $oObj->GetKey(), true /* Must be found */, true /* Allow All Data*/);
+ $sName = $oObj->GetName();
+ $sMessage = Dict::Format('UI:Title:Object_Of_Class_Created', $sName, $sClassLabel);
+
+ $sNextAction = utils::ReadPostedParam('next_action', '');
+ if (!empty($sNextAction)) {
+ $oP->add("$sMessage ");
+ try {
+ ApplyNextAction($oP, $oObj, $sNextAction);
+ }
+ catch (ApplicationException $e) {
+ $sMessage = $e->getMessage();
+ $sSeverity = 'info';
+ ReloadAndDisplay($oP, $oObj, 'create', $sMessage, $sSeverity);
+ }
+ } else {
+ // Nothing more to do
+ ReloadAndDisplay($oP, $oObj, 'create', $sMessage, 'ok');
+ }
+ }
+ catch (CoreCannotSaveObjectException $e) {
+ // Found issues, explain and give the user a second chance
+ //
+ $aIssues = $e->getIssues();
+
+ $sObjKey = $oObj->GetKey();
+ $sClassIcon = MetaModel::GetClassIcon($sClass, false);
+ $sHeaderTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
+
+ $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
+ if (!empty($aIssues)) {
+ $oP->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
+ }
+ if (!empty($aWarnings)) {
+ $sWarnings = implode(', ', $aWarnings);
+ $oP->AddHeaderMessage($sWarnings, 'message_warning');
+ }
+ cmdbAbstractObject::DisplayCreationForm($oP, $sClass, $oObj, [], ['transaction_id' => $sTransactionId]);
}
}
- if ($bDisplayDetails)
- {
- $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey()); //Workaround: reload the object so that the linkedset are displayed properly
- $sNextAction = utils::ReadPostedParam('next_action', '');
- if (!empty($sNextAction))
- {
- try
- {
- ApplyNextAction($oP, $oObj, $sNextAction);
- }
- catch (ApplicationException $e)
- {
- $sMessage = $e->getMessage();
- $sSeverity = 'info';
- ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
- }
- }
- else
- {
- // Nothing more to do
- $sMessage = isset($sMessage) ? $sMessage : '';
- $sSeverity = isset($sSeverity) ? $sSeverity : null;
- ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
- }
-
- $bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
- if ($bLockEnabled)
- {
- // Release the concurrent lock, if any
- $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
- if ($sOwnershipToken !== null)
- {
- // We're done, let's release the lock
- iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
- }
- }
- }
- break;
+ break;
- ///////////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////
- case 'select_for_deletion': // Select multiple objects for deletion
+ case 'select_bulk_stimulus': // Form displayed when applying a stimulus to many objects
$oP->DisableBreadCrumb();
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- if (empty($sFilter))
+ $sStimulus = utils::ReadParam('stimulus', '');
+ $sState = utils::ReadParam('state', '');
+ if (empty($sFilter) || empty($sStimulus) || empty($sState))
{
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
+ throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'filter', 'stimulus', 'state'));
}
- $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
-
- $oFilter = DBSearch::unserialize($sFilter); // TO DO : check that the filter is valid
+ $oFilter = DBObjectSearch::unserialize($sFilter);
$oFilter->UpdateContextFromUser();
-
+ $sClass = $oFilter->GetClass();
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+ $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
+ $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
+ $oP->set_title($sActionLabel);
$sClass = $oFilter->GetClass();
$aDisplayParams = [
'icon' => MetaModel::GetClassIcon($sClass, false),
- 'title' => Dict::S('UI:BulkDeleteTitle'),
+ 'title' => $sActionLabel,
];
- $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_DELETE);
- DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_delete', $oChecker, [], $aDisplayParams);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'bulk_delete_confirmed': // Confirm bulk deletion of objects
- $oP->DisableBreadCrumb();
- $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
- if (!utils::IsTransactionValid($sTransactionId))
- {
- $sUser = UserRights::GetUser();
- $sClass = utils::ReadParam('class', '', false, 'class');
- IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
- throw new ApplicationException(Dict::S('UI:Error:ObjectsAlreadyDeleted'));
- }
- // Fall through
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'delete':
- case 'bulk_delete': // Actual bulk deletion (if confirmed)
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sClassLabel = MetaModel::GetName($sClass);
- $aObjects = array();
- if ($operation == 'delete')
- {
- // Single object
- $id = utils::ReadParam('id', '');
- $oObj = MetaModel::GetObject($sClass, $id);
- $aObjects[] = $oObj;
- if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromObject($oObj)))
- {
- throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClassLabel));
- }
- }
- else
- {
- // Several objects
- $sFilter = utils::ReadPostedParam('filter', '', 'raw_data');
- $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
- // Add user filter
- $oFullSetFilter->UpdateContextFromUser();
- $aSelectObject = utils::ReadMultipleSelection($oFullSetFilter);
- if ( empty($sClass) || empty($aSelectObject)) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObject[]'));
- }
- foreach($aSelectObject as $iId)
- {
- $aObjects[] = MetaModel::GetObject($sClass, $iId);
- }
- if (count($aObjects) == 1)
- {
- if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
- {
- throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
- }
- }
- else
- {
- if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
- {
- throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
- }
- $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
- }
- }
- // Go for the common part... (delete single, delete bulk, delete confirmed)
- cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed');
+ $oChecker = new StimulusChecker($oFilter, $sState, $sStimulus);
+ $aExtraFormParams = array('stimulus' => $sStimulus, 'state' => $sState);
+ DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_stimulus', $oChecker, $aExtraFormParams, $aDisplayParams);
break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
- case 'apply_new': // Creation of a new object
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadPostedParam('class', '', 'class');
- $sClassLabel = MetaModel::GetName($sClass);
- $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
- $aErrors = array();
- $aWarnings = array();
- if ( empty($sClass) ) // TO DO: check that the class name is valid !
- {
- IssueLog::Trace('Object not created (empty class)', $sClass, array(
- '$operation' => $operation,
- '$sTransactionId' => $sTransactionId,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
-
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
- }
- if (!utils::IsTransactionValid($sTransactionId, false))
- {
- $sUser = UserRights::GetUser();
- IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
- $oP->p("".Dict::S('UI:Error:ObjectAlreadyCreated')." \n");
-
- IssueLog::Trace('Object not created (invalid transaction_id)', $sClass, array(
- '$operation' => $operation,
- '$sTransactionId' => $sTransactionId,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
- }
- else
- {
- /** @var \cmdbAbstractObject $oObj */
- $oObj = MetaModel::NewObject($sClass);
- if (MetaModel::HasLifecycle($sClass))
+ case 'bulk_stimulus':
+ $oP->DisableBreadCrumb();
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ $sStimulus = utils::ReadParam('stimulus', '');
+ $sState = utils::ReadParam('state', '');
+ if (empty($sFilter) || empty($sStimulus) || empty($sState))
{
- $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
- $sTargetState = utils::ReadPostedParam('obj_state', '');
- if ($sTargetState != '')
- {
- $sOrigState = utils::ReadPostedParam('obj_state_orig', '');
- if ($sTargetState != $sOrigState)
- {
- $aWarnings[] = Dict::S('UI:StateChanged');
- }
- $oObj->Set($sStateAttCode, $sTargetState);
- }
+ throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'filter', 'stimulus', 'state'));
}
- $aErrors = $oObj->UpdateObjectFromPostedForm();
- }
- if (isset($oObj) && is_object($oObj))
- {
- $sClass = get_class($oObj);
- $sClassLabel = MetaModel::GetName($sClass);
-
- try
- {
- if (!empty($aErrors) || !empty($aWarnings))
- {
- IssueLog::Trace('Object not created (see $aErrors)', $sClass, array(
- '$operation' => $operation,
- '$sTransactionId' => $sTransactionId,
- '$aErrors' => $aErrors,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
-
- throw new CoreCannotSaveObjectException(array('id' => $oObj->GetKey(), 'class' => $sClass, 'issues' => $aErrors));
- }
-
- $oObj->DBInsertNoReload();// No need to reload
-
- IssueLog::Trace('Object created', $sClass, array(
- '$operation' => $operation,
- '$id' => $oObj->GetKey(),
- '$sTransactionId' => $sTransactionId,
- '$aErrors' => $aErrors,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
-
- utils::RemoveTransaction($sTransactionId);
- $oP->set_title(Dict::S('UI:PageTitle:ObjectCreated'));
- QuickCreateHelper::AddClassToHistory($sClass);
-
- // Compute the name, by reloading the object, even if it disappeared from the silo
- $oObj = MetaModel::GetObject($sClass, $oObj->GetKey(), true /* Must be found */, true /* Allow All Data*/);
- $sName = $oObj->GetName();
- $sMessage = Dict::Format('UI:Title:Object_Of_Class_Created', $sName, $sClassLabel);
-
- $sNextAction = utils::ReadPostedParam('next_action', '');
- if (!empty($sNextAction)) {
- $oP->add("$sMessage ");
- try {
- ApplyNextAction($oP, $oObj, $sNextAction);
- }
- catch (ApplicationException $e) {
- $sMessage = $e->getMessage();
- $sSeverity = 'info';
- ReloadAndDisplay($oP, $oObj, 'create', $sMessage, $sSeverity);
- }
- } else {
- // Nothing more to do
- ReloadAndDisplay($oP, $oObj, 'create', $sMessage, 'ok');
- }
- }
- catch (CoreCannotSaveObjectException $e) {
- // Found issues, explain and give the user a second chance
- //
- $aIssues = $e->getIssues();
-
- $sObjKey = $oObj->GetKey();
- $sClassIcon = MetaModel::GetClassIcon($sClass, false);
- $sHeaderTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
-
- $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
- if (!empty($aIssues)) {
- $oP->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
- }
- if (!empty($aWarnings)) {
- $sWarnings = implode(', ', $aWarnings);
- $oP->AddHeaderMessage($sWarnings, 'message_warning');
- }
- cmdbAbstractObject::DisplayCreationForm($oP, $sClass, $oObj, [], ['transaction_id' => $sTransactionId]);
- }
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'select_bulk_stimulus': // Form displayed when applying a stimulus to many objects
- $oP->DisableBreadCrumb();
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $sStimulus = utils::ReadParam('stimulus', '');
- $sState = utils::ReadParam('state', '');
- if (empty($sFilter) || empty($sStimulus) || empty($sState))
- {
- throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'filter', 'stimulus', 'state'));
- }
- $oFilter = DBObjectSearch::unserialize($sFilter);
- $oFilter->UpdateContextFromUser();
- $sClass = $oFilter->GetClass();
- $aStimuli = MetaModel::EnumStimuli($sClass);
- $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
- $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
- $oP->set_title($sActionLabel);
- $sClass = $oFilter->GetClass();
-
- $aDisplayParams = [
- 'icon' => MetaModel::GetClassIcon($sClass, false),
- 'title' => $sActionLabel,
- ];
- $oChecker = new StimulusChecker($oFilter, $sState, $sStimulus);
- $aExtraFormParams = array('stimulus' => $sStimulus, 'state' => $sState);
- DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_stimulus', $oChecker, $aExtraFormParams, $aDisplayParams);
- break;
-
- case 'bulk_stimulus':
- $oP->DisableBreadCrumb();
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $sStimulus = utils::ReadParam('stimulus', '');
- $sState = utils::ReadParam('state', '');
- if (empty($sFilter) || empty($sStimulus) || empty($sState))
- {
- throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'filter', 'stimulus', 'state'));
- }
- $oFilter = DBObjectSearch::unserialize($sFilter);
- // Add user filter
- $oFilter->UpdateContextFromUser();
- $sClass = $oFilter->GetClass();
- $aSelectObject = utils::ReadMultipleSelection($oFilter);
- if (count($aSelectObject) == 0)
- {
- // Nothing to do, no object was selected !
- throw new ApplicationException(Dict::S('UI:BulkAction:NoObjectSelected'));
- }
- else
- {
- $aTransitions = MetaModel::EnumTransitions($sClass, $sState);
- $aStimuli = MetaModel::EnumStimuli($sClass);
-
- $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
- $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
- $sTargetState = $aTransitions[$sStimulus]['target_state'];
- $aStates = MetaModel::EnumStates($sClass);
- $aTargetStateDef = $aStates[$sTargetState];
-
- $oP->set_title(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aSelectObject), $sClass));
- $oP->add(<<
-
-HTML
- );
- $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aSelectObject), $sClass)));
- if (!empty($sActionDetails)) {
- $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage($sActionDetails));
- }
-
-
-
- $aExpectedAttributes = MetaModel::GetTransitionAttributes($sClass, $sStimulus, $sState);
- $aDetails = array();
- $sFormId = 'apply_stimulus';
- $sFormPrefix = $sFormId.'_';
- $iFieldIndex = 0;
- $aFieldsMap = array();
- $aValues = array();
- $aObjects = array();
- foreach($aSelectObject as $iId)
- {
- $aObjects[] = MetaModel::GetObject($sClass, $iId);
- }
- $oSet = DBObjectSet::FromArray($sClass, $aObjects);
- $oObj = $oSet->ComputeCommonObject($aValues);
- $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
- $oObj->Set($sStateAttCode,$sTargetState);
- $sReadyScript = '';
- foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
- {
- $sFieldInputId = $sFormPrefix.$sAttCode;
- // Prompt for an attribute if
- // - the attribute must be changed or must be displayed to the user for confirmation
- // - or the field is mandatory and currently empty
- if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
- (($iExpectCode & OPT_ATT_MANDATORY) && ($oObj->Get($sAttCode) == '')) )
- {
- $aAttributesDef = MetaModel::ListAttributeDefs($sClass);
- $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- $aPrerequisites = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
- if (count($aPrerequisites) > 0)
- {
- // When 'enabling' a field, all its prerequisites must be enabled too
- $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aPrerequisites)."']";
- $oP->add_ready_script("$('#enable_{$sFieldInputId}').on('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, true); } );\n");
- }
- $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
- if (count($aDependents) > 0)
- {
- // When 'disabling' a field, all its dependent fields must be disabled too
- $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aDependents)."']";
- $oP->add_ready_script("$('#enable_{$sFieldInputId}').on('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, false); } );\n");
- }
- $aArgs = array('this' => $oObj);
- $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oObj->Get($sAttCode), $oObj->GetEditValue($sAttCode), $sFieldInputId, '', $iExpectCode, $aArgs);
- $sComments = '
';
- if (!isset($aValues[$sAttCode]))
- {
- $aValues[$sAttCode] = array();
- }
- if (count($aValues[$sAttCode]) == 1)
- {
- $sComments = '
1'.$sComments.'
';
- }
- else
- {
- // Non-homogenous value
- $iMaxCount = 5;
- $sTip = "
".Dict::Format('UI:BulkModify_Count_DistinctValues', count($aValues[$sAttCode]))."
";
- $index = 0;
- foreach($aValues[$sAttCode] as $sCurrValue => $aVal)
- {
- $sDisplayValue = empty($aVal['display']) ? ''.Dict::S('Enum:Undefined').' ' : str_replace(array("\n", "\r"), " ", $aVal['display']);
- $sTip .= "".Dict::Format('UI:BulkModify:Value_Exists_N_Times', $sDisplayValue, $aVal['count'])." ";
- $index++;
- if ($iMaxCount == $index)
- {
- $sTip .= "".Dict::Format('UI:BulkModify:N_MoreValues', count($aValues[$sAttCode]) - $iMaxCount)." ";
- break;
- }
- }
- $sTip .= " ";
- $sTip = utils::HtmlEntities($sTip);
- $sComments = '
'.count($aValues[$sAttCode]).$sComments.'
';
- }
- $aDetails[] = array('label' => '
'.$oAttDef->GetLabel().' ', 'value' => "
$sHTMLValue ", 'comments' => $sComments);
- $aFieldsMap[$sAttCode] = $sFieldInputId;
- $iFieldIndex++;
- }
- }
- $oFormContainer = new UIContentBlock(null, ['ibo-wizard-container']);
- $oP->AddUiBlock($oFormContainer);
- $oForm = new Combodo\iTop\Application\UI\Base\Component\Form\Form($sFormId);
- $oFormContainer->AddSubBlock($oForm);
- $oForm->SetOnSubmitJsCode("return OnSubmit('{$sFormId}');")
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('class', $sClass))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('operation', 'bulk_apply_stimulus'))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('stimulus', $sStimulus))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('preview_mode', 1))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('filter', utils::HtmlEntities($sFilter)))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('state', $sState))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('selectObject', implode(',',$aSelectObject)))
- ->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', utils::GetNewTransactionId()));
-
- $aContextInputBlocks = $oAppContext->GetForUIForm();
- foreach ($aContextInputBlocks as $oContextInputBlock){
- $oForm->AddSubBlock($oContextInputBlock);
- }
- // Note: Remove the table if we want fields to occupy the whole width of the container
- $oForm->AddHtml('
');
- $oForm->AddHtml($oP->GetDetails($aDetails));
- $oForm->AddHtml('
');
-
- $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
- $oCancelButton = ButtonUIBlockFactory::MakeForCancel(Dict::S('UI:Button:Cancel'), 'cancel', 'cancel');
- $oCancelButton->SetOnClickJsCode("window.location.href='$sURL'");
- $oForm->AddSubBlock($oCancelButton);
-
- $oSubmitButton = ButtonUIBlockFactory::MakeForPrimaryAction($sActionLabel, 'submit', 'submit', true);
- $oForm->AddSubBlock($oSubmitButton);
-
- $oP->add(<<
-
-HTML
- );
-
- $iFieldsCount = count($aFieldsMap);
- $sJsonFieldsMap = json_encode($aFieldsMap);
-
- $oP->add_script(
-<<add_ready_script(
-<<DisableBreadCrumb();
- $bPreviewMode = utils::ReadPostedParam('preview_mode', false);
- $sFilter = utils::ReadPostedParam('filter', '', 'raw_data');
- $sStimulus = utils::ReadPostedParam('stimulus', '');
- $sState = utils::ReadPostedParam('state', '');
- $sSelectObject = utils::ReadPostedParam('selectObject', '', 'raw_data');
- $aSelectObject = explode(',', $sSelectObject);
-
- if (empty($sFilter) || empty($sStimulus) || empty($sState))
- {
- throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'filter', 'stimulus', 'state'));
- }
- $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
- if (!utils::IsTransactionValid($sTransactionId))
- {
- $sUser = UserRights::GetUser();
- IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser'");
- $oP->p(Dict::S('UI:Error:ObjectAlreadyUpdated'));
- }
- else
- {
- // For archiving the modification
$oFilter = DBObjectSearch::unserialize($sFilter);
// Add user filter
$oFilter->UpdateContextFromUser();
$sClass = $oFilter->GetClass();
- $aObjects = array();
- foreach($aSelectObject as $iId)
+ $aSelectObject = utils::ReadMultipleSelection($oFilter);
+ if (count($aSelectObject) == 0)
{
- $aObjects[] = MetaModel::GetObject($sClass, $iId);
+ // Nothing to do, no object was selected !
+ throw new ApplicationException(Dict::S('UI:BulkAction:NoObjectSelected'));
}
-
- $aTransitions = MetaModel::EnumTransitions($sClass, $sState);
- $aStimuli = MetaModel::EnumStimuli($sClass);
-
- $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
- $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
-
- $oP->set_title(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aObjects), $sClass));
-
- $oSet = DBObjectSet::FromArray($sClass, $aObjects);
-
- // For reporting
- $aHeaders = array(
- 'object' => array('label' => MetaModel::GetName($sClass), 'description' => Dict::S('UI:ModifiedObject')),
- 'status' => array('label' => Dict::S('UI:BulkModifyStatus'), 'description' => Dict::S('UI:BulkModifyStatus+')),
- 'errors' => array('label' => Dict::S('UI:BulkModifyErrors'), 'description' => Dict::S('UI:BulkModifyErrors+')),
- );
- $aRows = array();
- while ($oObj = $oSet->Fetch())
+ else
{
- $sError = Dict::S('UI:BulkModifyStatusOk');
- try
+ $aTransitions = MetaModel::EnumTransitions($sClass, $sState);
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+
+ $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
+ $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
+ $sTargetState = $aTransitions[$sStimulus]['target_state'];
+ $aStates = MetaModel::EnumStates($sClass);
+ $aTargetStateDef = $aStates[$sTargetState];
+
+ $oP->set_title(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aSelectObject), $sClass));
+ $oP->add(<<
+
+ HTML
+ );
+ $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aSelectObject), $sClass)));
+ if (!empty($sActionDetails)) {
+ $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage($sActionDetails));
+ }
+
+
+
+ $aExpectedAttributes = MetaModel::GetTransitionAttributes($sClass, $sStimulus, $sState);
+ $aDetails = array();
+ $sFormId = 'apply_stimulus';
+ $sFormPrefix = $sFormId.'_';
+ $iFieldIndex = 0;
+ $aFieldsMap = array();
+ $aValues = array();
+ $aObjects = array();
+ foreach($aSelectObject as $iId)
{
- $aTransitions = $oObj->EnumTransitions();
- $aStimuli = MetaModel::EnumStimuli($sClass);
- if (!isset($aTransitions[$sStimulus]))
+ $aObjects[] = MetaModel::GetObject($sClass, $iId);
+ }
+ $oSet = DBObjectSet::FromArray($sClass, $aObjects);
+ $oObj = $oSet->ComputeCommonObject($aValues);
+ $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
+ $oObj->Set($sStateAttCode,$sTargetState);
+ $sReadyScript = '';
+ foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
+ {
+ $sFieldInputId = $sFormPrefix.$sAttCode;
+ // Prompt for an attribute if
+ // - the attribute must be changed or must be displayed to the user for confirmation
+ // - or the field is mandatory and currently empty
+ if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
+ (($iExpectCode & OPT_ATT_MANDATORY) && ($oObj->Get($sAttCode) == '')) )
{
- throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
- }
- else
- {
- $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
- $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
- $sTargetState = $aTransitions[$sStimulus]['target_state'];
- $aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /* cureent state */);
- $aDetails = array();
- $aErrors = array();
- foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
+ $aAttributesDef = MetaModel::ListAttributeDefs($sClass);
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $aPrerequisites = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
+ if (count($aPrerequisites) > 0)
{
- $iFlags = $oObj->GetTransitionFlags($sAttCode, $sStimulus);
- if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') )
+ // When 'enabling' a field, all its prerequisites must be enabled too
+ $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aPrerequisites)."']";
+ $oP->add_ready_script("$('#enable_{$sFieldInputId}').on('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, true); } );\n");
+ }
+ $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
+ if (count($aDependents) > 0)
+ {
+ // When 'disabling' a field, all its dependent fields must be disabled too
+ $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aDependents)."']";
+ $oP->add_ready_script("$('#enable_{$sFieldInputId}').on('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, false); } );\n");
+ }
+ $aArgs = array('this' => $oObj);
+ $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oObj->Get($sAttCode), $oObj->GetEditValue($sAttCode), $sFieldInputId, '', $iExpectCode, $aArgs);
+ $sComments = '
';
+ if (!isset($aValues[$sAttCode]))
+ {
+ $aValues[$sAttCode] = array();
+ }
+ if (count($aValues[$sAttCode]) == 1)
+ {
+ $sComments = '
1'.$sComments.'
';
+ }
+ else
+ {
+ // Non-homogenous value
+ $iMaxCount = 5;
+ $sTip = "
".Dict::Format('UI:BulkModify_Count_DistinctValues', count($aValues[$sAttCode]))."
";
+ $index = 0;
+ foreach($aValues[$sAttCode] as $sCurrValue => $aVal)
{
- $paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data');
- if ( ($iFlags & OPT_ATT_SLAVE) && ($paramValue != $oObj->Get($sAttCode)) )
+ $sDisplayValue = empty($aVal['display']) ? ''.Dict::S('Enum:Undefined').' ' : str_replace(array("\n", "\r"), " ", $aVal['display']);
+ $sTip .= "".Dict::Format('UI:BulkModify:Value_Exists_N_Times', $sDisplayValue, $aVal['count'])." ";
+ $index++;
+ if ($iMaxCount == $index)
{
- $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- $aErrors[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel(), $sAttCode);
- unset($aExpectedAttributes[$sAttCode]);
+ $sTip .= "".Dict::Format('UI:BulkModify:N_MoreValues', count($aValues[$sAttCode]) - $iMaxCount)." ";
+ break;
}
}
+ $sTip .= " ";
+ $sTip = utils::HtmlEntities($sTip);
+ $sComments = '
'.count($aValues[$sAttCode]).$sComments.'
';
}
-
- $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $aExpectedAttributes);
-
- if (count($aErrors) == 0)
+ $aDetails[] = array('label' => '
'.$oAttDef->GetLabel().' ', 'value' => "
$sHTMLValue ", 'comments' => $sComments);
+ $aFieldsMap[$sAttCode] = $sFieldInputId;
+ $iFieldIndex++;
+ }
+ }
+ $oFormContainer = new UIContentBlock(null, ['ibo-wizard-container']);
+ $oP->AddUiBlock($oFormContainer);
+ $oForm = new Combodo\iTop\Application\UI\Base\Component\Form\Form($sFormId);
+ $oFormContainer->AddSubBlock($oForm);
+ $oForm->SetOnSubmitJsCode("return OnSubmit('{$sFormId}');")
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('class', $sClass))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('operation', 'bulk_apply_stimulus'))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('stimulus', $sStimulus))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('preview_mode', 1))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('filter', utils::HtmlEntities($sFilter)))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('state', $sState))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('selectObject', implode(',',$aSelectObject)))
+ ->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', utils::GetNewTransactionId()));
+
+ $aContextInputBlocks = $oAppContext->GetForUIForm();
+ foreach ($aContextInputBlocks as $oContextInputBlock){
+ $oForm->AddSubBlock($oContextInputBlock);
+ }
+ // Note: Remove the table if we want fields to occupy the whole width of the container
+ $oForm->AddHtml('
');
+ $oForm->AddHtml($oP->GetDetails($aDetails));
+ $oForm->AddHtml('
');
+
+ $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $oCancelButton = ButtonUIBlockFactory::MakeForCancel(Dict::S('UI:Button:Cancel'), 'cancel', 'cancel');
+ $oCancelButton->SetOnClickJsCode("window.location.href='$sURL'");
+ $oForm->AddSubBlock($oCancelButton);
+
+ $oSubmitButton = ButtonUIBlockFactory::MakeForPrimaryAction($sActionLabel, 'submit', 'submit', true);
+ $oForm->AddSubBlock($oSubmitButton);
+
+ $oP->add(<<
+
+ HTML
+ );
+
+ $iFieldsCount = count($aFieldsMap);
+ $sJsonFieldsMap = json_encode($aFieldsMap);
+
+ $oP->add_script(
+ <<add_ready_script(
+ <<DisableBreadCrumb();
+ $bPreviewMode = utils::ReadPostedParam('preview_mode', false);
+ $sFilter = utils::ReadPostedParam('filter', '', 'raw_data');
+ $sStimulus = utils::ReadPostedParam('stimulus', '');
+ $sState = utils::ReadPostedParam('state', '');
+ $sSelectObject = utils::ReadPostedParam('selectObject', '', 'raw_data');
+ $aSelectObject = explode(',', $sSelectObject);
+
+ if (empty($sFilter) || empty($sStimulus) || empty($sState))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'filter', 'stimulus', 'state'));
+ }
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
+ if (!utils::IsTransactionValid($sTransactionId))
+ {
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser'");
+ $oP->p(Dict::S('UI:Error:ObjectAlreadyUpdated'));
+ }
+ else
+ {
+ // For archiving the modification
+ $oFilter = DBObjectSearch::unserialize($sFilter);
+ // Add user filter
+ $oFilter->UpdateContextFromUser();
+ $sClass = $oFilter->GetClass();
+ $aObjects = array();
+ foreach($aSelectObject as $iId)
+ {
+ $aObjects[] = MetaModel::GetObject($sClass, $iId);
+ }
+
+ $aTransitions = MetaModel::EnumTransitions($sClass, $sState);
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+
+ $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
+ $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
+
+ $oP->set_title(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aObjects), $sClass));
+
+ $oSet = DBObjectSet::FromArray($sClass, $aObjects);
+
+ // For reporting
+ $aHeaders = array(
+ 'object' => array('label' => MetaModel::GetName($sClass), 'description' => Dict::S('UI:ModifiedObject')),
+ 'status' => array('label' => Dict::S('UI:BulkModifyStatus'), 'description' => Dict::S('UI:BulkModifyStatus+')),
+ 'errors' => array('label' => Dict::S('UI:BulkModifyErrors'), 'description' => Dict::S('UI:BulkModifyErrors+')),
+ );
+ $aRows = array();
+ while ($oObj = $oSet->Fetch())
+ {
+ $sError = Dict::S('UI:BulkModifyStatusOk');
+ try
+ {
+ $aTransitions = $oObj->EnumTransitions();
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+ if (!isset($aTransitions[$sStimulus]))
{
- if ($oObj->ApplyStimulus($sStimulus))
+ throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
+ }
+ else
+ {
+ $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
+ $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
+ $sTargetState = $aTransitions[$sStimulus]['target_state'];
+ $aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /* cureent state */);
+ $aDetails = array();
+ $aErrors = array();
+ foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
{
- list($bResult, $aErrors) = $oObj->CheckToWrite();
- $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusModified') : Dict::S('UI:BulkModifyStatusSkipped');
- if ($bResult)
+ $iFlags = $oObj->GetTransitionFlags($sAttCode, $sStimulus);
+ if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') )
{
- $oObj->DBUpdate();
+ $paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data');
+ if ( ($iFlags & OPT_ATT_SLAVE) && ($paramValue != $oObj->Get($sAttCode)) )
+ {
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $aErrors[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel(), $sAttCode);
+ unset($aExpectedAttributes[$sAttCode]);
+ }
+ }
+ }
+
+ $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $aExpectedAttributes);
+
+ if (count($aErrors) == 0)
+ {
+ if ($oObj->ApplyStimulus($sStimulus))
+ {
+ list($bResult, $aErrors) = $oObj->CheckToWrite();
+ $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusModified') : Dict::S('UI:BulkModifyStatusSkipped');
+ if ($bResult)
+ {
+ $oObj->DBUpdate();
+ }
+ else
+ {
+ $aErrorsToDisplay = array_map(function($sError) {
+ return utils::HtmlEntities($sError);
+ }, $aErrors);
+ $sError = ''.implode('
',$aErrorsToDisplay)."\n";
+ }
}
else
{
- $aErrorsToDisplay = array_map(function($sError) {
- return utils::HtmlEntities($sError);
- }, $aErrors);
- $sError = ''.implode('
',$aErrorsToDisplay)."\n";
+ $sStatus = Dict::S('UI:BulkModifyStatusSkipped');
+ $sError = ''.Dict::S('UI:FailedToApplyStimuli')."
\n";
}
}
else
{
- $sStatus = Dict::S('UI:BulkModifyStatusSkipped');
- $sError = '
'.Dict::S('UI:FailedToApplyStimuli')."
\n";
+ $sStatus = Dict::S('UI:BulkModifyStatusSkipped');
+ $sError = '
'.implode('
',$aErrors)."\n";
+ }
+ }
+ }
+ catch(Exception $e)
+ {
+ $sError = $e->getMessage();
+ $sStatus = Dict::S('UI:BulkModifyStatusSkipped');
+ }
+ $aRows[] = array(
+ 'object' => $oObj->GetHyperlink(),
+ 'status' => $sStatus,
+ 'errors' => $sError,
+ );
+ }
+ $oBlock = PanelUIBlockFactory::MakeForClass($sClass, Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aObjects), $sClass));
+ $oBlock->SetIcon(MetaModel::GetClassIcon($sClass, false));
+
+
+ $oDataTable = DataTableUIBlockFactory::MakeForStaticData('', $aHeaders,$aRows);
+ $oBlock->AddSubBlock($oDataTable);
+ $oP->AddUiBlock($oBlock);
+
+ // Back to the list
+ $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $oSubmitButton = ButtonUIBlockFactory::MakeForSecondaryAction(Dict::S('UI:Button:Done'), 'submit', 'submit', true);
+ $oSubmitButton->SetOnClickJsCode("window.location.href='$sURL'");
+ $oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null);
+ $oToolbarButtons->AddCSSClass('ibo-toolbar--button');
+ $oToolbarButtons->AddSubBlock($oSubmitButton);
+ $oP->AddSubBlock($oToolbarButtons);
+ }
+ break;
+
+ case 'stimulus': // Form displayed when applying a stimulus (state change)
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $id = utils::ReadParam('id', '');
+ $sStimulus = utils::ReadParam('stimulus', '');
+ if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus'));
+ }
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+ if ((get_class($aStimuli[$sStimulus]) !== 'StimulusUserAction') || (UserRights::IsStimulusAllowed($sClass, $sStimulus) === UR_ALLOWED_NO))
+ {
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : Stimulus '$sStimulus' not allowed ! data: user='$sUser', class='$sClass'");
+ throw new ApplicationException(Dict::S('UI:Error:ActionNotAllowed'));
+ }
+
+ /** @var \cmdbAbstractObject $oObj */
+ $oObj = MetaModel::GetObject($sClass, $id, false);
+ if ($oObj != null)
+ {
+ $aPrefillFormParam = [
+ 'user' => Session::Get('auth_user'),
+ 'context' => $oAppContext->GetAsHash(),
+ 'stimulus' => $sStimulus,
+ 'origin' => 'console',
+ ];
+ try {
+ $bApplyTransition = $oObj->DisplayStimulusForm($oP, $sStimulus, $aPrefillFormParam);
+ }
+ catch (ApplicationException $e) {
+ $sMessage = $e->getMessage();
+ $sSeverity = 'info';
+ ReloadAndDisplay($oP, $oObj, 'stimulus', $sMessage, $sSeverity);
+ }
+ if ($bApplyTransition) {
+ $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'ok';
+ //transition is ok, whe can display object with transition message
+ ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity);
+ }
+ }
+ else
+ {
+ $oP->set_title(Dict::S('UI:ErrorPageTitle'));
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'apply_stimulus': // Actual state change
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadPostedParam('class', '', 'class');
+ $id = utils::ReadPostedParam('id', '');
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
+ $sStimulus = utils::ReadPostedParam('stimulus', '');
+ if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus'));
+ }
+ /** @var \cmdbAbstractObject $oObj */
+ $oObj = MetaModel::GetObject($sClass, $id, false);
+ if ($oObj != null)
+ {
+ $aTransitions = $oObj->EnumTransitions();
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+ $sMessage = '';
+ $sSeverity = 'ok';
+ $bDisplayDetails = true;
+ if (!isset($aTransitions[$sStimulus]))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
+ }
+ if (!utils::IsTransactionValid($sTransactionId))
+ {
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
+ $sMessage = Dict::S('UI:Error:ObjectAlreadyUpdated');
+ $sSeverity = 'info';
+ }
+ elseif ((get_class($aStimuli[$sStimulus]) !== 'StimulusUserAction') || (UserRights::IsStimulusAllowed($sClass, $sStimulus) === UR_ALLOWED_NO))
+ {
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : Stimulus '$sStimulus' not allowed ! data: user='$sUser', class='$sClass'");
+ $sMessage = Dict::S('UI:Error:ActionNotAllowed');
+ $sSeverity = 'error';
+ }
+ else
+ {
+ $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
+ $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
+ $sTargetState = $aTransitions[$sStimulus]['target_state'];
+ $aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /*, current state*/);
+ $aDetails = array();
+ $aErrors = array();
+ foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
+ {
+ $iFlags = $oObj->GetTransitionFlags($sAttCode, $sStimulus);
+ if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') )
+ {
+ $paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data');
+ if ( ($iFlags & OPT_ATT_SLAVE) && ($paramValue != $oObj->Get($sAttCode)))
+ {
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $aErrors[] = Dict::Format('UI:AttemptingToChangeASlaveAttribute_Name', $oAttDef->GetLabel());
+ unset($aExpectedAttributes[$sAttCode]);
+ }
+ }
+ }
+
+ $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $aExpectedAttributes);
+
+ if (count($aErrors) == 0)
+ {
+ $sIssues = '';
+ $bApplyStimulus = true;
+ list($bRes, $aIssues) = $oObj->CheckToWrite(); // Check before trying to write the object
+ if ($bRes)
+ {
+ try
+ {
+ $bApplyStimulus = $oObj->ApplyStimulus($sStimulus); // will write the object in the DB
+ }
+ catch(CoreException $e)
+ {
+ // Rollback to the previous state... by reloading the object from the database and applying the modifications again
+ $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey());
+ $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $aExpectedAttributes);
+ $sIssues = $e->getMessage();
}
}
else
{
- $sStatus = Dict::S('UI:BulkModifyStatusSkipped');
- $sError = ''.implode('
',$aErrors)."\n";
+ $sIssues = implode(' ', $aIssues);
}
- }
- }
- catch(Exception $e)
- {
- $sError = $e->getMessage();
- $sStatus = Dict::S('UI:BulkModifyStatusSkipped');
- }
- $aRows[] = array(
- 'object' => $oObj->GetHyperlink(),
- 'status' => $sStatus,
- 'errors' => $sError,
- );
- }
- $oBlock = PanelUIBlockFactory::MakeForClass($sClass, Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aObjects), $sClass));
- $oBlock->SetIcon(MetaModel::GetClassIcon($sClass, false));
-
- $oDataTable = DataTableUIBlockFactory::MakeForStaticData('', $aHeaders,$aRows);
- $oBlock->AddSubBlock($oDataTable);
- $oP->AddUiBlock($oBlock);
+ if (!$bApplyStimulus)
+ {
+ $sMessage = Dict::S('UI:FailedToApplyStimuli');
+ $sSeverity = 'error';
- // Back to the list
- $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
- $oSubmitButton = ButtonUIBlockFactory::MakeForSecondaryAction(Dict::S('UI:Button:Done'), 'submit', 'submit', true);
- $oSubmitButton->SetOnClickJsCode("window.location.href='$sURL'");
- $oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null);
- $oToolbarButtons->AddCSSClass('ibo-toolbar--button');
- $oToolbarButtons->AddSubBlock($oSubmitButton);
- $oP->AddSubBlock($oToolbarButtons);
- }
- break;
-
- case 'stimulus': // Form displayed when applying a stimulus (state change)
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $id = utils::ReadParam('id', '');
- $sStimulus = utils::ReadParam('stimulus', '');
- if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus'));
- }
- $aStimuli = MetaModel::EnumStimuli($sClass);
- if ((get_class($aStimuli[$sStimulus]) !== 'StimulusUserAction') || (UserRights::IsStimulusAllowed($sClass, $sStimulus) === UR_ALLOWED_NO))
- {
- $sUser = UserRights::GetUser();
- IssueLog::Error("UI.php '$operation' : Stimulus '$sStimulus' not allowed ! data: user='$sUser', class='$sClass'");
- throw new ApplicationException(Dict::S('UI:Error:ActionNotAllowed'));
- }
-
- /** @var \cmdbAbstractObject $oObj */
- $oObj = MetaModel::GetObject($sClass, $id, false);
- if ($oObj != null)
- {
- $aPrefillFormParam = [
- 'user' => Session::Get('auth_user'),
- 'context' => $oAppContext->GetAsHash(),
- 'stimulus' => $sStimulus,
- 'origin' => 'console',
- ];
- try {
- $bApplyTransition = $oObj->DisplayStimulusForm($oP, $sStimulus, $aPrefillFormParam);
- }
- catch (ApplicationException $e) {
- $sMessage = $e->getMessage();
- $sSeverity = 'info';
- ReloadAndDisplay($oP, $oObj, 'stimulus', $sMessage, $sSeverity);
- }
- if ($bApplyTransition) {
- $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'ok';
- //transition is ok, whe can display object with transition message
- ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity);
- }
- }
- else
- {
- $oP->set_title(Dict::S('UI:ErrorPageTitle'));
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'apply_stimulus': // Actual state change
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadPostedParam('class', '', 'class');
- $id = utils::ReadPostedParam('id', '');
- $sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
- $sStimulus = utils::ReadPostedParam('stimulus', '');
- if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus'));
- }
- /** @var \cmdbAbstractObject $oObj */
- $oObj = MetaModel::GetObject($sClass, $id, false);
- if ($oObj != null)
- {
- $aTransitions = $oObj->EnumTransitions();
- $aStimuli = MetaModel::EnumStimuli($sClass);
- $sMessage = '';
- $sSeverity = 'ok';
- $bDisplayDetails = true;
- if (!isset($aTransitions[$sStimulus]))
- {
- throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
- }
- if (!utils::IsTransactionValid($sTransactionId))
- {
- $sUser = UserRights::GetUser();
- IssueLog::Error("UI.php '$operation' : invalid transaction_id ! data: user='$sUser', class='$sClass'");
- $sMessage = Dict::S('UI:Error:ObjectAlreadyUpdated');
- $sSeverity = 'info';
- }
- elseif ((get_class($aStimuli[$sStimulus]) !== 'StimulusUserAction') || (UserRights::IsStimulusAllowed($sClass, $sStimulus) === UR_ALLOWED_NO))
- {
- $sUser = UserRights::GetUser();
- IssueLog::Error("UI.php '$operation' : Stimulus '$sStimulus' not allowed ! data: user='$sUser', class='$sClass'");
- $sMessage = Dict::S('UI:Error:ActionNotAllowed');
- $sSeverity = 'error';
- }
- else
- {
- $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
- $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
- $sTargetState = $aTransitions[$sStimulus]['target_state'];
- $aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /*, current state*/);
- $aDetails = array();
- $aErrors = array();
- foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
- {
- $iFlags = $oObj->GetTransitionFlags($sAttCode, $sStimulus);
- if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') )
- {
- $paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data');
- if ( ($iFlags & OPT_ATT_SLAVE) && ($paramValue != $oObj->Get($sAttCode)))
- {
- $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- $aErrors[] = Dict::Format('UI:AttemptingToChangeASlaveAttribute_Name', $oAttDef->GetLabel());
- unset($aExpectedAttributes[$sAttCode]);
- }
- }
- }
-
- $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $aExpectedAttributes);
-
- if (count($aErrors) == 0)
- {
- $sIssues = '';
- $bApplyStimulus = true;
- list($bRes, $aIssues) = $oObj->CheckToWrite(); // Check before trying to write the object
- if ($bRes)
- {
- try
- {
- $bApplyStimulus = $oObj->ApplyStimulus($sStimulus); // will write the object in the DB
- }
- catch(CoreException $e)
- {
- // Rollback to the previous state... by reloading the object from the database and applying the modifications again
- $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey());
- $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $aExpectedAttributes);
- $sIssues = $e->getMessage();
- }
- }
- else
- {
- $sIssues = implode(' ', $aIssues);
- }
-
- if (!$bApplyStimulus)
- {
- $sMessage = Dict::S('UI:FailedToApplyStimuli');
- $sSeverity = 'error';
-
- $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
- if ($sOwnershipToken !== null)
- {
- // Release the concurrent lock, if any
- iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
- }
- }
- else if ($sIssues != '')
- {
- $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
- if ($sOwnershipToken !== null)
- {
- // Release the concurrent lock, if any, a new lock will be re-acquired by DisplayStimulusForm below
- iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
- }
-
- $bDisplayDetails = false;
- // Found issues, explain and give the user a second chance
- //
- try
- {
- $oObj->DisplayStimulusForm($oP, $sStimulus);
- }
- catch(ApplicationException $e)
- {
- $sMessage = $e->getMessage();
- $sSeverity = 'info';
- }
- $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten',$sIssues);
- $oP->add_ready_script("alert('".addslashes($sIssueDesc)."');");
- }
- else
- {
- $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'ok';
- utils::RemoveTransaction($sTransactionId);
- $bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
- if ($bLockEnabled)
- {
- // Release the concurrent lock, if any
$sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
if ($sOwnershipToken !== null)
{
- // We're done, let's release the lock
+ // Release the concurrent lock, if any
iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
}
}
+ else if ($sIssues != '')
+ {
+ $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
+ if ($sOwnershipToken !== null)
+ {
+ // Release the concurrent lock, if any, a new lock will be re-acquired by DisplayStimulusForm below
+ iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
+ }
+
+ $bDisplayDetails = false;
+ // Found issues, explain and give the user a second chance
+ //
+ try
+ {
+ $oObj->DisplayStimulusForm($oP, $sStimulus);
+ }
+ catch(ApplicationException $e)
+ {
+ $sMessage = $e->getMessage();
+ $sSeverity = 'info';
+ }
+ $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten',$sIssues);
+ $oP->add_ready_script("alert('".addslashes($sIssueDesc)."');");
+ }
+ else
+ {
+ $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'ok';
+ utils::RemoveTransaction($sTransactionId);
+ $bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
+ if ($bLockEnabled)
+ {
+ // Release the concurrent lock, if any
+ $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, 'raw_data');
+ if ($sOwnershipToken !== null)
+ {
+ // We're done, let's release the lock
+ iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
+ }
+ }
+ }
+ }
+ else
+ {
+ $sMessage = implode('', $aErrors);
+ $sSeverity = 'error';
}
}
- else
+ if ($bDisplayDetails)
{
- $sMessage = implode('
', $aErrors);
- $sSeverity = 'error';
+ ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity);
}
}
- if ($bDisplayDetails)
- {
- ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity);
- }
- }
- else
- {
- $oP->set_title(Dict::S('UI:ErrorPageTitle'));
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'swf_navigator': /** @deprecated SWF was removed in iTop */
- case 'view_relations': // Graphical display of the relations "impact" / "depends on"
- require_once(APPROOT.'core/simplegraph.class.inc.php');
- require_once(APPROOT.'core/relationgraph.class.inc.php');
- require_once(APPROOT.'core/displayablegraph.class.inc.php');
- $sClass = utils::ReadParam('class', '', false, 'class');
- $id = utils::ReadParam('id', 0);
- $sRelation = utils::ReadParam('relation', 'impact');
- $sDirection = utils::ReadParam('direction', 'down');
- $iGroupingThreshold = utils::ReadParam('g', 5);
-
- $bDirDown = ($sDirection === 'down');
- $oObj = MetaModel::GetObject($sClass, $id);
- $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
- $aSourceObjects = array($oObj);
-
- $oP->set_title(MetaModel::GetRelationDescription($sRelation, $bDirDown).' '.$oObj->GetName());
-
- $sPageId = "ui-relation-graph-".$sClass.'::'.$id;
- $sLabel = $oObj->GetName().' '.MetaModel::GetRelationLabel($sRelation, $bDirDown);
- $sDescription = MetaModel::GetRelationDescription($sRelation, $bDirDown).' '.$oObj->GetName();
- $oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription);
-
- if ($sRelation == 'depends on') {
- $sRelation = 'impacts';
- $sDirection = 'up';
- }
- if ($sDirection == 'up') {
- $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
- } else {
- $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth);
- }
-
-
- $aResults = $oRelGraph->GetObjectsByClass();
- $oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
- $oPanel = PanelUIBlockFactory::MakeForClass($sClass, MetaModel::GetRelationDescription($sRelation).' '.$oObj->GetName());
- $sClassIcon = MetaModel::GetClassIcon($sClass, false);
- if (strlen($sClassIcon) > 0){
- $oPanel->SetIcon($sClassIcon);
- }
-
- $oP->AddUiBlock($oPanel);
- $oP->AddTabContainer('Navigator', '', $oPanel);
- $oP->SetCurrentTabContainer('Navigator');
-
- $sFirstTab = MetaModel::GetConfig()->Get('impact_analysis_first_tab');
- $bLazyLoading = MetaModel::GetConfig()->Get('impact_analysis_lazy_loading');
- $sContextKey = "itop-config-mgmt/relation_context/$sClass/$sRelation/$sDirection";
-
- // Check if the current object supports Attachments, similar to AttachmentPlugin::IsTargetObject
- $sClassForAttachment = null;
- $iIdForAttachment = null;
- if (class_exists('Attachment')) {
- $aAllowedClasses = MetaModel::GetModuleSetting('itop-attachments', 'allowed_classes', array('Ticket'));
- foreach ($aAllowedClasses as $sAllowedClass) {
- if ($oObj instanceof $sAllowedClass) {
- $iIdForAttachment = $id;
- $sClassForAttachment = $sClass;
- }
- }
- }
-
- // Display the tabs
- if ($sFirstTab == 'list')
- {
- DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj);
- $oP->SetCurrentTab('UI:RelationshipGraph');
- $oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj),$bLazyLoading);
- DisplayNavigatorGroupTab($oP);
- }
else
{
- $oP->SetCurrentTab('UI:RelationshipGraph');
- $oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj),$bLazyLoading);
- DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj);
- DisplayNavigatorGroupTab($oP);
+ $oP->set_title(Dict::S('UI:ErrorPageTitle'));
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
}
-
- $oP->SetCurrentTab('');
break;
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'kill_lock':
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $id = utils::ReadParam('id', '');
- iTopOwnershipLock::KillLock($sClass, $id);
- $oObj = MetaModel::GetObject($sClass, $id);
- ReloadAndDisplay($oP, $oObj, 'concurrent_lock_killed', Dict::S('UI:ConcurrentLockKilled'), 'info');
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////
- case 'cancel': // An action was cancelled
- $oP->DisableBreadCrumb();
- $oP->set_title(Dict::S('UI:OperationCancelled'));
- $oP->add('
'.Dict::S('UI:OperationCancelled').' ');
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
+ case 'swf_navigator': /** @deprecated SWF was removed in iTop */
+ case 'view_relations': // Graphical display of the relations "impact" / "depends on"
+ require_once(APPROOT.'core/simplegraph.class.inc.php');
+ require_once(APPROOT.'core/relationgraph.class.inc.php');
+ require_once(APPROOT.'core/displayablegraph.class.inc.php');
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $id = utils::ReadParam('id', 0);
+ $sRelation = utils::ReadParam('relation', 'impact');
+ $sDirection = utils::ReadParam('direction', 'down');
+ $iGroupingThreshold = utils::ReadParam('g', 5);
- default: // Menu node rendering (templates)
- ApplicationMenu::LoadAdditionalMenus();
- $oMenuNode = ApplicationMenu::GetMenuNode(ApplicationMenu::GetMenuIndexById(ApplicationMenu::GetActiveNodeId()));
- if (is_object($oMenuNode))
- {
- $oMenuNode->RenderContent($oP, $oAppContext->GetAsHash());
- $oP->set_title($oMenuNode->GetLabel());
+ $bDirDown = ($sDirection === 'down');
+ $oObj = MetaModel::GetObject($sClass, $id);
+ $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
+ $aSourceObjects = array($oObj);
+
+ $oP->set_title(MetaModel::GetRelationDescription($sRelation, $bDirDown).' '.$oObj->GetName());
+
+ $sPageId = "ui-relation-graph-".$sClass.'::'.$id;
+ $sLabel = $oObj->GetName().' '.MetaModel::GetRelationLabel($sRelation, $bDirDown);
+ $sDescription = MetaModel::GetRelationDescription($sRelation, $bDirDown).' '.$oObj->GetName();
+ $oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription);
+
+ if ($sRelation == 'depends on') {
+ $sRelation = 'impacts';
+ $sDirection = 'up';
+ }
+ if ($sDirection == 'up') {
+ $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
+ } else {
+ $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth);
+ }
+
+
+ $aResults = $oRelGraph->GetObjectsByClass();
+ $oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
+ $oPanel = PanelUIBlockFactory::MakeForClass($sClass, MetaModel::GetRelationDescription($sRelation).' '.$oObj->GetName());
+ $sClassIcon = MetaModel::GetClassIcon($sClass, false);
+ if (strlen($sClassIcon) > 0){
+ $oPanel->SetIcon($sClassIcon);
+ }
+
+ $oP->AddUiBlock($oPanel);
+ $oP->AddTabContainer('Navigator', '', $oPanel);
+ $oP->SetCurrentTabContainer('Navigator');
+
+ $sFirstTab = MetaModel::GetConfig()->Get('impact_analysis_first_tab');
+ $bLazyLoading = MetaModel::GetConfig()->Get('impact_analysis_lazy_loading');
+ $sContextKey = "itop-config-mgmt/relation_context/$sClass/$sRelation/$sDirection";
+
+ // Check if the current object supports Attachments, similar to AttachmentPlugin::IsTargetObject
+ $sClassForAttachment = null;
+ $iIdForAttachment = null;
+ if (class_exists('Attachment')) {
+ $aAllowedClasses = MetaModel::GetModuleSetting('itop-attachments', 'allowed_classes', array('Ticket'));
+ foreach ($aAllowedClasses as $sAllowedClass) {
+ if ($oObj instanceof $sAllowedClass) {
+ $iIdForAttachment = $id;
+ $sClassForAttachment = $sClass;
+ }
+ }
+ }
+
+ // Display the tabs
+ if ($sFirstTab == 'list')
+ {
+ DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj);
+ $oP->SetCurrentTab('UI:RelationshipGraph');
+ $oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj),$bLazyLoading);
+ DisplayNavigatorGroupTab($oP);
+ }
+ else
+ {
+ $oP->SetCurrentTab('UI:RelationshipGraph');
+ $oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj),$bLazyLoading);
+ DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj);
+ DisplayNavigatorGroupTab($oP);
+ }
+
+ $oP->SetCurrentTab('');
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'kill_lock':
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $id = utils::ReadParam('id', '');
+ iTopOwnershipLock::KillLock($sClass, $id);
+ $oObj = MetaModel::GetObject($sClass, $id);
+ ReloadAndDisplay($oP, $oObj, 'concurrent_lock_killed', Dict::S('UI:ConcurrentLockKilled'), 'info');
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'cancel': // An action was cancelled
+ $oP->DisableBreadCrumb();
+ $oP->set_title(Dict::S('UI:OperationCancelled'));
+ $oP->add(''.Dict::S('UI:OperationCancelled').' ');
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ default: // Menu node rendering (templates)
+ ApplicationMenu::LoadAdditionalMenus();
+ $oMenuNode = ApplicationMenu::GetMenuNode(ApplicationMenu::GetMenuIndexById(ApplicationMenu::GetActiveNodeId()));
+ if (is_object($oMenuNode))
+ {
+ $oMenuNode->RenderContent($oP, $oAppContext->GetAsHash());
+ $oP->set_title($oMenuNode->GetLabel());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
}
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
}
+
DisplayWelcomePopup($oP);
$oKPI->ComputeAndReport('Compute page');
- $oP->output();
+ $oP->output();
}
catch (Exception $e) {
$oErrorPage = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
diff --git a/pages/ajax.render.php b/pages/ajax.render.php
index 08008bb68..d2a46116c 100644
--- a/pages/ajax.render.php
+++ b/pages/ajax.render.php
@@ -15,6 +15,7 @@ use Combodo\iTop\Controller\Base\Layout\ObjectController;
use Combodo\iTop\Controller\PreferencesController;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
+use Combodo\iTop\Router\Router;
require_once('../approot.inc.php');
@@ -35,6 +36,7 @@ try
$oKPI = new ExecutionKPI();
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
+ $sRoute = utils::ReadParam('route', '', false, utils::ENUM_SANITIZATION_FILTER_ROUTE);
$operation = utils::ReadParam('operation', '', false, utils::ENUM_SANITIZATION_FILTER_OPERATION);
// Only allow export functions to portal users
@@ -55,945 +57,896 @@ try
LoginWebPage::DoLoginEx($sRequestedPortalId, false);
$oKPI->ComputeAndReport('User login');
- $oPage = new AjaxPage("");
-
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $sEncoding = utils::ReadParam('encoding', 'serialize');
- $sClass = utils::ReadParam('class', 'MissingAjaxParam', false, 'class');
- $sStyle = utils::ReadParam('style', 'list');
-
// N°2780 Fix ContextTag for console
- // some operations are also used in the portal though
+ // Some operations are also used in the portal though
switch ($operation) {
case 'export_build_portal':
case 'export_download':
- // do nothing : used in portal (export.js in portal-base)
+ // Do nothing: used in portal (export.js in portal-base)
break;
default:
ContextTag::AddContext(ContextTag::TAG_CONSOLE);
}
- $oAjaxRenderController = new AjaxRenderController();
+ // First check if we can redirect the route to a dedicated controller
+ $sRoute = utils::ReadParam('route', '', false, utils::ENUM_SANITIZATION_FILTER_ROUTE);
+ $oRouter = Router::GetInstance();
+ if ($oRouter->CanDispatchRoute($sRoute)) {
+ $mResponse = $oRouter->DispatchRoute($sRoute);
- switch ($operation) {
- case 'search_and_refresh':
- $oPage = new JsonPage();
- // Feeds dataTables directly
- $oPage->SetOutputDataOnly(true);
- $aResult = AjaxRenderController::SearchAndRefresh($sFilter);
- $oPage->SetData($aResult);
- break;
+ // If response isn't a \WebPage, it is most likely that the output already occured, stop the script.
+ // Note that this is done here and not directly in the Router::DispatchRoute() so custom endpoint can handle null responses their own way.
+ if (false === ($mResponse instanceof WebPage)) {
+ die();
+ }
- case 'search':
- $oPage = new JsonPage();
- // Feeds dataTables directly
- $oPage->SetOutputDataOnly(true);
- $aResult = AjaxRenderController::Search($sEncoding, $sFilter);
- $oPage->SetData($aResult);
- break;
+ // Response is a \WebPage, let's handle it like legacy operations
+ $oPage = $mResponse;
+ }
+ // Otherwise, use legacy operation
+ else {
+ // Default for most operations, but can be switch to a \JsonPage, \DownloadPage or else if the operation requires it
+ $oPage = new AjaxPage("");
- case 'refreshDashletCount':
- $oPage->SetContentType('application/json');
- $aResult = AjaxRenderController::RefreshDashletCount($sFilter);
- $oPage->add(json_encode($aResult));
- break;
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ $sEncoding = utils::ReadParam('encoding', 'serialize');
+ $sClass = utils::ReadParam('class', 'MissingAjaxParam', false, 'class');
+ $sStyle = utils::ReadParam('style', 'list');
- case 'refreshDashletList':
- $oPage->SetContentType('application/json');
- $aResult = AjaxRenderController::RefreshDashletList($sStyle, $sFilter);
- $oPage->add(json_encode($aResult));
- break;
- case 'refreshDashletSummary':
- $oPage->SetContentType('text/html');
- $sExtraParams = utils::ReadParam('extra_params', '', false, 'raw_data');
- $aExtraParams = json_decode($sExtraParams, true);
- $aQueryParams = [];
- if (isset($aExtraParams['query_params'])) {
- $aQueryParams = $aExtraParams['query_params'];
- }
- $oFilter = DBObjectSearch::FromOQL($sFilter, $aQueryParams);
- $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
- $oSet = new CMDBObjectSet($oFilter, [], $aExtraParams);
- $oBlock = new displayblock($oFilter, 'summary', false, [], $oSet);
- $oBlock->RenderContent($oPage, $aExtraParams);
- break;
+ $oAjaxRenderController = new AjaxRenderController();
- case 'datatable_save_settings':
- $oPage->SetContentType('text/plain');
- $bRet = AjaxRenderController::DatatableSaveSettings();
- $oPage->add($bRet ? 'Ok' : 'KO');
- break;
+ switch ($operation) {
+ case 'search_and_refresh':
+ $oPage = new JsonPage();
+ // Feeds dataTables directly
+ $oPage->SetOutputDataOnly(true);
+ $aResult = AjaxRenderController::SearchAndRefresh($sFilter);
+ $oPage->SetData($aResult);
+ break;
- case 'datatable_reset_settings':
- $oPage->SetContentType('text/plain');
- $bRet = AjaxRenderController::DatatableResetSettings();
- $oPage->add($bRet ? 'Ok' : 'KO');
- break;
+ case 'search':
+ $oPage = new JsonPage();
+ // Feeds dataTables directly
+ $oPage->SetOutputDataOnly(true);
+ $aResult = AjaxRenderController::Search($sEncoding, $sFilter);
+ $oPage->SetData($aResult);
+ break;
- // ui.searchformforeignkeys
- case 'ShowModalSearchForeignKeys':
- $oPage->SetContentType('text/html');
- $iInputId = utils::ReadParam('iInputId', '');
- $sTitle = utils::ReadParam('sTitle', '', false, 'raw_data');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $oWidget = new UISearchFormForeignKeys($sTargetClass, $iInputId);
- $oWidget->ShowModalSearchForeignKeys($oPage, $sTitle);
- break;
+ case 'refreshDashletCount':
+ $oPage->SetContentType('application/json');
+ $aResult = AjaxRenderController::RefreshDashletCount($sFilter);
+ $oPage->add(json_encode($aResult));
+ break;
- // ui.searchformforeignkeys
- case 'GetFullListForeignKeysFromSelection':
- $oPage->SetContentType('application/json');
- $oWidget = new UISearchFormForeignKeys($sClass);
- $oFullSetFilter = new DBObjectSearch($sClass);
- $oWidget->GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter);
- break;
+ case 'refreshDashletList':
+ $oPage->SetContentType('application/json');
+ $aResult = AjaxRenderController::RefreshDashletList($sStyle, $sFilter);
+ $oPage->add(json_encode($aResult));
+ break;
- // ui.searchformforeignkeys
- case 'ListResultsSearchForeignKeys':
- $oPage->SetContentType('text/html');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $iInputId = utils::ReadParam('iInputId', '');
- $sRemoteClass = utils::ReadParam('sRemoteClass', '', false, 'class');
- $oWidget = new UISearchFormForeignKeys($sTargetClass, $iInputId);
- $oWidget->ListResultsSearchForeignKeys($oPage, $sRemoteClass);
- break;
-
- // ui.linkswidget
- case 'addObjects':
- $oPage->SetContentType('text/html');
- $sAttCode = utils::ReadParam('sAttCode', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $sSuffix = utils::ReadParam('sSuffix', '');
- $bDuplicates = (utils::ReadParam('bDuplicates', 'false') == 'false') ? false : true;
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- if (!empty($sJson))
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- }
- else
- {
- // Search form: no current object
- $oObj = null;
- }
- $oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
- $oAppContext = new ApplicationContext();
- $aPrefillFormParam = array( 'user' => Session::Get("auth_user"),
- 'context' => $oAppContext->GetAsHash(),
- 'att_code' => $sAttCode,
- 'origin' => 'console',
- 'source_obj' => $oObj
- );
- $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
- /** @var \DBObject $oObj */
- $oWidget->GetObjectPickerDialog($oPage, $oObj, $sJson, $aAlreadyLinked, $aPrefillFormParam);
- break;
-
- // ui.linkswidget
- case 'searchObjectsToAdd':
- $oPage->SetContentType('text/html');
- $sRemoteClass = utils::ReadParam('sRemoteClass', '', false, 'class');
- $sAttCode = utils::ReadParam('sAttCode', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $sSuffix = utils::ReadParam('sSuffix', '');
- $bDuplicates = (utils::ReadParam('bDuplicates', 'false') == 'false') ? false : true;
- $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
- $oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
- $oWidget->SearchObjectsToAdd($oPage, $sRemoteClass, $aAlreadyLinked);
- break;
-
- //ui.linksdirectwidget
- case 'createObject':
- $oPage->SetContentType('text/html');
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sRealClass = utils::ReadParam('real_class', '', false, 'class');
- $sAttCode = utils::ReadParam('att_code', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $oPage->SetContentType('text/html');
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- if (!empty($sJson))
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- }
- $oObj = $oWizardHelper->GetTargetObject();
- $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
- $oWidget->GetObjectCreationDlg($oPage, $sRealClass, $oObj);
- break;
-
- // ui.linksdirectwidget
- case 'getLinksetRow':
- $oPage = new JsonPage();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sRealClass = utils::ReadParam('real_class', '', false, 'class');
- $sAttCode = utils::ReadParam('att_code', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $iTempId = utils::ReadParam('tempId', '');
- $aValues = utils::ReadParam('values', array(), false, 'raw_data');
- $oPage->SetContentType('text/html');
- $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
- $oPage->AddData($oWidget->GetFormRow($oPage, $sRealClass, $aValues, -$iTempId));
- break;
-
- // ui.linksdirectwidget
- case 'selectObjectsToAdd':
- $oPage->SetContentType('text/html');
- $sClass = utils::ReadParam('class', '', false, 'class');
- $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- /** @var \DBObject $oObj */
- $oObj = null;
- if ($sJson != '')
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- }
- $sRealClass = utils::ReadParam('real_class', '', false, 'class');
- $sAttCode = utils::ReadParam('att_code', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $iCurrObjectId = utils::ReadParam('iObjId', 0);
- $oPage->SetContentType('text/html');
- $oAppContext = new ApplicationContext();
- $aPrefillFormParam = array( 'user' => Session::Get('auth_user'),
- 'context' => $oAppContext->GetAsHash(),
- 'att_code' => $sAttCode,
- 'origin' => 'console',
- 'source_obj' => $oObj,
- );
- $aPrefillFormParam['dest_class'] = ($oObj === null ? '' : $oObj->Get($sAttCode)->GetClass());
- $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
- $oWidget->GetObjectsSelectionDlg($oPage, $oObj, $aAlreadyLinked, $aPrefillFormParam);
- break;
-
- // ui.linksdirectwidget
- case 'searchObjectsToAdd2':
- $oPage->SetContentType('text/html');
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sRealClass = utils::ReadParam('real_class', '', false, 'class');
- $sAttCode = utils::ReadParam('att_code', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- $oObj = null;
- if ($sJson != '')
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- }
- $oAppContext = new ApplicationContext();
- $aPrefillFormParam = array( 'user' => Session::Get('auth_user'),
- 'context' => $oAppContext->GetAsHash(),
- 'att_code' => $sAttCode,
- 'origin' => 'console',
- 'source_obj' => $oObj,
- );
- $aPrefillFormParam['dest_class'] = ($oObj === null ? '' : $oObj->Get($sAttCode)->GetClass());
- $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
- $oWidget->SearchObjectsToAdd($oPage, $sRealClass, $aAlreadyLinked, $oObj, $aPrefillFormParam);
- break;
-
- // ui.linksdirectwidget
- case 'doAddObjects2':
- $oPage->SetContentType('text/html');
- $oPage->SetContentType('text/html');
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sRealClass = utils::ReadParam('real_class', '', false, 'class');
- $sAttCode = utils::ReadParam('att_code', '');
- $iInputId = utils::ReadParam('iInputId', '');
- $iCurrObjectId = utils::ReadParam('iObjId', 0);
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- if ($sFilter != '')
- {
- $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
- }
- else
- {
- $oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- $valuesDef = $oLinksetDef->GetValuesDef();
- if ($valuesDef === null)
- {
- $oFullSetFilter = new DBObjectSearch($oLinksetDef->GetLinkedClass());
+ case 'refreshDashletSummary':
+ $oPage->SetContentType('text/html');
+ $sExtraParams = utils::ReadParam('extra_params', '', false, 'raw_data');
+ $aExtraParams = json_decode($sExtraParams, true);
+ $aQueryParams = [];
+ if (isset($aExtraParams['query_params'])) {
+ $aQueryParams = $aExtraParams['query_params'];
}
- else
- {
- if (!$valuesDef instanceof ValueSetObjects)
- {
- throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
- }
- $oFullSetFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
- }
- }
- $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
- $oWidget->DoAddObjects($oPage, $oFullSetFilter);
- break;
+ $oFilter = DBObjectSearch::FromOQL($sFilter, $aQueryParams);
+ $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
+ $oSet = new CMDBObjectSet($oFilter, [], $aExtraParams);
+ $oBlock = new displayblock($oFilter, 'summary', false, [], $oSet);
+ $oBlock->RenderContent($oPage, $aExtraParams);
+ break;
- ////////////////////////////////////////////////////////////
+ case 'datatable_save_settings':
+ $oPage->SetContentType('text/plain');
+ $bRet = AjaxRenderController::DatatableSaveSettings();
+ $oPage->add($bRet ? 'Ok' : 'KO');
+ break;
- // ui.extkeywidget
- case 'searchObjectsToSelect':
- $oPage->SetContentType('text/html');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $iInputId = utils::ReadParam('iInputId', '');
- $sRemoteClass = utils::ReadParam('sRemoteClass', '', false, 'class');
- $sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- $sAttCode = utils::ReadParam('sAttCode', '');
- $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
- if (!empty($sJson))
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- }
- else
- {
- // Search form: no current object
- $oObj = null;
- }
- $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
- $oWidget->SearchObjectsToSelect($oPage, $sFilter, $sRemoteClass, $oObj);
- break;
+ case 'datatable_reset_settings':
+ $oPage->SetContentType('text/plain');
+ $bRet = AjaxRenderController::DatatableResetSettings();
+ $oPage->add($bRet ? 'Ok' : 'KO');
+ break;
- // ui.extkeywidget: autocomplete
- case 'ac_extkey':
- $oPage->SetContentType('text/plain');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $iInputId = utils::ReadParam('iInputId', '');
- $sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- $sContains = utils::ReadParam('q', '', false, 'raw_data');
- $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
- $sOutputFormat = utils::ReadParam('sOutputFormat', UIExtKeyWidget::ENUM_OUTPUT_FORMAT_CSV, false, 'raw_data');
- if ($sContains != '')
- {
- if (!empty($sJson))
- {
+ // ui.searchformforeignkeys
+ case 'ShowModalSearchForeignKeys':
+ $oPage->SetContentType('text/html');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sTitle = utils::ReadParam('sTitle', '', false, 'raw_data');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $oWidget = new UISearchFormForeignKeys($sTargetClass, $iInputId);
+ $oWidget->ShowModalSearchForeignKeys($oPage, $sTitle);
+ break;
+
+ // ui.searchformforeignkeys
+ case 'GetFullListForeignKeysFromSelection':
+ $oPage->SetContentType('application/json');
+ $oWidget = new UISearchFormForeignKeys($sClass);
+ $oFullSetFilter = new DBObjectSearch($sClass);
+ $oWidget->GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter);
+ break;
+
+ // ui.searchformforeignkeys
+ case 'ListResultsSearchForeignKeys':
+ $oPage->SetContentType('text/html');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sRemoteClass = utils::ReadParam('sRemoteClass', '', false, 'class');
+ $oWidget = new UISearchFormForeignKeys($sTargetClass, $iInputId);
+ $oWidget->ListResultsSearchForeignKeys($oPage, $sRemoteClass);
+ break;
+
+ // ui.linkswidget
+ case 'addObjects':
+ $oPage->SetContentType('text/html');
+ $sAttCode = utils::ReadParam('sAttCode', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sSuffix = utils::ReadParam('sSuffix', '');
+ $bDuplicates = (utils::ReadParam('bDuplicates', 'false') == 'false') ? false : true;
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ if (!empty($sJson)) {
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
- }
- else
- {
+ } else {
// Search form: no current object
$oObj = null;
}
+ $oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
+ $oAppContext = new ApplicationContext();
+ $aPrefillFormParam = array(
+ 'user' => Session::Get("auth_user"),
+ 'context' => $oAppContext->GetAsHash(),
+ 'att_code' => $sAttCode,
+ 'origin' => 'console',
+ 'source_obj' => $oObj
+ );
+ $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
+ /** @var \DBObject $oObj */
+ $oWidget->GetObjectPickerDialog($oPage, $oObj, $sJson, $aAlreadyLinked, $aPrefillFormParam);
+ break;
+
+ // ui.linkswidget
+ case 'searchObjectsToAdd':
+ $oPage->SetContentType('text/html');
+ $sRemoteClass = utils::ReadParam('sRemoteClass', '', false, 'class');
+ $sAttCode = utils::ReadParam('sAttCode', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sSuffix = utils::ReadParam('sSuffix', '');
+ $bDuplicates = (utils::ReadParam('bDuplicates', 'false') == 'false') ? false : true;
+ $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
+ $oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
+ $oWidget->SearchObjectsToAdd($oPage, $sRemoteClass, $aAlreadyLinked);
+ break;
+
+ //ui.linksdirectwidget
+ case 'createObject':
+ $oPage->SetContentType('text/html');
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sRealClass = utils::ReadParam('real_class', '', false, 'class');
+ $sAttCode = utils::ReadParam('att_code', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $oPage->SetContentType('text/html');
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ if (!empty($sJson)) {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ }
+ $oObj = $oWizardHelper->GetTargetObject();
+ $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
+ $oWidget->GetObjectCreationDlg($oPage, $sRealClass, $oObj);
+ break;
+
+ // ui.linksdirectwidget
+ case 'getLinksetRow':
+ $oPage = new JsonPage();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sRealClass = utils::ReadParam('real_class', '', false, 'class');
+ $sAttCode = utils::ReadParam('att_code', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $iTempId = utils::ReadParam('tempId', '');
+ $aValues = utils::ReadParam('values', array(), false, 'raw_data');
+ $oPage->SetContentType('text/html');
+ $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
+ $oPage->AddData($oWidget->GetFormRow($oPage, $sRealClass, $aValues, -$iTempId));
+ break;
+
+ // ui.linksdirectwidget
+ case 'selectObjectsToAdd':
+ $oPage->SetContentType('text/html');
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ /** @var \DBObject $oObj */
+ $oObj = null;
+ if ($sJson != '') {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ }
+ $sRealClass = utils::ReadParam('real_class', '', false, 'class');
+ $sAttCode = utils::ReadParam('att_code', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $iCurrObjectId = utils::ReadParam('iObjId', 0);
+ $oPage->SetContentType('text/html');
+ $oAppContext = new ApplicationContext();
+ $aPrefillFormParam = array(
+ 'user' => Session::Get('auth_user'),
+ 'context' => $oAppContext->GetAsHash(),
+ 'att_code' => $sAttCode,
+ 'origin' => 'console',
+ 'source_obj' => $oObj,
+ );
+ $aPrefillFormParam['dest_class'] = ($oObj === null ? '' : $oObj->Get($sAttCode)->GetClass());
+ $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
+ $oWidget->GetObjectsSelectionDlg($oPage, $oObj, $aAlreadyLinked, $aPrefillFormParam);
+ break;
+
+ // ui.linksdirectwidget
+ case 'searchObjectsToAdd2':
+ $oPage->SetContentType('text/html');
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sRealClass = utils::ReadParam('real_class', '', false, 'class');
+ $sAttCode = utils::ReadParam('att_code', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $aAlreadyLinked = utils::ReadParam('aAlreadyLinked', array());
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ $oObj = null;
+ if ($sJson != '') {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ }
+ $oAppContext = new ApplicationContext();
+ $aPrefillFormParam = array(
+ 'user' => Session::Get('auth_user'),
+ 'context' => $oAppContext->GetAsHash(),
+ 'att_code' => $sAttCode,
+ 'origin' => 'console',
+ 'source_obj' => $oObj,
+ );
+ $aPrefillFormParam['dest_class'] = ($oObj === null ? '' : $oObj->Get($sAttCode)->GetClass());
+ $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
+ $oWidget->SearchObjectsToAdd($oPage, $sRealClass, $aAlreadyLinked, $oObj, $aPrefillFormParam);
+ break;
+
+ // ui.linksdirectwidget
+ case 'doAddObjects2':
+ $oPage->SetContentType('text/html');
+ $oPage->SetContentType('text/html');
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sRealClass = utils::ReadParam('real_class', '', false, 'class');
+ $sAttCode = utils::ReadParam('att_code', '');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $iCurrObjectId = utils::ReadParam('iObjId', 0);
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ if ($sFilter != '') {
+ $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
+ } else {
+ $oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $valuesDef = $oLinksetDef->GetValuesDef();
+ if ($valuesDef === null) {
+ $oFullSetFilter = new DBObjectSearch($oLinksetDef->GetLinkedClass());
+ } else {
+ if (!$valuesDef instanceof ValueSetObjects) {
+ throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
+ }
+ $oFullSetFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
+ }
+ }
+ $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iInputId);
+ $oWidget->DoAddObjects($oPage, $oFullSetFilter);
+ break;
+
+ ////////////////////////////////////////////////////////////
+
+ // ui.extkeywidget
+ case 'searchObjectsToSelect':
+ $oPage->SetContentType('text/html');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sRemoteClass = utils::ReadParam('sRemoteClass', '', false, 'class');
+ $sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ $sAttCode = utils::ReadParam('sAttCode', '');
+ $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
+ if (!empty($sJson)) {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ } else {
+ // Search form: no current object
+ $oObj = null;
+ }
+ $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
+ $oWidget->SearchObjectsToSelect($oPage, $sFilter, $sRemoteClass, $oObj);
+ break;
+
+ // ui.extkeywidget: autocomplete
+ case 'ac_extkey':
+ $oPage->SetContentType('text/plain');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ $sContains = utils::ReadParam('q', '', false, 'raw_data');
+ $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
+ $sOutputFormat = utils::ReadParam('sOutputFormat', UIExtKeyWidget::ENUM_OUTPUT_FORMAT_CSV, false, 'raw_data');
+ if ($sContains != '') {
+ if (!empty($sJson)) {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ } else {
+ // Search form: no current object
+ $oObj = null;
+ }
+ $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, '', $bSearchMode);
+ $oWidget->AutoComplete($oPage, $sFilter, $oObj, $sContains, $sOutputFormat);
+ }
+ break;
+
+ // ui.extkeywidget
+ case 'objectSearchForm':
+ $oPage->SetContentType('text/html');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $sFilter = utils::ReadParam('sFilter', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sTitle = utils::ReadParam('sTitle', '', false, 'raw_data');
+ $sAttCode = utils::ReadParam('sAttCode', '');
+ $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
+ $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode, $sFilter);
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ if (!empty($sJson)) {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ } else {
+ // Search form: no current object
+ $oObj = null;
+ }
+ $oWidget->GetSearchDialog($oPage, $sTitle, $oObj);
+ break;
+
+ // ui.extkeywidget
+ case 'objectCreationForm':
+ $oPage->SetContentType('text/html');
+ // Retrieving parameters
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sAttCode = utils::ReadParam('sAttCode', '');
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ // Building form, if target class is abstract we ask the user for the desired leaf class
+ $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
+ if (MetaModel::IsAbstract($sTargetClass)) {
+ $oWidget->GetClassSelectionForm($oPage);
+ } else {
+ $aPrefillFormParam = array();
+ if (!empty($sJson)) {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ $oAppContext = new ApplicationContext();
+ $aPrefillFormParam = array(
+ 'user' => Session::Get('auth_user'),
+ 'context' => $oAppContext->GetAsHash(),
+ 'att_code' => $sAttCode,
+ 'source_obj' => $oObj,
+ 'origin' => 'console'
+ );
+ } else {
+ // Search form: no current object
+ $oObj = null;
+ }
+ $oWidget->GetObjectCreationForm($oPage, $oObj, $aPrefillFormParam);
+ }
+ break;
+
+ // ui.extkeywidget
+ case 'doCreateObject':
+ $oPage->SetContentType('application/json');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $sFormPrefix = utils::ReadParam('sFormPrefix', '');
+ $sAttCode = utils::ReadParam('sAttCode', '');
+ $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
+ $aResult = $oWidget->DoCreateObject($oPage);
+ echo json_encode($aResult);
+ break;
+
+ // ui.extkeywidget
+ case 'getObjectName':
+ $oPage->SetContentType('application/json');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $iInputId = utils::ReadParam('iInputId', '');
+ $iObjectId = utils::ReadParam('iObjectId', '');
+ $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
+ $sFormAttCode = utils::ReadParam('sFormAttCode', null);
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, '', $bSearchMode);
- $oWidget->AutoComplete($oPage, $sFilter, $oObj, $sContains, $sOutputFormat);
- }
- break;
+ $sName = $oWidget->GetObjectName($iObjectId, $sFormAttCode);
+ echo json_encode(array('name' => $sName));
+ break;
- // ui.extkeywidget
- case 'objectSearchForm':
- $oPage->SetContentType('text/html');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $sFilter = utils::ReadParam('sFilter', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
- $iInputId = utils::ReadParam('iInputId', '');
- $sTitle = utils::ReadParam('sTitle', '', false, 'raw_data');
- $sAttCode = utils::ReadParam('sAttCode', '');
- $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
- $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode, $sFilter);
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- if (!empty($sJson)) {
+ // ui.extkeywidget
+ case 'displayHierarchy':
+ $oPage->SetContentType('text/html');
+ $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
+ $sInputId = utils::ReadParam('sInputId', '');
+ $sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
+ $sJson = utils::ReadParam('json', '', false, 'raw_data');
+ $currValue = utils::ReadParam('value', '');
+ $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
+ if (!empty($sJson)) {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
+ } else {
+ // Search form: no current object
+ $oObj = null;
+ }
+ $oWidget = new UIExtKeyWidget($sTargetClass, $sInputId, '', $bSearchMode);
+ $oWidget->DisplayHierarchy($oPage, $sFilter, $currValue, $oObj);
+ break;
+
+ ////////////////////////////////////////////////////
+
+ // ui.linkswidget
+ case 'doAddObjects':
+ $oPage->SetContentType('text/html');
+ AjaxRenderController::DoAddObjects($oPage, $sClass, $sFilter);
+ break;
+
+ // ui.linkswidget
+ case 'doAddIndirectLinks':
+ $oPage = new JsonPage();
+ AjaxRenderController::DoAddIndirectLinks($oPage, $sClass, $sFilter);
+ break;
+ ////////////////////////////////////////////////////////////
+ /// WizardHelper : see the corresponding PHP class, and JS class
+
+ case 'wizard_helper_preview':
+ $oPage->SetContentType('text/html');
+ $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
- } else {
- // Search form: no current object
- $oObj = null;
- }
- $oWidget->GetSearchDialog($oPage, $sTitle, $oObj);
- break;
+ $oObj->DisplayBareProperties($oPage);
+ break;
- // ui.extkeywidget
- case 'objectCreationForm':
- $oPage->SetContentType('text/html');
- // Retrieving parameters
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $iInputId = utils::ReadParam('iInputId', '');
- $sAttCode = utils::ReadParam('sAttCode', '');
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- // Building form, if target class is abstract we ask the user for the desired leaf class
- $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
- if(MetaModel::IsAbstract($sTargetClass))
- {
- $oWidget->GetClassSelectionForm($oPage);
- }
- else
- {
- $aPrefillFormParam = array();
- if (!empty($sJson))
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- $oAppContext = new ApplicationContext();
- $aPrefillFormParam = array( 'user' => Session::Get('auth_user'),
- 'context' => $oAppContext->GetAsHash(),
- 'att_code' => $sAttCode,
- 'source_obj' => $oObj,
- 'origin' => 'console'
- );
- }
- else
- {
- // Search form: no current object
- $oObj = null;
- }
- $oWidget->GetObjectCreationForm($oPage, $oObj, $aPrefillFormParam);
- }
- break;
-
- // ui.extkeywidget
- case 'doCreateObject':
- $oPage->SetContentType('application/json');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $iInputId = utils::ReadParam('iInputId', '');
- $sFormPrefix = utils::ReadParam('sFormPrefix', '');
- $sAttCode = utils::ReadParam('sAttCode', '');
- $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
- $aResult = $oWidget->DoCreateObject($oPage);
- echo json_encode($aResult);
- break;
+ case 'wizard_helper':
+ $oPage->SetContentType('text/html');
+ $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ /** @var \DBObject $oObj */
+ $oObj = $oWizardHelper->GetTargetObject();
+ $sClass = $oWizardHelper->GetTargetClass();
+ foreach ($oWizardHelper->GetFieldsForDefaultValue() as $sAttCode) {
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $defaultValue = $oAttDef->GetDefaultValue($oObj);
+ $oWizardHelper->SetDefaultValue($sAttCode, $defaultValue);
+ $oObj->Set($sAttCode, $defaultValue);
+ }
+ $sFormPrefix = $oWizardHelper->GetFormPrefix();
+ $aExpectedAttributes = ($oWizardHelper->GetStimulus() === null) ? array() : $oObj->GetTransitionAttributes($oWizardHelper->GetStimulus(), $oWizardHelper->GetInitialState());
+ foreach ($oWizardHelper->GetFieldsForAllowedValues() as $sAttCode) {
+ $sId = $oWizardHelper->GetIdForField($sAttCode);
+ if ($sId != '') {
+ if (array_key_exists($sAttCode, $aExpectedAttributes)) {
+ $iFlags = $aExpectedAttributes[$sAttCode];
+ } elseif ($oObj->IsNew()) {
+ $iFlags = $oObj->GetInitialStateAttributeFlags($sAttCode);
+ } else {
+ $iFlags = $oObj->GetAttributeFlags($sAttCode);
+ }
+ if ($iFlags & OPT_ATT_READONLY) {
+ $sHTMLValue = "".$oObj->GetAsHTML($sAttCode);
+ $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
+ } else {
+ // It may happen that the field we'd like to update does not
+ // exist in the form. For example, if the field should be hidden/read-only
+ // in the current state of the object
+ $value = $oObj->Get($sAttCode);
+ $displayValue = $oObj->GetEditValue($sAttCode);
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ if (!$oAttDef->IsWritable() || ($oWizardHelper->GetReturnNotEditableFields())) {
+ // Even non-writable fields (like AttributeExternal) can be refreshed
+ $sHTMLValue = "".$oObj->GetAsHTML($sAttCode)."
";
+ } else {
+ $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value,
+ $displayValue, $sId, '', $iFlags, array('this' => $oObj, 'formPrefix' => $sFormPrefix), false);
+ // Make sure that we immediately validate the field when we reload it
+ $oPage->add_ready_script("$('#$sId').trigger('validate');");
+ }
+ $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
+ }
+ }
+ }
+ $oPage->add_script($oWizardHelper->GetJsForUpdateFields());
+ break;
- // ui.extkeywidget
- case 'getObjectName':
- $oPage->SetContentType('application/json');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $iInputId = utils::ReadParam('iInputId', '');
- $iObjectId = utils::ReadParam('iObjectId', '');
- $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
- $sFormAttCode = utils::ReadParam('sFormAttCode', null);
- $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, '', $bSearchMode);
- $sName = $oWidget->GetObjectName($iObjectId, $sFormAttCode);
- echo json_encode(array('name' => $sName));
- break;
-
- // ui.extkeywidget
- case 'displayHierarchy':
- $oPage->SetContentType('text/html');
- $sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
- $sInputId = utils::ReadParam('sInputId', '');
- $sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
- $sJson = utils::ReadParam('json', '', false, 'raw_data');
- $currValue = utils::ReadParam('value', '');
- $bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
- if (!empty($sJson))
- {
+ case 'obj_creation_form':
+ $oPage->SetContentType('text/html');
+ $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
- }
- else
- {
- // Search form: no current object
- $oObj = null;
- }
- $oWidget = new UIExtKeyWidget($sTargetClass, $sInputId, '', $bSearchMode);
- $oWidget->DisplayHierarchy($oPage, $sFilter, $currValue, $oObj);
- break;
+ $sClass = $oWizardHelper->GetTargetClass();
+ $sTargetState = utils::ReadParam('target_state', '');
+ $iTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
+ $oObj->Set(MetaModel::GetStateAttributeCode($sClass), $sTargetState);
+ cmdbAbstractObject::DisplayCreationForm($oPage, $sClass, $oObj, array(), array('action' => utils::GetAbsoluteUrlAppRoot().'pages/UI.php', 'transaction_id' => $iTransactionId));
+ break;
- ////////////////////////////////////////////////////
-
- // ui.linkswidget
- case 'doAddObjects':
- $oPage->SetContentType('text/html');
- AjaxRenderController::DoAddObjects($oPage, $sClass, $sFilter);
- break;
-
- // ui.linkswidget
- case 'doAddIndirectLinks':
- $oPage = new JsonPage();
- AjaxRenderController::DoAddIndirectLinks($oPage, $sClass, $sFilter);
- break;
- ////////////////////////////////////////////////////////////
- /// WizardHelper : see the corresponding PHP class, and JS class
-
- case 'wizard_helper_preview':
- $oPage->SetContentType('text/html');
- $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- $oObj->DisplayBareProperties($oPage);
- break;
-
- case 'wizard_helper':
- $oPage->SetContentType('text/html');
- $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- /** @var \DBObject $oObj */
- $oObj = $oWizardHelper->GetTargetObject();
- $sClass = $oWizardHelper->GetTargetClass();
- foreach($oWizardHelper->GetFieldsForDefaultValue() as $sAttCode)
- {
- $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- $defaultValue = $oAttDef->GetDefaultValue($oObj);
- $oWizardHelper->SetDefaultValue($sAttCode, $defaultValue);
- $oObj->Set($sAttCode, $defaultValue);
- }
- $sFormPrefix = $oWizardHelper->GetFormPrefix();
- $aExpectedAttributes = ($oWizardHelper->GetStimulus() === null) ? array() : $oObj->GetTransitionAttributes($oWizardHelper->GetStimulus(), $oWizardHelper->GetInitialState());
- foreach($oWizardHelper->GetFieldsForAllowedValues() as $sAttCode)
- {
- $sId = $oWizardHelper->GetIdForField($sAttCode);
- if ($sId != '')
- {
- if (array_key_exists($sAttCode, $aExpectedAttributes))
- {
- $iFlags = $aExpectedAttributes[$sAttCode];
+ // DisplayBlock
+ case 'ajax':
+ $oPage->SetContentType('text/html');
+ if ($sFilter != "") {
+ $sExtraParams = stripslashes(utils::ReadParam('extra_params', '', false, 'raw_data'));
+ $aExtraParams = array();
+ if (!empty($sExtraParams)) {
+ $aExtraParams = json_decode(str_replace("'", '"', $sExtraParams), true /* associative array */);
}
- elseif ($oObj->IsNew())
- {
- $iFlags = $oObj->GetInitialStateAttributeFlags($sAttCode);
- }
- else
- {
- $iFlags = $oObj->GetAttributeFlags($sAttCode);
- }
- if ($iFlags & OPT_ATT_READONLY)
- {
- $sHTMLValue = "".$oObj->GetAsHTML($sAttCode);
- $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
- }
- else
- {
- // It may happen that the field we'd like to update does not
- // exist in the form. For example, if the field should be hidden/read-only
- // in the current state of the object
- $value = $oObj->Get($sAttCode);
- $displayValue = $oObj->GetEditValue($sAttCode);
- $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- if (!$oAttDef->IsWritable() || ($oWizardHelper->GetReturnNotEditableFields()))
- {
- // Even non-writable fields (like AttributeExternal) can be refreshed
- $sHTMLValue = "".$oObj->GetAsHTML($sAttCode)."
";
+ // Restore the app context from the ExtraParams
+ $oAppContext = new ApplicationContext(false); // false => don't read the context yet !
+ $aContext = array();
+ foreach ($oAppContext->GetNames() as $sName) {
+ $sParamName = 'c['.$sName.']';
+ if (isset($aExtraParams[$sParamName])) {
+ $aContext[$sName] = $aExtraParams[$sParamName];
}
- else
- {
- $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value,
- $displayValue, $sId, '', $iFlags, array('this' => $oObj, 'formPrefix' => $sFormPrefix), false);
- // Make sure that we immediately validate the field when we reload it
- $oPage->add_ready_script("$('#$sId').trigger('validate');");
+ }
+ $_REQUEST['c'] = $aContext;
+ if ($sEncoding == 'oql') {
+ $oFilter = DBSearch::FromOQL($sFilter);
+ } else {
+ try {
+ $oFilter = DBSearch::unserialize($sFilter);
+ }
+ catch (CoreException $e) {
+ $sFilter = utils::HtmlEntities($sFilter);
+ $oPage->p("Invalid query (invalid filter) : $sFilter");
+ IssueLog::Error("ajax.render operation='ajax', invalid DBSearch filter param : $sFilter");
+ break;
}
- $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
}
+ $oDisplayBlock = new DisplayBlock($oFilter, $sStyle, false);
+ $aExtraParams['display_limit'] = true;
+ $oDisplayBlock->RenderContent($oPage, $aExtraParams);
+ } else {
+ $oPage->p("Invalid query (empty filter).");
}
- }
- $oPage->add_script($oWizardHelper->GetJsForUpdateFields());
- break;
+ break;
- case 'obj_creation_form':
- $oPage->SetContentType('text/html');
- $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
- $sClass = $oWizardHelper->GetTargetClass();
- $sTargetState = utils::ReadParam('target_state', '');
- $iTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
- $oObj->Set(MetaModel::GetStateAttributeCode($sClass), $sTargetState);
- cmdbAbstractObject::DisplayCreationForm($oPage, $sClass, $oObj, array(), array('action' => utils::GetAbsoluteUrlAppRoot().'pages/UI.php', 'transaction_id' => $iTransactionId));
- break;
+ case 'displayCSVHistory':
+ $oPage->SetContentType('text/html');
+ $bShowAll = (utils::ReadParam('showall', 'false') == 'true');
+ BulkChange::DisplayImportHistory($oPage, true, $bShowAll);
+ break;
- // DisplayBlock
- case 'ajax':
- $oPage->SetContentType('text/html');
- if ($sFilter != "")
- {
- $sExtraParams = stripslashes(utils::ReadParam('extra_params', '', false, 'raw_data'));
- $aExtraParams = array();
- if (!empty($sExtraParams))
- {
- $aExtraParams = json_decode(str_replace("'", '"', $sExtraParams), true /* associative array */);
- }
- // Restore the app context from the ExtraParams
- $oAppContext = new ApplicationContext(false); // false => don't read the context yet !
- $aContext = array();
- foreach($oAppContext->GetNames() as $sName)
- {
- $sParamName = 'c['.$sName.']';
- if (isset($aExtraParams[$sParamName]))
- {
- $aContext[$sName] = $aExtraParams[$sParamName];
- }
- }
- $_REQUEST['c'] = $aContext;
- if ($sEncoding == 'oql')
- {
- $oFilter = DBSearch::FromOQL($sFilter);
- }
- else
- {
- try
- {
+ case 'details':
+ $oPage->SetContentType('text/html');
+ $key = utils::ReadParam('id', 0);
+ $oFilter = new DBObjectSearch($sClass);
+ $oFilter->AddCondition('id', $key, '=');
+ $oDisplayBlock = new DisplayBlock($oFilter, 'details', false);
+ $oDisplayBlock->RenderContent($oPage);
+ break;
+
+ case 'pie_chart':
+ $oPage->SetContentType('application/json');
+ $sGroupBy = utils::ReadParam('group_by', '');
+ if ($sFilter != '') {
+ if ($sEncoding == 'oql') {
+ $oFilter = DBSearch::FromOQL($sFilter);
+ } else {
$oFilter = DBSearch::unserialize($sFilter);
}
- catch (CoreException $e)
- {
- $sFilter = utils::HtmlEntities($sFilter);
- $oPage->p("Invalid query (invalid filter) : $sFilter");
- IssueLog::Error("ajax.render operation='ajax', invalid DBSearch filter param : $sFilter");
- break;
- }
- }
- $oDisplayBlock = new DisplayBlock($oFilter, $sStyle, false);
- $aExtraParams['display_limit'] = true;
- $oDisplayBlock->RenderContent($oPage, $aExtraParams);
- }
- else
- {
- $oPage->p("Invalid query (empty filter).");
- }
- break;
-
- case 'displayCSVHistory':
- $oPage->SetContentType('text/html');
- $bShowAll = (utils::ReadParam('showall', 'false') == 'true');
- BulkChange::DisplayImportHistory($oPage, true, $bShowAll);
- break;
-
- case 'details':
- $oPage->SetContentType('text/html');
- $key = utils::ReadParam('id', 0);
- $oFilter = new DBObjectSearch($sClass);
- $oFilter->AddCondition('id', $key, '=');
- $oDisplayBlock = new DisplayBlock($oFilter, 'details', false);
- $oDisplayBlock->RenderContent($oPage);
- break;
-
- case 'pie_chart':
- $oPage->SetContentType('application/json');
- $sGroupBy = utils::ReadParam('group_by', '');
- if ($sFilter != '')
- {
- if ($sEncoding == 'oql')
- {
- $oFilter = DBSearch::FromOQL($sFilter);
- }
- else
- {
- $oFilter = DBSearch::unserialize($sFilter);
- }
- $oDisplayBlock = new DisplayBlock($oFilter, 'pie_chart_ajax', false);
- $oDisplayBlock->RenderContent($oPage, array('group_by' => $sGroupBy));
- }
- else
- {
-
- $oPage->add("\n3d pie \n.");
- }
- break;
-
- case 'chart':
- $iRefresh = utils::ReadParam('refresh', '-1', false, 'int');
- if ($iRefresh != -1) {
- $oPage->SetContentType('application/json');
- $aParams = utils::ReadParam('params', array(), false, 'raw_data');
- if ($sFilter != '') {
- $oFilter = DBObjectSearch::FromOQL($sFilter);
- $oDisplayBlock = new DisplayBlock($oFilter, 'chart_ajax', false);
- $oBlock = $oDisplayBlock->GetRenderContent($oPage, $aParams, $aParams['currentId']);
- $sChartType = isset($aParams['chart_type']) ? $aParams['chart_type'] : 'pie';
- switch ($sChartType) {
- case 'bars':
- $aResult['type'] = 'bars';
- //$aResult['JSNames'] = str_replace('"','\'',$oBlock->sJSNames);
- $aResult['Json'] = str_replace('"', '\'', $oBlock->sJson);
- $aResult['JSURLs'] = str_replace('"', '\'', $oBlock->sJSURLs);
- $aResult['js'] = 'charts['.$iRefresh.'].load({json: '.str_replace('"', '\'', $oBlock->sJson).
- ',keys: { x: \'label\', value: [\'value\']'.
- '},onclick: function (d) { var aURLs = $.parseJSON('.str_replace('"', '\'', $oBlock->sJSURLs).'); window.location.href= aURLs[d.index]; }})';
- break;
-
- case 'pie':
- $aResult['type'] = 'pie';
- $aResult['JSColumns'] = str_replace('"', '\'', $oBlock->sJSColumns);
- $aResult['JSNames'] = str_replace('"', '\'', $oBlock->sJSNames);
- //$aResult['JSNames'] = json_decode($oBlock->sJSNames);
- $aResult['JSURLs'] = str_replace('"', '\'', $oBlock->sJSURLs);
- $aResult['js'] = 'charts['.$iRefresh.'].load({columns: '.str_replace('"', '\'', $oBlock->sJSColumns).
- ',names: '.str_replace('"', '\'', $oBlock->sJSNames).
- ',onclick: function (d) { var aURLs = $.parseJSON('.str_replace('"', '\'', $oBlock->sJSURLs).'); window.location.href= aURLs[d.index]; }})';
- break;
- }
- } else {
- $aResult = [];
- }
-
- $oPage->add(json_encode($aResult));
- } else {
- // Workaround for IE8 + IIS + HTTPS
- // See TRAC #363, fix described here: http://forums.codecharge.com/posts.php?post_id=97771
- $oPage->add_header("Cache-Control: cache, must-revalidate");
- $oPage->add_header("Pragma: public");
- $oPage->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT");
-
- $aParams = utils::ReadParam('params', array(), false, 'raw_data');
- if ($sFilter != '') {
- $oFilter = DBSearch::unserialize($sFilter);
- $oDisplayBlock = new DisplayBlock($oFilter, 'chart_ajax', false);
- $oDisplayBlock->RenderContent($oPage, $aParams);
+ $oDisplayBlock = new DisplayBlock($oFilter, 'pie_chart_ajax', false);
+ $oDisplayBlock->RenderContent($oPage, array('group_by' => $sGroupBy));
} else {
$oPage->add("\n3d pie \n.");
}
- }
- break;
+ break;
- case 'modal_details':
- $oPage->SetContentType('text/html');
- $key = utils::ReadParam('id', 0);
- $oFilter = new DBObjectSearch($sClass);
- $oFilter->AddCondition('id', $key, '=');
- $oPage->Add("Object Details
\n");
- $oDisplayBlock = new DisplayBlock($oFilter, 'details', false);
- $oDisplayBlock->RenderContent($oPage);
- $oPage->Add(" \n");
- break;
+ case 'chart':
+ $iRefresh = utils::ReadParam('refresh', '-1', false, 'int');
+ if ($iRefresh != -1) {
+ $oPage->SetContentType('application/json');
+ $aParams = utils::ReadParam('params', array(), false, 'raw_data');
+ if ($sFilter != '') {
+ $oFilter = DBObjectSearch::FromOQL($sFilter);
+ $oDisplayBlock = new DisplayBlock($oFilter, 'chart_ajax', false);
+ $oBlock = $oDisplayBlock->GetRenderContent($oPage, $aParams, $aParams['currentId']);
+ $sChartType = isset($aParams['chart_type']) ? $aParams['chart_type'] : 'pie';
+ switch ($sChartType) {
+ case 'bars':
+ $aResult['type'] = 'bars';
+ //$aResult['JSNames'] = str_replace('"','\'',$oBlock->sJSNames);
+ $aResult['Json'] = str_replace('"', '\'', $oBlock->sJson);
+ $aResult['JSURLs'] = str_replace('"', '\'', $oBlock->sJSURLs);
+ $aResult['js'] = 'charts['.$iRefresh.'].load({json: '.str_replace('"', '\'', $oBlock->sJson).
+ ',keys: { x: \'label\', value: [\'value\']'.
+ '},onclick: function (d) { var aURLs = $.parseJSON('.str_replace('"', '\'', $oBlock->sJSURLs).'); window.location.href= aURLs[d.index]; }})';
+ break;
- case 'link':
- $oPage->SetContentType('text/html');
- $sClass = utils::ReadParam('sclass', 'logInfra', false, 'class');
- $sAttCode = utils::ReadParam('attCode', 'name');
- //$sOrg = utils::ReadParam('org_id', '');
- $sName = utils::ReadParam('q', '');
- $iMaxCount = utils::ReadParam('max', 30);
- $iCount = 0;
- $oFilter = new DBObjectSearch($sClass);
- $oFilter->AddCondition($sAttCode, $sName, 'Begins with');
- //$oFilter->AddCondition('org_id', $sOrg, '=');
- $oSet = new CMDBObjectSet($oFilter, array($sAttCode => true));
- while (($iCount < $iMaxCount) && ($oObj = $oSet->fetch()))
- {
- $oPage->add($oObj->GetAsHTML($sAttCode)."|".$oObj->GetKey()."\n");
- $iCount++;
- }
- break;
+ case 'pie':
+ $aResult['type'] = 'pie';
+ $aResult['JSColumns'] = str_replace('"', '\'', $oBlock->sJSColumns);
+ $aResult['JSNames'] = str_replace('"', '\'', $oBlock->sJSNames);
+ //$aResult['JSNames'] = json_decode($oBlock->sJSNames);
+ $aResult['JSURLs'] = str_replace('"', '\'', $oBlock->sJSURLs);
+ $aResult['js'] = 'charts['.$iRefresh.'].load({columns: '.str_replace('"', '\'', $oBlock->sJSColumns).
+ ',names: '.str_replace('"', '\'', $oBlock->sJSNames).
+ ',onclick: function (d) { var aURLs = $.parseJSON('.str_replace('"', '\'', $oBlock->sJSURLs).'); window.location.href= aURLs[d.index]; }})';
+ break;
+ }
+ } else {
+ $aResult = [];
+ }
- case 'combo_options':
- $oPage->SetContentType('text/html');
- $oFilter = DBSearch::FromOQL($sFilter);
- $oSet = new CMDBObjectSet($oFilter);
- while ($oObj = $oSet->fetch())
- {
- $oPage->add(''.$oObj->GetName().' ');
- }
- break;
+ $oPage->add(json_encode($aResult));
+ } else {
+ // Workaround for IE8 + IIS + HTTPS
+ // See TRAC #363, fix described here: http://forums.codecharge.com/posts.php?post_id=97771
+ $oPage->add_header("Cache-Control: cache, must-revalidate");
+ $oPage->add_header("Pragma: public");
+ $oPage->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT");
- case 'display_document':
- $id = utils::ReadParam('id', '');
- $sField = utils::ReadParam('field', '');
- if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField))
- {
+ $aParams = utils::ReadParam('params', array(), false, 'raw_data');
+ if ($sFilter != '') {
+ $oFilter = DBSearch::unserialize($sFilter);
+ $oDisplayBlock = new DisplayBlock($oFilter, 'chart_ajax', false);
+ $oDisplayBlock->RenderContent($oPage, $aParams);
+ } else {
+
+ $oPage->add("\n3d pie \n.");
+ }
+ }
+ break;
+
+ case 'modal_details':
+ $oPage->SetContentType('text/html');
+ $key = utils::ReadParam('id', 0);
+ $oFilter = new DBObjectSearch($sClass);
+ $oFilter->AddCondition('id', $key, '=');
+ $oPage->Add("Object Details
\n");
+ $oDisplayBlock = new DisplayBlock($oFilter, 'details', false);
+ $oDisplayBlock->RenderContent($oPage);
+ $oPage->Add(" \n");
+ break;
+
+ case 'link':
+ $oPage->SetContentType('text/html');
+ $sClass = utils::ReadParam('sclass', 'logInfra', false, 'class');
+ $sAttCode = utils::ReadParam('attCode', 'name');
+ //$sOrg = utils::ReadParam('org_id', '');
+ $sName = utils::ReadParam('q', '');
+ $iMaxCount = utils::ReadParam('max', 30);
+ $iCount = 0;
+ $oFilter = new DBObjectSearch($sClass);
+ $oFilter->AddCondition($sAttCode, $sName, 'Begins with');
+ //$oFilter->AddCondition('org_id', $sOrg, '=');
+ $oSet = new CMDBObjectSet($oFilter, array($sAttCode => true));
+ while (($iCount < $iMaxCount) && ($oObj = $oSet->fetch())) {
+ $oPage->add($oObj->GetAsHTML($sAttCode)."|".$oObj->GetKey()."\n");
+ $iCount++;
+ }
+ break;
+
+ case 'combo_options':
+ $oPage->SetContentType('text/html');
+ $oFilter = DBSearch::FromOQL($sFilter);
+ $oSet = new CMDBObjectSet($oFilter);
+ while ($oObj = $oSet->fetch()) {
+ $oPage->add(''.$oObj->GetName().' ');
+ }
+ break;
+
+ case 'display_document':
+ $id = utils::ReadParam('id', '');
+ $sField = utils::ReadParam('field', '');
+ if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) {
+ $oPage = new DownloadPage('');
+ // X-Frame http header : set in page constructor, but we need to allow frame integration for this specific page
+ // so we're resetting its value ! (see N°3416)
+ $oPage->add_xframe_options('');
+ $iCacheSec = (int)utils::ReadParam('cache', 0);
+ $oPage->set_cache($iCacheSec);
+
+ // N°4129 - Prevent XSS attacks & other script executions
+ if (utils::GetConfig()->Get('security.disable_inline_documents_sandbox') === false) {
+ $oPage->add_header('Content-Security-Policy: sandbox;');
+ }
+
+ ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline');
+ }
+ break;
+
+ case 'search_form':
+ $oPage->SetContentType('text/html');
+ $sClass = utils::ReadParam('className', '', false, 'class');
+ $sRootClass = utils::ReadParam('baseClass', '', false, 'class');
+ $currentId = utils::ReadParam('currentId', '');
+ $sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data');
+ $sAction = utils::ReadParam('action', '');
+ $sSelectionMode = utils::ReadParam('selection_mode', null, false, 'raw_data');
+ $sResultListOuterSelector = utils::ReadParam('result_list_outer_selector', null, false, 'raw_data');
+ $scssCount = utils::ReadParam('css_count', null, false, 'raw_data');
+ $sTableInnerId = utils::ReadParam('table_inner_id', $sTableId, false, 'raw_data');
+
+ $oFilter = new DBObjectSearch($sClass);
+ $oSet = new CMDBObjectSet($oFilter);
+ $sHtml = cmdbAbstractObject::GetSearchForm($oPage, $oSet, array(
+ 'currentId' => $currentId,
+ 'baseClass' => $sRootClass,
+ 'action' => $sAction,
+ 'table_id' => $sTableId,
+ 'selection_mode' => $sSelectionMode,
+ 'result_list_outer_selector' => $sResultListOuterSelector,
+ 'cssCount' => $scssCount,
+ 'table_inner_id' => $sTableInnerId
+ ));
+ $oPage->add($sHtml);
+ break;
+
+ case 'set_pref':
+ $sCode = utils::ReadPostedParam('code', '', 'raw_data');
+ $sValue = utils::ReadPostedParam('value', '', 'raw_data');
+ appUserPreferences::SetPref($sCode, $sValue);
+ break;
+
+ case 'erase_all_pref':
+ // Can be useful in case a user got some corrupted prefs...
+ appUserPreferences::ClearPreferences();
+ break;
+
+ case 'on_form_cancel':
+ // Called when a creation/modification form is cancelled by the end-user
+ // Let's take this opportunity to inform the plug-ins so that they can perform some cleanup
+ $iTransactionId = utils::ReadParam('transaction_id', 0, false, 'transaction_id');
+ $sTempId = utils::GetUploadTempId($iTransactionId);
+ InlineImage::OnFormCancel($sTempId);
+ /** @var \iApplicationUIExtension $oExtensionInstance */
+ foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
+ $oExtensionInstance->OnFormCancel($sTempId);
+ }
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
+ $sToken = utils::ReadParam('token', 0, false, 'raw_data');
+ if (($sObjClass != '') && ($iObjKey != 0) && ($sToken != '')) {
+ $bReleaseLock = iTopOwnershipLock::ReleaseLock($sObjClass, $iObjKey, $sToken);
+ }
+
+ IssueLog::Trace('on_form_cancel', $sObjClass, array(
+ '$iObjKey' => $iObjKey,
+ '$sTransactionId' => $iTransactionId,
+ '$sTempId' => $sTempId,
+ '$sToken' => $sToken,
+ '$sUser' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+
+ break;
+
+ case 'dashboard':
+ $oPage->SetContentType('text/html');
+ $id = (int)utils::ReadParam('id', 0);
+ $sAttCode = utils::ReadParam('attcode', '');
+ /** @var \cmdbAbstractObject $oObj */
+ $oObj = MetaModel::GetObject($sClass, $id);
+ // - Add graphs dependencies
+ WebResourcesHelper::EnableC3JSToWebPage($oPage);
+ $oObj->DisplayDashboard($oPage, $sAttCode);
+ break;
+
+ case 'export_dashboard':
$oPage = new DownloadPage('');
- // X-Frame http header : set in page constructor, but we need to allow frame integration for this specific page
- // so we're resetting its value ! (see N°3416)
- $oPage->add_xframe_options('');
- $iCacheSec = (int)utils::ReadParam('cache', 0);
- $oPage->set_cache($iCacheSec);
-
- // N°4129 - Prevent XSS attacks & other script executions
- if (utils::GetConfig()->Get('security.disable_inline_documents_sandbox') === false) {
- $oPage->add_header('Content-Security-Policy: sandbox;');
+ $sDashboardId = utils::ReadParam('id', '', false, 'raw_data');
+ $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
+ $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
+ if (!is_null($oDashboard)) {
+ $oPage->TrashUnexpectedOutput();
+ $oPage->SetContentType('text/xml');
+ $oPage->SetContentDisposition('attachment', 'dashboard_'.$oDashboard->GetTitle().'.xml');
+ $oPage->add($oDashboard->ToXml());
}
+ break;
- ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline');
- }
- break;
+ case 'import_dashboard':
+ $oPage = new JsonPage();
+ $oPage->SetOutputDataOnly(true);
- case 'search_form':
- $oPage->SetContentType('text/html');
- $sClass = utils::ReadParam('className', '', false, 'class');
- $sRootClass = utils::ReadParam('baseClass', '', false, 'class');
- $currentId = utils::ReadParam('currentId', '');
- $sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data');
- $sAction = utils::ReadParam('action', '');
- $sSelectionMode = utils::ReadParam('selection_mode', null,false,'raw_data');
- $sResultListOuterSelector = utils::ReadParam('result_list_outer_selector', null,false,'raw_data');
- $scssCount = utils::ReadParam('css_count', null,false,'raw_data');
- $sTableInnerId = utils::ReadParam('table_inner_id', $sTableId,false,'raw_data');
-
- $oFilter = new DBObjectSearch($sClass);
- $oSet = new CMDBObjectSet($oFilter);
- $sHtml = cmdbAbstractObject::GetSearchForm($oPage, $oSet, array('currentId' => $currentId,
- 'baseClass' => $sRootClass,
- 'action' => $sAction,
- 'table_id' => $sTableId,
- 'selection_mode' => $sSelectionMode,
- 'result_list_outer_selector' => $sResultListOuterSelector,
- 'cssCount' => $scssCount,
- 'table_inner_id' => $sTableInnerId));
- $oPage->add($sHtml);
- break;
-
- case 'set_pref':
- $sCode = utils::ReadPostedParam('code', '', 'raw_data');
- $sValue = utils::ReadPostedParam('value', '', 'raw_data');
- appUserPreferences::SetPref($sCode, $sValue);
- break;
-
- case 'erase_all_pref':
- // Can be useful in case a user got some corrupted prefs...
- appUserPreferences::ClearPreferences();
- break;
-
- case 'on_form_cancel':
- // Called when a creation/modification form is cancelled by the end-user
- // Let's take this opportunity to inform the plug-ins so that they can perform some cleanup
- $iTransactionId = utils::ReadParam('transaction_id', 0, false, 'transaction_id');
- $sTempId = utils::GetUploadTempId($iTransactionId);
- InlineImage::OnFormCancel($sTempId);
- /** @var \iApplicationUIExtension $oExtensionInstance */
- foreach(MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
- {
- $oExtensionInstance->OnFormCancel($sTempId);
- }
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
- $sToken = utils::ReadParam('token', 0, false, 'raw_data');
- if (($sObjClass != '') && ($iObjKey != 0) && ($sToken != ''))
- {
- $bReleaseLock = iTopOwnershipLock::ReleaseLock($sObjClass, $iObjKey, $sToken);
- }
-
- IssueLog::Trace('on_form_cancel', $sObjClass, array(
- '$iObjKey' => $iObjKey,
- '$sTransactionId' => $iTransactionId,
- '$sTempId' => $sTempId,
- '$sToken' => $sToken,
- '$sUser' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
-
- break;
-
- case 'dashboard':
- $oPage->SetContentType('text/html');
- $id = (int)utils::ReadParam('id', 0);
- $sAttCode = utils::ReadParam('attcode', '');
- /** @var \cmdbAbstractObject $oObj */
- $oObj = MetaModel::GetObject($sClass, $id);
- // - Add graphs dependencies
- WebResourcesHelper::EnableC3JSToWebPage($oPage);
- $oObj->DisplayDashboard($oPage, $sAttCode);
- break;
-
- case 'export_dashboard':
- $oPage = new DownloadPage('');
- $sDashboardId = utils::ReadParam('id', '', false, 'raw_data');
- $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
- $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
- if (!is_null($oDashboard)) {
- $oPage->TrashUnexpectedOutput();
- $oPage->SetContentType('text/xml');
- $oPage->SetContentDisposition('attachment', 'dashboard_'.$oDashboard->GetTitle().'.xml');
- $oPage->add($oDashboard->ToXml());
- }
- break;
-
- case 'import_dashboard':
- $oPage = new JsonPage();
- $oPage->SetOutputDataOnly(true);
-
- $sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
- if (!utils::IsTransactionValid($sTransactionId, true))
- {
- throw new SecurityException('ajax.render.php import_dashboard : invalid transaction_id');
- }
- $sDashboardId = utils::ReadParam('id', '', false, 'raw_data');
- $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
- $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
- $aResult = array('error' => '');
- if (!is_null($oDashboard))
- {
- try
- {
- $oDoc = utils::ReadPostedDocument('dashboard_upload_file');
- $oDashboard->FromXml($oDoc->GetData());
- $oDashboard->Save();
- } catch (DOMException $e)
- {
- $aResult = array('error' => Dict::S('UI:Error:InvalidDashboardFile'));
- } catch (Exception $e)
- {
- $aResult = array('error' => $e->getMessage());
+ $sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
+ if (!utils::IsTransactionValid($sTransactionId, true)) {
+ throw new SecurityException('ajax.render.php import_dashboard : invalid transaction_id');
}
- }
- else
- {
- $aResult['error'] = 'Dashboard id="'.$sDashboardId.'" not found.';
- }
- $oPage->SetData($aResult);
- break;
-
- case 'toggle_dashboard':
- $oPage->SetContentType('text/html');
- $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
-
- $bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sDashboardId, false);
- appUserPreferences::UnsetPref('display_original_dashboard_'.$sDashboardId);
- appUserPreferences::SetPref('display_original_dashboard_'.$sDashboardId, !$bStandardSelected);
-
- $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
- $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
- $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
- $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
- $aResult = array('error' => '');
- if (!is_null($oDashboard))
- {
- if (!empty($sReloadURL))
- {
- $oDashboard->SetReloadURL($sReloadURL);
+ $sDashboardId = utils::ReadParam('id', '', false, 'raw_data');
+ $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
+ $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
+ $aResult = array('error' => '');
+ if (!is_null($oDashboard)) {
+ try {
+ $oDoc = utils::ReadPostedDocument('dashboard_upload_file');
+ $oDashboard->FromXml($oDoc->GetData());
+ $oDashboard->Save();
+ }
+ catch (DOMException $e) {
+ $aResult = array('error' => Dict::S('UI:Error:InvalidDashboardFile'));
+ }
+ catch (Exception $e) {
+ $aResult = array('error' => $e->getMessage());
+ }
+ } else {
+ $aResult['error'] = 'Dashboard id="'.$sDashboardId.'" not found.';
}
- $oDashboard->Render($oPage, false, $aExtraParams);
- }
- break;
+ $oPage->SetData($aResult);
+ break;
- case 'reload_dashboard':
- $oPage->SetContentType('text/html');
- $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
- $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
- $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
- $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
- $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
- $aResult = array('error' => '');
- if (!is_null($oDashboard))
- {
- if (!empty($sReloadURL))
- {
- $oDashboard->SetReloadURL($sReloadURL);
+ case 'toggle_dashboard':
+ $oPage->SetContentType('text/html');
+ $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
+
+ $bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sDashboardId, false);
+ appUserPreferences::UnsetPref('display_original_dashboard_'.$sDashboardId);
+ appUserPreferences::SetPref('display_original_dashboard_'.$sDashboardId, !$bStandardSelected);
+
+ $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
+ $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
+ $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
+ $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
+ $aResult = array('error' => '');
+ if (!is_null($oDashboard)) {
+ if (!empty($sReloadURL)) {
+ $oDashboard->SetReloadURL($sReloadURL);
+ }
+ $oDashboard->Render($oPage, false, $aExtraParams);
}
- $oDashboard->Render($oPage, false, $aExtraParams);
- }
- break;
+ break;
- case 'save_dashboard':
- $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'context_param');
+ case 'reload_dashboard':
+ $oPage->SetContentType('text/html');
+ $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
+ $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
+ $sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
+ $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
+ $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
+ $aResult = array('error' => '');
+ if (!is_null($oDashboard)) {
+ if (!empty($sReloadURL)) {
+ $oDashboard->SetReloadURL($sReloadURL);
+ }
+ $oDashboard->Render($oPage, false, $aExtraParams);
+ }
+ break;
- $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
- $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
- appUserPreferences::SetPref('display_original_dashboard_'.$sDashboardId, false);
- $sJSExtraParams = json_encode($aExtraParams);
- $aParams = array();
- $aParams['layout_class'] = utils::ReadParam('layout_class', '');
- $aParams['title'] = utils::ReadParam('title', '', false, 'raw_data');
- $aParams['auto_reload'] = utils::ReadParam('auto_reload', false);
- $aParams['auto_reload_sec'] = utils::ReadParam('auto_reload_sec', 300);
- $aParams['cells'] = utils::ReadParam('cells', array(), false, 'raw_data');
+ case 'save_dashboard':
+ $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'context_param');
- $oDashboard = new RuntimeDashboard($sDashboardId);
- $oDashboard->FromParams($aParams);
- $bIsNew = $oDashboard->Save();
+ $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
+ $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
+ appUserPreferences::SetPref('display_original_dashboard_'.$sDashboardId, false);
+ $sJSExtraParams = json_encode($aExtraParams);
+ $aParams = array();
+ $aParams['layout_class'] = utils::ReadParam('layout_class', '');
+ $aParams['title'] = utils::ReadParam('title', '', false, 'raw_data');
+ $aParams['auto_reload'] = utils::ReadParam('auto_reload', false);
+ $aParams['auto_reload_sec'] = utils::ReadParam('auto_reload_sec', 300);
+ $aParams['cells'] = utils::ReadParam('cells', array(), false, 'raw_data');
- $sDashboardFile = addslashes(utils::ReadParam('file', '', false, 'string'));
- $sDashboardDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sDashboardId);
- $sOperation = 'reload_dashboard';
- if ($bIsNew) {
- // Trigger a reload of the current page since the dashboard just changed
- $oPage->add_script(
- <<FromParams($aParams);
+ $bIsNew = $oDashboard->Save();
+
+ $sDashboardFile = addslashes(utils::ReadParam('file', '', false, 'string'));
+ $sDashboardDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sDashboardId);
+ $sOperation = 'reload_dashboard';
+ if ($bIsNew) {
+ // Trigger a reload of the current page since the dashboard just changed
+ $oPage->add_script(
+ <<add_script(
- <<add_script(
+ <<Revert();
- $sFile = addslashes($oDashboard->GetDefinitionFile());
- $sDivId = utils::Sanitize($sDashboardId, '', 'element_identifier');
- // trigger a reload of the current page since the dashboard just changed
- $oPage->add_script(
-<<Revert();
+ $sFile = addslashes($oDashboard->GetDefinitionFile());
+ $sDivId = utils::Sanitize($sDashboardId, '', 'element_identifier');
+ // trigger a reload of the current page since the dashboard just changed
+ $oPage->add_script(
+ <<FromParams($aParams);
- $oDashboard->SetReloadURL($sReloadURL);
- $oDashboard->Render($oPage, true /* bEditMode */, $aExtraParams);
- break;
+ case 'render_dashboard':
+ $sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
+ $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
+ $aParams = array();
+ $aParams['layout_class'] = utils::ReadParam('layout_class', '');
+ $aParams['title'] = utils::ReadParam('title', '', false, 'raw_data');
+ $aParams['cells'] = utils::ReadParam('cells', array(), false, 'raw_data');
+ $aParams['auto_reload'] = utils::ReadParam('auto_reload', false);
+ $aParams['auto_reload_sec'] = utils::ReadParam('auto_reload_sec', 300);
+ $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
+ $oDashboard = new RuntimeDashboard($sDashboardId);
+ $oDashboard->FromParams($aParams);
+ $oDashboard->SetReloadURL($sReloadURL);
+ $oDashboard->Render($oPage, true /* bEditMode */, $aExtraParams);
+ break;
- case 'dashboard_editor':
- $sId = utils::ReadParam('id', '', false, 'context_param');
- $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
- $aExtraParams['dashboard_div_id'] = utils::Sanitize($sId, '', 'element_identifier');
- $sDashboardFile = utils::ReadParam('file', '', false, 'string');
- $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
- $oDashboard = RuntimeDashboard::GetDashboardToEdit($sDashboardFile, $sId);
- if (!is_null($oDashboard)) {
- if (!empty($sReloadURL)) {
- $oDashboard->SetReloadURL($sReloadURL);
+ case 'dashboard_editor':
+ $sId = utils::ReadParam('id', '', false, 'context_param');
+ $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
+ $aExtraParams['dashboard_div_id'] = utils::Sanitize($sId, '', 'element_identifier');
+ $sDashboardFile = utils::ReadParam('file', '', false, 'string');
+ $sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
+ $oDashboard = RuntimeDashboard::GetDashboardToEdit($sDashboardFile, $sId);
+ if (!is_null($oDashboard)) {
+ if (!empty($sReloadURL)) {
+ $oDashboard->SetReloadURL($sReloadURL);
+ }
+ $oDashboard->RenderEditor($oPage, $aExtraParams);
}
- $oDashboard->RenderEditor($oPage, $aExtraParams);
- }
- break;
+ break;
- case 'new_dashlet_id':
- $sDashboardDivId = utils::ReadParam("dashboardid");
- $bIsCustomized = true; // Only called at runtime when customizing a dashboard
- $iRow = utils::ReadParam("iRow");
- $iCol = utils::ReadParam("iCol");
- $sDashletIdOrig = utils::ReadParam("dashletid");
- $sFinalDashletId = Dashboard::GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletIdOrig);
- $oPage = new AjaxPage('');
- $oPage->SetOutputDataOnly(true);
- $oPage->add($sFinalDashletId);
- break;
+ case 'new_dashlet_id':
+ $sDashboardDivId = utils::ReadParam("dashboardid");
+ $bIsCustomized = true; // Only called at runtime when customizing a dashboard
+ $iRow = utils::ReadParam("iRow");
+ $iCol = utils::ReadParam("iCol");
+ $sDashletIdOrig = utils::ReadParam("dashletid");
+ $sFinalDashletId = Dashboard::GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletIdOrig);
+ $oPage = new AjaxPage('');
+ $oPage->SetOutputDataOnly(true);
+ $oPage->add($sFinalDashletId);
+ break;
- case 'new_dashlet':
- require_once(APPROOT.'application/forms.class.inc.php');
- require_once(APPROOT.'application/dashlet.class.inc.php');
- $sDashletClass = utils::ReadParam('dashlet_class', '');
- $sDashletId = utils::ReadParam('dashlet_id', '', false, 'raw_data');
- if (is_subclass_of($sDashletClass, 'Dashlet'))
- {
- $oDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sDashletId);
- $offset = $oPage->start_capture();
- $oDashlet->DoRender($oPage, true /* bEditMode */, false /* bEnclosingDiv */);
- $sHtml = addslashes($oPage->end_capture($offset));
- $sHtml = str_replace("\n", '', $sHtml);
- $sHtml = str_replace("\r", '', $sHtml);
- $oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml');"); // in ajax web page add_script has the same effect as add_ready_script
- // but is executed BEFORE all 'ready_scripts'
- $oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
- $oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
- $sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, '.itop-dashboard'));
- $sHtml = str_replace("\n", '', $sHtml);
- $sHtml = str_replace("\r", '', $sHtml);
- $oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')"); // in ajax web page add_script has the same effect as add_ready_script // but is executed BEFORE all 'ready_scripts'
- }
- break;
+ case 'new_dashlet':
+ require_once(APPROOT.'application/forms.class.inc.php');
+ require_once(APPROOT.'application/dashlet.class.inc.php');
+ $sDashletClass = utils::ReadParam('dashlet_class', '');
+ $sDashletId = utils::ReadParam('dashlet_id', '', false, 'raw_data');
+ if (is_subclass_of($sDashletClass, 'Dashlet')) {
+ $oDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sDashletId);
+ $offset = $oPage->start_capture();
+ $oDashlet->DoRender($oPage, true /* bEditMode */, false /* bEnclosingDiv */);
+ $sHtml = addslashes($oPage->end_capture($offset));
+ $sHtml = str_replace("\n", '', $sHtml);
+ $sHtml = str_replace("\r", '', $sHtml);
+ $oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml');"); // in ajax web page add_script has the same effect as add_ready_script
+ // but is executed BEFORE all 'ready_scripts'
+ $oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
+ $oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
+ $sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, '.itop-dashboard'));
+ $sHtml = str_replace("\n", '', $sHtml);
+ $sHtml = str_replace("\r", '', $sHtml);
+ $oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')"); // in ajax web page add_script has the same effect as add_ready_script // but is executed BEFORE all 'ready_scripts'
+ }
+ break;
- case 'update_dashlet_property':
- require_once(APPROOT.'application/forms.class.inc.php');
- require_once(APPROOT.'application/dashlet.class.inc.php');
- $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
- $aParams = utils::ReadParam('params', '', false, 'raw_data');
- $sDashletClass = $aParams['attr_dashlet_class'];
- $sDashletType = $aParams['attr_dashlet_type'];
- $sDashletId = $aParams['attr_dashlet_id'];
- $aUpdatedProperties = $aParams['updated']; // Code of the changed properties as an array: 'attr_xxx', 'attr_xxy', etc...
- $aPreviousValues = $aParams['previous_values']; // hash array: 'attr_xxx' => 'old_value'
- if (is_subclass_of($sDashletClass, 'Dashlet')) {
- /** @var \Dashlet $oDashlet */
- $oDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sDashletId);
- $oDashlet->SetDashletType($sDashletType);
- $oForm = $oDashlet->GetForm();
- $aValues = $oForm->ReadParams(); // hash array: 'xxx' => 'new_value'
+ case 'update_dashlet_property':
+ require_once(APPROOT.'application/forms.class.inc.php');
+ require_once(APPROOT.'application/dashlet.class.inc.php');
+ $aExtraParams = utils::ReadParam('extra_params', array(), false, 'raw_data');
+ $aParams = utils::ReadParam('params', '', false, 'raw_data');
+ $sDashletClass = $aParams['attr_dashlet_class'];
+ $sDashletType = $aParams['attr_dashlet_type'];
+ $sDashletId = $aParams['attr_dashlet_id'];
+ $aUpdatedProperties = $aParams['updated']; // Code of the changed properties as an array: 'attr_xxx', 'attr_xxy', etc...
+ $aPreviousValues = $aParams['previous_values']; // hash array: 'attr_xxx' => 'old_value'
+ if (is_subclass_of($sDashletClass, 'Dashlet')) {
+ /** @var \Dashlet $oDashlet */
+ $oDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sDashletId);
+ $oDashlet->SetDashletType($sDashletType);
+ $oForm = $oDashlet->GetForm();
+ $aValues = $oForm->ReadParams(); // hash array: 'xxx' => 'new_value'
- $aCurrentValues = $aValues;
- $aUpdatedDecoded = array();
- foreach ($aUpdatedProperties as $sProp) {
- $sDecodedProp = str_replace('attr_', '', $sProp); // Remove the attr_ prefix
- // Set the previous value
- if ( isset($aPreviousValues[$sProp]) && $aPreviousValues[$sProp] != '' ){
- $aCurrentValues[$sDecodedProp] = $aPreviousValues[$sProp];
- } else {
- if(gettype($aCurrentValues[$sDecodedProp]) == "array") {
- $aCurrentValues[$sDecodedProp] = [];
+ $aCurrentValues = $aValues;
+ $aUpdatedDecoded = array();
+ foreach ($aUpdatedProperties as $sProp) {
+ $sDecodedProp = str_replace('attr_', '', $sProp); // Remove the attr_ prefix
+ // Set the previous value
+ if (isset($aPreviousValues[$sProp]) && $aPreviousValues[$sProp] != '') {
+ $aCurrentValues[$sDecodedProp] = $aPreviousValues[$sProp];
} else {
- $aCurrentValues[$sDecodedProp] = '';
+ if (gettype($aCurrentValues[$sDecodedProp]) == "array") {
+ $aCurrentValues[$sDecodedProp] = [];
+ } else {
+ $aCurrentValues[$sDecodedProp] = '';
+ }
+ }
+ $aUpdatedDecoded[] = $sDecodedProp;
+ }
+
+ $oDashlet->FromParams($aCurrentValues);
+ $sPrevClass = get_class($oDashlet);
+ $oDashlet = $oDashlet->Update($aValues, $aUpdatedDecoded);
+ $sNewClass = get_class($oDashlet);
+ if ($sNewClass != $sPrevClass) {
+ $oPage->add_ready_script("$('#dashlet_$sDashletId').dashlet('option', {dashlet_class: '$sNewClass'});");
+ }
+ if ($oDashlet->IsRedrawNeeded()) {
+ $oBlock = $oDashlet->DoRender($oPage, true, false, $aExtraParams);
+ $sHtml = ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
+ $sHtml = str_replace("\n", '', $sHtml);
+ $sHtml = str_replace("\r", '', $sHtml);
+ $sHtml = str_replace("'", "\'", $sHtml);
+ $oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml');");
+ }
+ if ($oDashlet->IsFormRedrawNeeded()) {
+ $oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
+ $oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
+ $sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true, '.itop-dashboard'));
+ $sHtml = str_replace("\n", '', $sHtml);
+ $sHtml = str_replace("\r", '', $sHtml);
+ $oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')");
+ }
+ }
+ break;
+
+ case 'dashlet_creation_dlg':
+ $sOQL = utils::ReadParam('oql', '', false, 'raw_data');
+ RuntimeDashboard::GetDashletCreationDlgFromOQL($oPage, $sOQL);
+ break;
+
+ case 'add_dashlet':
+ $oForm = RuntimeDashboard::GetDashletCreationForm();
+ $aValues = $oForm->ReadParams();
+
+ $sDashletClass = $aValues['dashlet_class'];
+ $sMenuId = $aValues['menu_id'];
+
+ if (is_subclass_of($sDashletClass, 'Dashlet')) {
+ $oDashlet = new $sDashletClass(new ModelReflectionRuntime(), 0);
+ $oDashlet->FromParams($aValues);
+
+ ApplicationMenu::LoadAdditionalMenus();
+ $index = ApplicationMenu::GetMenuIndexById($sMenuId);
+ $oMenu = ApplicationMenu::GetMenuNode($index);
+ $oMenu->AddDashlet($oDashlet);
+ // navigate to the dashboard page
+ if ($aValues['open_editor']) {
+ $oPage->add_ready_script("window.location.href='".addslashes(utils::GetAbsoluteUrlAppRoot().'pages/UI.php?c[menu]='.urlencode($sMenuId))."&edit=1';"); // reloads the page, doing a GET even if we arrived via a POST
+ }
+ }
+ break;
+
+ case 'shortcut_list_dlg':
+ $sOQL = utils::ReadParam('oql', '', false, 'raw_data');
+ $sTableSettings = utils::ReadParam('table_settings', '', false, 'raw_data');
+ ShortcutOQL::GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings);
+ break;
+
+ case 'shortcut_list_create':
+ $oForm = ShortcutOQL::GetCreationForm();
+ $aValues = $oForm->ReadParams();
+
+ $oAppContext = new ApplicationContext();
+ $aContext = $oAppContext->GetAsHash();
+ $sContext = serialize($aContext);
+
+ // Create shortcut
+ /** @var ShortcutOQL $oShortcut */
+ $oShortcut = MetaModel::NewObject("ShortcutOQL");
+ $oShortcut->Set('user_id', UserRights::GetUserId());
+ $oShortcut->Set("context", $sContext);
+ $oShortcut->Set("name", $aValues['name']);
+ $oShortcut->Set("oql", $aValues['oql']);
+ $iAutoReload = (int)$aValues['auto_reload_sec'];
+ if (($aValues['auto_reload']) && ($iAutoReload > 0)) {
+ $oShortcut->Set("auto_reload_sec", max(MetaModel::GetConfig()->Get('min_reload_interval'), $iAutoReload));
+ $oShortcut->Set("auto_reload", 'custom');
+ }
+ utils::PushArchiveMode(false);
+ $iId = $oShortcut->DBInsertNoReload();
+ utils::PopArchiveMode();
+
+ $oShortcut->CloneTableSettings($aValues['table_settings']);
+
+ // Add shortcut to current menu
+ // - Init. app. menu
+ ApplicationMenu::LoadAdditionalMenus();
+
+ // - Find newly created shortcut
+ $aNewShortcutNode = null;
+ $sMenuGroupId = 'MyShortcuts';
+ $sMenuGroupIdx = ApplicationMenu::GetMenuIndexById($sMenuGroupId);
+ if (0 <= $sMenuGroupIdx) {
+ $sNewShortcutId = $sMenuGroupId.'_'.$oShortcut->GetKey();
+ $aShortcutsNodes = ApplicationMenu::GetSubMenuNodes($sMenuGroupIdx);
+ foreach ($aShortcutsNodes as $aShortcutNode) {
+ if ($sNewShortcutId === $aShortcutNode['sId']) {
+ $aNewShortcutNode = $aShortcutNode;
+ break;
}
}
- $aUpdatedDecoded[] = $sDecodedProp;
}
- $oDashlet->FromParams($aCurrentValues);
- $sPrevClass = get_class($oDashlet);
- $oDashlet = $oDashlet->Update($aValues, $aUpdatedDecoded);
- $sNewClass = get_class($oDashlet);
- if ($sNewClass != $sPrevClass) {
- $oPage->add_ready_script("$('#dashlet_$sDashletId').dashlet('option', {dashlet_class: '$sNewClass'});");
- }
- if ($oDashlet->IsRedrawNeeded()) {
- $oBlock = $oDashlet->DoRender($oPage, true, false, $aExtraParams);
- $sHtml = ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
- $sHtml = str_replace("\n", '', $sHtml);
- $sHtml = str_replace("\r", '', $sHtml);
- $sHtml = str_replace("'", "\'", $sHtml);
- $oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml');");
- }
- if ($oDashlet->IsFormRedrawNeeded()) {
- $oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
- $oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
- $sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true, '.itop-dashboard'));
- $sHtml = str_replace("\n", '', $sHtml);
- $sHtml = str_replace("\r", '', $sHtml);
- $oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')");
- }
- }
- break;
+ // - If shortcut found, insert it in the navigation menu
+ if (!empty($aNewShortcutNode)) {
+ $sHtml = TwigHelper::RenderTemplate(
+ TwigHelper::GetTwigEnvironment(TwigHelper::ENUM_TEMPLATES_BASE_PATH_BACKOFFICE),
+ ['aMenuNode' => $aNewShortcutNode],
+ 'base/layouts/navigation-menu/menu-node'
+ );
- case 'dashlet_creation_dlg':
- $sOQL = utils::ReadParam('oql', '', false, 'raw_data');
- RuntimeDashboard::GetDashletCreationDlgFromOQL($oPage, $sOQL);
- break;
-
- case 'add_dashlet':
- $oForm = RuntimeDashboard::GetDashletCreationForm();
- $aValues = $oForm->ReadParams();
-
- $sDashletClass = $aValues['dashlet_class'];
- $sMenuId = $aValues['menu_id'];
-
- if (is_subclass_of($sDashletClass, 'Dashlet'))
- {
- $oDashlet = new $sDashletClass(new ModelReflectionRuntime(), 0);
- $oDashlet->FromParams($aValues);
-
- ApplicationMenu::LoadAdditionalMenus();
- $index = ApplicationMenu::GetMenuIndexById($sMenuId);
- $oMenu = ApplicationMenu::GetMenuNode($index);
- $oMenu->AddDashlet($oDashlet);
- // navigate to the dashboard page
- if ($aValues['open_editor'])
- {
- $oPage->add_ready_script("window.location.href='".addslashes(utils::GetAbsoluteUrlAppRoot().'pages/UI.php?c[menu]='.urlencode($sMenuId))."&edit=1';"); // reloads the page, doing a GET even if we arrived via a POST
- }
- }
- break;
-
- case 'shortcut_list_dlg':
- $sOQL = utils::ReadParam('oql', '', false, 'raw_data');
- $sTableSettings = utils::ReadParam('table_settings', '', false, 'raw_data');
- ShortcutOQL::GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings);
- break;
-
- case 'shortcut_list_create':
- $oForm = ShortcutOQL::GetCreationForm();
- $aValues = $oForm->ReadParams();
-
- $oAppContext = new ApplicationContext();
- $aContext = $oAppContext->GetAsHash();
- $sContext = serialize($aContext);
-
- // Create shortcut
- /** @var ShortcutOQL $oShortcut */
- $oShortcut = MetaModel::NewObject("ShortcutOQL");
- $oShortcut->Set('user_id', UserRights::GetUserId());
- $oShortcut->Set("context", $sContext);
- $oShortcut->Set("name", $aValues['name']);
- $oShortcut->Set("oql", $aValues['oql']);
- $iAutoReload = (int)$aValues['auto_reload_sec'];
- if (($aValues['auto_reload']) && ($iAutoReload > 0)) {
- $oShortcut->Set("auto_reload_sec", max(MetaModel::GetConfig()->Get('min_reload_interval'), $iAutoReload));
- $oShortcut->Set("auto_reload", 'custom');
- }
- utils::PushArchiveMode(false);
- $iId = $oShortcut->DBInsertNoReload();
- utils::PopArchiveMode();
-
- $oShortcut->CloneTableSettings($aValues['table_settings']);
-
- // Add shortcut to current menu
- // - Init. app. menu
- ApplicationMenu::LoadAdditionalMenus();
-
- // - Find newly created shortcut
- $aNewShortcutNode = null;
- $sMenuGroupId = 'MyShortcuts';
- $sMenuGroupIdx = ApplicationMenu::GetMenuIndexById($sMenuGroupId);
- if (0 <= $sMenuGroupIdx) {
- $sNewShortcutId = $sMenuGroupId.'_'.$oShortcut->GetKey();
- $aShortcutsNodes = ApplicationMenu::GetSubMenuNodes($sMenuGroupIdx);
- foreach ($aShortcutsNodes as $aShortcutNode) {
- if ($sNewShortcutId === $aShortcutNode['sId']) {
- $aNewShortcutNode = $aShortcutNode;
- break;
- }
- }
- }
-
- // - If shortcut found, insert it in the navigation menu
- if (!empty($aNewShortcutNode)) {
- $sHtml = TwigHelper::RenderTemplate(
- TwigHelper::GetTwigEnvironment(TwigHelper::ENUM_TEMPLATES_BASE_PATH_BACKOFFICE),
- ['aMenuNode' => $aNewShortcutNode],
- 'base/layouts/navigation-menu/menu-node'
- );
-
- // Important: Mind the back ticks to avoid line breaks to break the JS
- $oPage->add_script(<<add_script(<<StartRenameDialog($oPage);
- break;
-
- case 'shortcut_rename_go':
- $iShortcut = utils::ReadParam('id', 0);
- $oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
-
- $sName = utils::ReadParam('attr_name', '', false, 'raw_data');
- if (strlen($sName) > 0)
- {
- $oShortcut->Set('name', $sName);
- utils::PushArchiveMode(false);
- $oShortcut->DBUpdate();
- utils::PopArchiveMode();
- $oPage->add_ready_script('window.location.reload();');
- }
-
- break;
-
- case 'shortcut_delete_go':
- $oSearch = new DBObjectSearch('Shortcut');
- $oSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
- $aShortcuts = utils::ReadMultipleSelection($oSearch);
- foreach($aShortcuts as $iShortcut)
- {
- $oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
- utils::PushArchiveMode(false);
- $oShortcut->DBDelete();
- utils::PopArchiveMode();
- $oPage->add_ready_script('window.location.reload();');
- }
- break;
-
- case 'about_box':
- AjaxRenderController::DisplayAboutBox($oPage);
- break;
-
- case 'full_text_search':
- $aFullTextNeedles = utils::ReadParam('needles', array(), false, 'raw_data');
- $sFullText = trim(implode(' ', $aFullTextNeedles));
- $sClassName = utils::ReadParam('classname', '');
- $iCount = utils::ReadParam('count', 0);
- $iCurrentPos = utils::ReadParam('position', 0);
- $iTune = utils::ReadParam('tune', 0);
- if (empty($sFullText)) {
- $oPage->p(Dict::S('UI:Search:NoSearch'));
+ );
+ }
break;
- }
- // Search in full text mode in all the classes
- $aMatches = array();
+ case 'shortcut_rename_dlg':
+ $oSearch = new DBObjectSearch('Shortcut');
+ $aShortcuts = utils::ReadMultipleSelection($oSearch);
+ $iShortcut = $aShortcuts[0];
+ $oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
+ $oShortcut->StartRenameDialog($oPage);
+ break;
- // Build the ordered list of classes to search into
- //
- if (empty($sClassName))
- {
- $aSearchClasses = MetaModel::GetClasses('searchable');
- }
- else
- {
- // Search is limited to a given class and its subclasses
- $aSearchClasses = MetaModel::EnumChildClasses($sClassName, ENUM_CHILD_CLASSES_ALL);
- }
- // Skip abstract classes, since we search in all the child classes anyway
- foreach($aSearchClasses as $idx => $sClass)
- {
- if (MetaModel::IsAbstract($sClass))
- {
- unset($aSearchClasses[$idx]);
- }
- }
+ case 'shortcut_rename_go':
+ $iShortcut = utils::ReadParam('id', 0);
+ $oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
- $sMaxChunkDuration = MetaModel::GetConfig()->Get('full_text_chunk_duration');
- $aAccelerators = MetaModel::GetConfig()->Get('full_text_accelerators');
+ $sName = utils::ReadParam('attr_name', '', false, 'raw_data');
+ if (strlen($sName) > 0) {
+ $oShortcut->Set('name', $sName);
+ utils::PushArchiveMode(false);
+ $oShortcut->DBUpdate();
+ utils::PopArchiveMode();
+ $oPage->add_ready_script('window.location.reload();');
+ }
- foreach(array_reverse($aAccelerators) as $sClass => $aRestriction)
- {
- $bSkip = false;
- $iPos = array_search($sClass, $aSearchClasses);
- if ($iPos !== false)
- {
- unset($aSearchClasses[$iPos]);
- }
- else
- {
- $bSkip = true;
- }
- $bSkip |= array_key_exists('skip', $aRestriction) ? $aRestriction['skip'] : false;
- if (!in_array($sClass, $aSearchClasses))
- {
- if ($sClass == $sClassName)
- {
- // Class explicitely requested, do NOT skip it
- // beware: there may not be a 'query' defined for a skipped class !
- $bSkip = false;
- }
- }
- if (!$bSkip)
- {
- // NOT skipped, add the class to the list of classes to search into
- if (array_key_exists('query', $aRestriction))
- {
- array_unshift($aSearchClasses, $aRestriction['query']);
- }
- else
- {
- // No accelerator query
- array_unshift($aSearchClasses, $sClassName);
- }
- }
- }
+ break;
- $aSearchClasses = array_values($aSearchClasses); // renumbers the array starting from zero, removing the missing indexes
- $fStarted = microtime(true);
- $iFoundInThisRound = 0;
- for($iPos = $iCurrentPos; $iPos < count($aSearchClasses); $iPos++)
- {
- if ($iFoundInThisRound && (microtime(true) - $fStarted >= $sMaxChunkDuration))
- {
+ case 'shortcut_delete_go':
+ $oSearch = new DBObjectSearch('Shortcut');
+ $oSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
+ $aShortcuts = utils::ReadMultipleSelection($oSearch);
+ foreach ($aShortcuts as $iShortcut) {
+ $oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
+ utils::PushArchiveMode(false);
+ $oShortcut->DBDelete();
+ utils::PopArchiveMode();
+ $oPage->add_ready_script('window.location.reload();');
+ }
+ break;
+
+ case 'about_box':
+ AjaxRenderController::DisplayAboutBox($oPage);
+ break;
+
+ case 'full_text_search':
+ $aFullTextNeedles = utils::ReadParam('needles', array(), false, 'raw_data');
+ $sFullText = trim(implode(' ', $aFullTextNeedles));
+ $sClassName = utils::ReadParam('classname', '');
+ $iCount = utils::ReadParam('count', 0);
+ $iCurrentPos = utils::ReadParam('position', 0);
+ $iTune = utils::ReadParam('tune', 0);
+ if (empty($sFullText)) {
+ $oPage->p(Dict::S('UI:Search:NoSearch'));
break;
}
- $sClassSpec = $aSearchClasses[$iPos];
- if (substr($sClassSpec, 0, 7) == 'SELECT ')
- {
- $oFilter = DBObjectSearch::FromOQL($sClassSpec);
- $sClassName = $oFilter->GetClass();
- $sNeedleFormat = isset($aAccelerators[$sClassName]['needle']) ? $aAccelerators[$sClassName]['needle'] : '%$needle$%';
- $sNeedle = str_replace('$needle$', $sFullText, $sNeedleFormat);
- $aParams = array('needle' => $sNeedle);
- }
- else
- {
- $sClassName = $sClassSpec;
- $oFilter = new DBObjectSearch($sClassName);
- $aParams = array();
+ // Search in full text mode in all the classes
+ $aMatches = array();
- foreach($aFullTextNeedles as $sSearchText)
- {
- $oFilter->AddCondition_FullText($sSearchText);
+ // Build the ordered list of classes to search into
+ //
+ if (empty($sClassName)) {
+ $aSearchClasses = MetaModel::GetClasses('searchable');
+ } else {
+ // Search is limited to a given class and its subclasses
+ $aSearchClasses = MetaModel::EnumChildClasses($sClassName, ENUM_CHILD_CLASSES_ALL);
+ }
+ // Skip abstract classes, since we search in all the child classes anyway
+ foreach ($aSearchClasses as $idx => $sClass) {
+ if (MetaModel::IsAbstract($sClass)) {
+ unset($aSearchClasses[$idx]);
}
}
- $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
- // Skip abstract classes
- if (MetaModel::IsAbstract($sClassName)) continue;
- if ($iTune > 0)
- {
- $fStartedClass = microtime(true);
- }
- $oSet = new DBObjectSet($oFilter, array(), $aParams);
- if (array_key_exists($sClassName, $aAccelerators) && array_key_exists('attributes', $aAccelerators[$sClassName]))
- {
- $oSet->OptimizeColumnLoad(array($oFilter->GetClassAlias() => $aAccelerators[$sClassName]['attributes']));
+ $sMaxChunkDuration = MetaModel::GetConfig()->Get('full_text_chunk_duration');
+ $aAccelerators = MetaModel::GetConfig()->Get('full_text_accelerators');
+
+ foreach (array_reverse($aAccelerators) as $sClass => $aRestriction) {
+ $bSkip = false;
+ $iPos = array_search($sClass, $aSearchClasses);
+ if ($iPos !== false) {
+ unset($aSearchClasses[$iPos]);
+ } else {
+ $bSkip = true;
+ }
+ $bSkip |= array_key_exists('skip', $aRestriction) ? $aRestriction['skip'] : false;
+ if (!in_array($sClass, $aSearchClasses)) {
+ if ($sClass == $sClassName) {
+ // Class explicitely requested, do NOT skip it
+ // beware: there may not be a 'query' defined for a skipped class !
+ $bSkip = false;
+ }
+ }
+ if (!$bSkip) {
+ // NOT skipped, add the class to the list of classes to search into
+ if (array_key_exists('query', $aRestriction)) {
+ array_unshift($aSearchClasses, $aRestriction['query']);
+ } else {
+ // No accelerator query
+ array_unshift($aSearchClasses, $sClassName);
+ }
+ }
}
- $sFullTextJS = addslashes($sFullText);
- $bEnableEnlarge = array_key_exists($sClassName, $aAccelerators) && array_key_exists('query', $aAccelerators[$sClassName]);
- if (array_key_exists($sClassName, $aAccelerators) && array_key_exists('enable_enlarge', $aAccelerators[$sClassName]))
- {
- $bEnableEnlarge &= $aAccelerators[$sClassName]['enable_enlarge'];
- }
- $sEnlargeTheSearch =
- <<= $sMaxChunkDuration)) {
+ break;
+ }
+
+ $sClassSpec = $aSearchClasses[$iPos];
+ if (substr($sClassSpec, 0, 7) == 'SELECT ') {
+ $oFilter = DBObjectSearch::FromOQL($sClassSpec);
+ $sClassName = $oFilter->GetClass();
+ $sNeedleFormat = isset($aAccelerators[$sClassName]['needle']) ? $aAccelerators[$sClassName]['needle'] : '%$needle$%';
+ $sNeedle = str_replace('$needle$', $sFullText, $sNeedleFormat);
+ $aParams = array('needle' => $sNeedle);
+ } else {
+ $sClassName = $sClassSpec;
+ $oFilter = new DBObjectSearch($sClassName);
+ $aParams = array();
+
+ foreach ($aFullTextNeedles as $sSearchText) {
+ $oFilter->AddCondition_FullText($sSearchText);
+ }
+ }
+ $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
+ // Skip abstract classes
+ if (MetaModel::IsAbstract($sClassName)) {
+ continue;
+ }
+
+ if ($iTune > 0) {
+ $fStartedClass = microtime(true);
+ }
+ $oSet = new DBObjectSet($oFilter, array(), $aParams);
+ if (array_key_exists($sClassName, $aAccelerators) && array_key_exists('attributes', $aAccelerators[$sClassName])) {
+ $oSet->OptimizeColumnLoad(array($oFilter->GetClassAlias() => $aAccelerators[$sClassName]['attributes']));
+ }
+
+ $sFullTextJS = addslashes($sFullText);
+ $bEnableEnlarge = array_key_exists($sClassName, $aAccelerators) && array_key_exists('query', $aAccelerators[$sClassName]);
+ if (array_key_exists($sClassName, $aAccelerators) && array_key_exists('enable_enlarge', $aAccelerators[$sClassName])) {
+ $bEnableEnlarge &= $aAccelerators[$sClassName]['enable_enlarge'];
+ }
+ $sEnlargeTheSearch =
+ <<');
@@ -1436,91 +1362,75 @@ JS
EOF;
- $sEnlargeButton = '';
- if ($bEnableEnlarge)
- {
- $sEnlargeButton = " ".Dict::S('UI:Search:Enlarge')." ";
- }
- if ($oSet->Count() > 0)
- {
- $aLeafs = array();
- while ($oObj = $oSet->Fetch())
- {
- if (get_class($oObj) == $sClassName)
- {
- $aLeafs[] = $oObj->GetKey();
- $iFoundInThisRound++;
+ $sEnlargeButton = '';
+ if ($bEnableEnlarge) {
+ $sEnlargeButton = " ".Dict::S('UI:Search:Enlarge')." ";
+ }
+ if ($oSet->Count() > 0) {
+ $aLeafs = array();
+ while ($oObj = $oSet->Fetch()) {
+ if (get_class($oObj) == $sClassName) {
+ $aLeafs[] = $oObj->GetKey();
+ $iFoundInThisRound++;
+ }
+ }
+ $oLeafsFilter = new DBObjectSearch($sClassName);
+ if (count($aLeafs) > 0) {
+ $iCount += count($aLeafs);
+ $oPage->add("\n");
+ $oPage->add("\n");
+ $oLeafsFilter->AddCondition('id', $aLeafs, 'IN');
+ $oBlock = new DisplayBlock($oLeafsFilter, 'list', false);
+ $sBlockId = 'global_search_'.$sClassName;
+ $oPage->add('
');
+ $oBlock->RenderContent($oPage, array('table_id' => $sBlockId, 'currentId' => $sBlockId));
+ $oPage->add("
\n");
+ $oPage->add("
\n");
+ $oPage->p(' '); // Some space ?
+ }
+ } else {
+ if (array_key_exists($sClassName, $aAccelerators)) {
+ $oPage->add("\n");
+ $oPage->add("\n");
+ $oPage->add("
\n");
+ $oPage->p(' '); // Some space ?
}
}
- $oLeafsFilter = new DBObjectSearch($sClassName);
- if (count($aLeafs) > 0)
- {
- $iCount += count($aLeafs);
- $oPage->add("\n");
- $oPage->add("\n");
- $oLeafsFilter->AddCondition('id', $aLeafs, 'IN');
- $oBlock = new DisplayBlock($oLeafsFilter, 'list', false);
- $sBlockId = 'global_search_'.$sClassName;
- $oPage->add('
');
- $oBlock->RenderContent($oPage, array('table_id' => $sBlockId, 'currentId' => $sBlockId));
- $oPage->add("
\n");
- $oPage->add("
\n");
- $oPage->p(' '); // Some space ?
+ if ($iTune > 0) {
+ $fDurationClass = microtime(true) - $fStartedClass;
+ $oPage->add_script("oTimeStatistics.$sClassName = $fDurationClass;");
}
}
- else
- {
- if (array_key_exists($sClassName, $aAccelerators))
- {
- $oPage->add("\n");
- $oPage->add("\n");
- $oPage->add("
\n");
- $oPage->p(' '); // Some space ?
- }
- }
- if ($iTune > 0)
- {
- $fDurationClass = microtime(true) - $fStartedClass;
- $oPage->add_script("oTimeStatistics.$sClassName = $fDurationClass;");
- }
- }
- if ($iPos < count($aSearchClasses))
- {
- $sJSNeedle = json_encode($aFullTextNeedles);
- $oPage->add_ready_script(
- <<add_ready_script(
+ <<add_ready_script(
- <<add_ready_script(
+ << 0)
- {
- $oPage->add_ready_script(
- << 0) {
+ $oPage->add_ready_script(
+ <<Class Time ';
sRes += '';
@@ -1538,81 +1448,72 @@ EOF
sRes += '';
$('#full_text_results').append(sRes);
EOF
- );
- }
+ );
+ }
- if ($iCount == 0)
- {
- $sFullTextSummary = addslashes(Dict::S('UI:Search:NoObjectFound'));
- $oPage->add_ready_script("$('#full_text_results').append('$sFullTextSummary
');");
- }
- }
- break;
-
- case 'full_text_search_enlarge':
- $sFullText = trim(utils::ReadParam('text', '', false, 'raw_data'));
- $sClass = trim(utils::ReadParam('class', ''));
- $iTune = utils::ReadParam('tune', 0);
-
- if (preg_match('/^"(.*)"$/', $sFullText, $aMatches))
- {
- // The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
- $aFullTextNeedles = array($aMatches[1]);
- }
- else
- {
- // Split the text on the blanks and treat this as a search for AND AND
- $aFullTextNeedles = explode(' ', $sFullText);
- }
-
- $oFilter = new DBObjectSearch($sClass);
- foreach($aFullTextNeedles as $sSearchText)
- {
- $oFilter->AddCondition_FullText($sSearchText);
- }
- $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
- $oSet = new DBObjectSet($oFilter);
- $oPage->add("\n");
- if ($oSet->Count() > 0)
- {
- $aLeafs = array();
- while ($oObj = $oSet->Fetch())
- {
- if (get_class($oObj) == $sClass)
- {
- $aLeafs[] = $oObj->GetKey();
+ if ($iCount == 0) {
+ $sFullTextSummary = addslashes(Dict::S('UI:Search:NoObjectFound'));
+ $oPage->add_ready_script("$('#full_text_results').append('$sFullTextSummary
');");
}
}
- $oLeafsFilter = new DBObjectSearch($sClass);
- if (count($aLeafs) > 0)
- {
- $oLeafsFilter->AddCondition('id', $aLeafs, 'IN');
- $oBlock = new DisplayBlock($oLeafsFilter, 'list', false);
- $sBlockId = 'global_search_'.$sClass;
- $oPage->add('');
- $oBlock->RenderContent($oPage, array('table_id' => $sBlockId, 'currentId' => $sBlockId));
- $oPage->add('
');
- $oPage->P(' '); // Some space ?
- // Hide "no object found"
- $oPage->add_ready_script('$("#no_object_found").hide();');
+ break;
+
+ case 'full_text_search_enlarge':
+ $sFullText = trim(utils::ReadParam('text', '', false, 'raw_data'));
+ $sClass = trim(utils::ReadParam('class', ''));
+ $iTune = utils::ReadParam('tune', 0);
+
+ if (preg_match('/^"(.*)"$/', $sFullText, $aMatches)) {
+ // The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
+ $aFullTextNeedles = array($aMatches[1]);
+ } else {
+ // Split the text on the blanks and treat this as a search for AND AND
+ $aFullTextNeedles = explode(' ', $sFullText);
}
- }
- $oPage->add_ready_script(
- <<AddCondition_FullText($sSearchText);
+ }
+ $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
+ $oSet = new DBObjectSet($oFilter);
+ $oPage->add("\n");
+ if ($oSet->Count() > 0) {
+ $aLeafs = array();
+ while ($oObj = $oSet->Fetch()) {
+ if (get_class($oObj) == $sClass) {
+ $aLeafs[] = $oObj->GetKey();
+ }
+ }
+ $oLeafsFilter = new DBObjectSearch($sClass);
+ if (count($aLeafs) > 0) {
+ $oLeafsFilter->AddCondition('id', $aLeafs, 'IN');
+ $oBlock = new DisplayBlock($oLeafsFilter, 'list', false);
+ $sBlockId = 'global_search_'.$sClass;
+ $oPage->add('');
+ $oBlock->RenderContent($oPage, array('table_id' => $sBlockId, 'currentId' => $sBlockId));
+ $oPage->add('
');
+ $oPage->P(' '); // Some space ?
+ // Hide "no object found"
+ $oPage->add_ready_script('$("#no_object_found").hide();');
+ }
+ }
+ $oPage->add_ready_script(
+ <<SetContentType('text/html');
- $oPage->add(
- <<SetContentType('text/html');
+ $oPage->add(
+ <<
.ui-progressbar {
position: relative;
@@ -1654,568 +1555,599 @@ EOF
}
EOF
- );
- $oPage->add('');
- $oPage->add('
');
- $oPage->add('
'.Dict::S('UI:CSVImport:AdvancedMode').'
');
- $oPage->add('
'.Dict::S('UI:CSVImport:AdvancedMode+').'
');
- $oPage->add('
'.Dict::S('ExcelExport:AutoDownload').'
');
- $oPage->add('
');
- $oPage->add('
'.Dict::S('ExcelExport:PreparingExport').'
');
- $oPage->add('
'.Dict::S('ExcelExport:Statistics').'
');
- $oPage->add('
');
- $aLabels = array(
- 'dialog_title' => Dict::S('ExcelExporter:ExportDialogTitle'),
- 'cancel_button' => Dict::S('UI:Button:Cancel'),
- 'export_button' => Dict::S('ExcelExporter:ExportButton'),
- 'download_button' => Dict::Format('ExcelExporter:DownloadButton', 'export.xlsx'), //TODO: better name for the file (based on the class of the filter??)
- );
- $sJSLabels = json_encode($aLabels);
- $sFilter = addslashes($sFilter);
- $sJSPageUrl = addslashes(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php');
- $oPage->add_ready_script("$('#XlsxExportDlg').xlsxexporter({filter: '$sFilter', labels: $sJSLabels, ajax_page_url: '$sJSPageUrl'});");
- break;
+ );
+ $oPage->add('');
+ $oPage->add('
');
+ $oPage->add('
'.Dict::S('UI:CSVImport:AdvancedMode').'
');
+ $oPage->add('
'.Dict::S('UI:CSVImport:AdvancedMode+').'
');
+ $oPage->add('
'.Dict::S('ExcelExport:AutoDownload').'
');
+ $oPage->add('
');
+ $oPage->add('
'.Dict::S('ExcelExport:PreparingExport').'
');
+ $oPage->add('
'.Dict::S('ExcelExport:Statistics').'
');
+ $oPage->add('
');
+ $aLabels = array(
+ 'dialog_title' => Dict::S('ExcelExporter:ExportDialogTitle'),
+ 'cancel_button' => Dict::S('UI:Button:Cancel'),
+ 'export_button' => Dict::S('ExcelExporter:ExportButton'),
+ 'download_button' => Dict::Format('ExcelExporter:DownloadButton', 'export.xlsx'), //TODO: better name for the file (based on the class of the filter??)
+ );
+ $sJSLabels = json_encode($aLabels);
+ $sFilter = addslashes($sFilter);
+ $sJSPageUrl = addslashes(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php');
+ $oPage->add_ready_script("$('#XlsxExportDlg').xlsxexporter({filter: '$sFilter', labels: $sJSLabels, ajax_page_url: '$sJSPageUrl'});");
+ break;
- case 'xlsx_start':
- DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $bAdvanced = (utils::ReadParam('advanced', 'false') == 'true');
- $oSearch = DBObjectSearch::unserialize($sFilter);
- $oExcelExporter = new ExcelExporter();
- $oExcelExporter->SetObjectList($oSearch);
- //$oExcelExporter->SetChunkSize(10); //Only for testing
- $oExcelExporter->SetAdvancedMode($bAdvanced);
- $sToken = $oExcelExporter->SaveState();
- $oPage->add(json_encode(array('status' => 'ok', 'token' => $sToken)));
- break;
+ case 'xlsx_start':
+ DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ $bAdvanced = (utils::ReadParam('advanced', 'false') == 'true');
+ $oSearch = DBObjectSearch::unserialize($sFilter);
+ $oExcelExporter = new ExcelExporter();
+ $oExcelExporter->SetObjectList($oSearch);
+ //$oExcelExporter->SetChunkSize(10); //Only for testing
+ $oExcelExporter->SetAdvancedMode($bAdvanced);
+ $sToken = $oExcelExporter->SaveState();
+ $oPage->add(json_encode(array('status' => 'ok', 'token' => $sToken)));
+ break;
- case 'xlsx_run':
- DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
- $sMemoryLimit = MetaModel::GetConfig()->Get('xlsx_exporter_memory_limit');
- if (utils::SetMinMemoryLimit($sMemoryLimit) === false) {
- IssueLog::Warning("XSLX export : cannot set memory_limit to {$sMemoryLimit}");
- }
- ini_set('max_execution_time', max(300, ini_get('max_execution_time'))); // At least 5 minutes
-
- $sToken = utils::ReadParam('token', '', false, 'raw_data');
- $oExcelExporter = new ExcelExporter($sToken);
- $aStatus = $oExcelExporter->Run();
- $aResults = array('status' => $aStatus['code'], 'percentage' => $aStatus['percentage'], 'message' => $aStatus['message']);
- if ($aStatus['code'] == 'done') {
- $aResults['statistics'] = $oExcelExporter->GetStatistics('html');
- }
- $oPage->add(json_encode($aResults));
- break;
-
- case 'xlsx_download':
- DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
- $oPage = new DownloadPage('');
- $sToken = utils::ReadParam('token', '', false, 'raw_data');
- $oPage->SetContentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
- $oPage->SetContentDisposition('attachment', 'export.xlsx');
- $sFileContent = ExcelExporter::GetExcelFileFromToken($sToken);
- $oPage->add($sFileContent);
- ExcelExporter::CleanupFromToken($sToken);
- break;
-
- case 'xlsx_abort':
- DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
- // Stop & cleanup an export...
- $sToken = utils::ReadParam('token', '', false, 'raw_data');
- ExcelExporter::CleanupFromToken($sToken);
- break;
-
- case 'relation_pdf':
- case 'relation_attachment':
- require_once(APPROOT.'core/simplegraph.class.inc.php');
- require_once(APPROOT.'core/relationgraph.class.inc.php');
- require_once(APPROOT.'core/displayablegraph.class.inc.php');
- $sRelation = utils::ReadParam('relation', 'impacts');
- $sDirection = utils::ReadParam('direction', 'down');
-
- $iGroupingThreshold = utils::ReadParam('g', 5, false, 'integer');
- $sPageFormat = utils::ReadParam('p', 'A4');
- $sPageOrientation = utils::ReadParam('o', 'L');
- $sTitle = utils::ReadParam('title', '', false, 'raw_data');
- $sPositions = utils::ReadParam('positions', null, false, 'raw_data');
- $aExcludedClasses = utils::ReadParam('excluded_classes', array(), false, 'raw_data');
- $bIncludeList = (bool)utils::ReadParam('include_list', false);
- $sComments = utils::ReadParam('comments', '', false, 'raw_data');
- $aContexts = utils::ReadParam('contexts', array(), false, 'raw_data');
- $sContextKey = utils::ReadParam('context_key', '', false, 'raw_data');
- $aPositions = null;
- if ($sPositions != null) {
- $aPositions = json_decode($sPositions, true);
- }
-
- // Get the list of source objects
- $aSources = utils::ReadParam('sources', array(), false, 'raw_data');
- $aSourceObjects = array();
- foreach ($aSources as $sClass => $aIDs) {
- $oSearch = new DBObjectSearch($sClass);
- $oSearch->AddCondition('id', $aIDs, 'IN');
- $oSet = new DBObjectSet($oSearch);
- while ($oObj = $oSet->Fetch()) {
- $aSourceObjects[] = $oObj;
+ case 'xlsx_run':
+ DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
+ $sMemoryLimit = MetaModel::GetConfig()->Get('xlsx_exporter_memory_limit');
+ if (utils::SetMinMemoryLimit($sMemoryLimit) === false) {
+ IssueLog::Warning("XSLX export : cannot set memory_limit to {$sMemoryLimit}");
}
- }
- $sSourceClass = '*';
- if (count($aSourceObjects) == 1) {
- $sSourceClass = get_class($aSourceObjects[0]);
- }
+ ini_set('max_execution_time', max(300, ini_get('max_execution_time'))); // At least 5 minutes
- // Get the list of excluded objects
- $aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
- $aExcludedObjects = array();
- foreach ($aExcluded as $sClass => $aIDs) {
- $oSearch = new DBObjectSearch($sClass);
- $oSearch->AddCondition('id', $aIDs, 'IN');
- $oSet = new DBObjectSet($oSearch);
- while ($oObj = $oSet->Fetch()) {
- $aExcludedObjects[] = $oObj;
+ $sToken = utils::ReadParam('token', '', false, 'raw_data');
+ $oExcelExporter = new ExcelExporter($sToken);
+ $aStatus = $oExcelExporter->Run();
+ $aResults = array('status' => $aStatus['code'], 'percentage' => $aStatus['percentage'], 'message' => $aStatus['message']);
+ if ($aStatus['code'] == 'done') {
+ $aResults['statistics'] = $oExcelExporter->GetStatistics('html');
}
- }
+ $oPage->add(json_encode($aResults));
+ break;
- $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
- if ($sDirection == 'up') {
- $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aContexts);
- } else {
- $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aExcludedObjects, $aContexts);
- }
+ case 'xlsx_download':
+ DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
+ $oPage = new DownloadPage('');
+ $sToken = utils::ReadParam('token', '', false, 'raw_data');
+ $oPage->SetContentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+ $oPage->SetContentDisposition('attachment', 'export.xlsx');
+ $sFileContent = ExcelExporter::GetExcelFileFromToken($sToken);
+ $oPage->add($sFileContent);
+ ExcelExporter::CleanupFromToken($sToken);
+ break;
- // Remove excluded classes from the graph
- if (count($aExcludedClasses) > 0) {
- $oIterator = new RelationTypeIterator($oRelGraph, 'Node');
- foreach ($oIterator as $oNode) {
- $oObj = $oNode->GetProperty('object');
- if ($oObj && in_array(get_class($oObj), $aExcludedClasses)) {
- $oRelGraph->FilterNode($oNode);
+ case 'xlsx_abort':
+ DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
+ // Stop & cleanup an export...
+ $sToken = utils::ReadParam('token', '', false, 'raw_data');
+ ExcelExporter::CleanupFromToken($sToken);
+ break;
+
+ case 'relation_pdf':
+ case 'relation_attachment':
+ require_once(APPROOT.'core/simplegraph.class.inc.php');
+ require_once(APPROOT.'core/relationgraph.class.inc.php');
+ require_once(APPROOT.'core/displayablegraph.class.inc.php');
+ $sRelation = utils::ReadParam('relation', 'impacts');
+ $sDirection = utils::ReadParam('direction', 'down');
+
+ $iGroupingThreshold = utils::ReadParam('g', 5, false, 'integer');
+ $sPageFormat = utils::ReadParam('p', 'A4');
+ $sPageOrientation = utils::ReadParam('o', 'L');
+ $sTitle = utils::ReadParam('title', '', false, 'raw_data');
+ $sPositions = utils::ReadParam('positions', null, false, 'raw_data');
+ $aExcludedClasses = utils::ReadParam('excluded_classes', array(), false, 'raw_data');
+ $bIncludeList = (bool)utils::ReadParam('include_list', false);
+ $sComments = utils::ReadParam('comments', '', false, 'raw_data');
+ $aContexts = utils::ReadParam('contexts', array(), false, 'raw_data');
+ $sContextKey = utils::ReadParam('context_key', '', false, 'raw_data');
+ $aPositions = null;
+ if ($sPositions != null) {
+ $aPositions = json_decode($sPositions, true);
+ }
+
+ // Get the list of source objects
+ $aSources = utils::ReadParam('sources', array(), false, 'raw_data');
+ $aSourceObjects = array();
+ foreach ($aSources as $sClass => $aIDs) {
+ $oSearch = new DBObjectSearch($sClass);
+ $oSearch->AddCondition('id', $aIDs, 'IN');
+ $oSet = new DBObjectSet($oSearch);
+ while ($oObj = $oSet->Fetch()) {
+ $aSourceObjects[] = $oObj;
}
}
- }
-
- $oPage = new PDFPage($sTitle, $sPageFormat, $sPageOrientation);
- $oPage->SetContentDisposition('attachment', $sTitle.'.pdf');
-
- $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'), true);
- $oGraph->InitFromGraphviz();
- if ($aPositions != null) {
- $oGraph->UpdatePositions($aPositions);
- }
-
- $aGroups = array();
- $oIterator = new RelationTypeIterator($oGraph, 'Node');
- foreach ($oIterator as $oNode) {
- if ($oNode instanceof DisplayableGroupNode) {
- $aGroups[$oNode->GetProperty('group_index')] = $oNode->GetObjects();
+ $sSourceClass = '*';
+ if (count($aSourceObjects) == 1) {
+ $sSourceClass = get_class($aSourceObjects[0]);
}
- }
- // First page is the graph
- $oGraph->RenderAsPDF($oPage, $sComments, $sContextKey);
- if ($bIncludeList) {
- // Then the lists of objects (one table per finalclass)
- $aResults = array();
- $oIterator = new RelationTypeIterator($oRelGraph, 'Node');
- foreach ($oIterator as $oNode) {
- $oObj = $oNode->GetProperty('object'); // Some nodes (Redundancy Nodes and Group) do not contain an object
- if ($oObj) {
- $sObjClass = get_class($oObj);
- if (!array_key_exists($sObjClass, $aResults)) {
- $aResults[$sObjClass] = array();
+ // Get the list of excluded objects
+ $aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
+ $aExcludedObjects = array();
+ foreach ($aExcluded as $sClass => $aIDs) {
+ $oSearch = new DBObjectSearch($sClass);
+ $oSearch->AddCondition('id', $aIDs, 'IN');
+ $oSet = new DBObjectSet($oSearch);
+ while ($oObj = $oSet->Fetch()) {
+ $aExcludedObjects[] = $oObj;
+ }
+ }
+
+ $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
+ if ($sDirection == 'up') {
+ $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aContexts);
+ } else {
+ $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aExcludedObjects, $aContexts);
+ }
+
+ // Remove excluded classes from the graph
+ if (count($aExcludedClasses) > 0) {
+ $oIterator = new RelationTypeIterator($oRelGraph, 'Node');
+ foreach ($oIterator as $oNode) {
+ $oObj = $oNode->GetProperty('object');
+ if ($oObj && in_array(get_class($oObj), $aExcludedClasses)) {
+ $oRelGraph->FilterNode($oNode);
}
- $aResults[$sObjClass][] = $oObj;
}
}
- $oPage->get_tcpdf()->AddPage();
- $oPage->get_tcpdf()->SetFontSize(10); // Reset the font size to its default
- $oPage->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:RelationshipList')));
- $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
- foreach ($aResults as $sListClass => $aObjects) {
- set_time_limit($iLoopTimeLimit * count($aObjects));
- $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects);
- $oSet->SetShowObsoleteData(utils::ShowObsoleteData());
- /* cf N°3928 - Polishing: Impact analysis - remove icons in pdf list
- $sIconUrl = MetaModel::GetClassIcon($sListClass, false);
- $sIconUrl = str_replace(utils::GetAbsoluteUrlModulesRoot(), APPROOT.'env-'.utils::GetCurrentEnvironment().'/', $sIconUrl);
- $oTitle = new Html(" ".Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', $oSet->Count(), Metamodel::GetName($sListClass)));*/
- $oTitle = new Html(Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', $oSet->Count(), Metamodel::GetName($sListClass)));
- $oPage->AddSubBlock(TitleUIBlockFactory::MakeStandard($oTitle, 2));
- $oPage->AddSubBlock(cmdbAbstractObject::GetDataTableFromDBObjectSet($oSet, array('table_id' => $sSourceClass.'_'.$sRelation.'_'.$sDirection.'_'.$sListClass)));
+ $oPage = new PDFPage($sTitle, $sPageFormat, $sPageOrientation);
+ $oPage->SetContentDisposition('attachment', $sTitle.'.pdf');
+
+ $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'), true);
+ $oGraph->InitFromGraphviz();
+ if ($aPositions != null) {
+ $oGraph->UpdatePositions($aPositions);
}
- // Then the content of the groups (one table per group)
- if (count($aGroups) > 0) {
+ $aGroups = array();
+ $oIterator = new RelationTypeIterator($oGraph, 'Node');
+ foreach ($oIterator as $oNode) {
+ if ($oNode instanceof DisplayableGroupNode) {
+ $aGroups[$oNode->GetProperty('group_index')] = $oNode->GetObjects();
+ }
+ }
+ // First page is the graph
+ $oGraph->RenderAsPDF($oPage, $sComments, $sContextKey);
+
+ if ($bIncludeList) {
+ // Then the lists of objects (one table per finalclass)
+ $aResults = array();
+ $oIterator = new RelationTypeIterator($oRelGraph, 'Node');
+ foreach ($oIterator as $oNode) {
+ $oObj = $oNode->GetProperty('object'); // Some nodes (Redundancy Nodes and Group) do not contain an object
+ if ($oObj) {
+ $sObjClass = get_class($oObj);
+ if (!array_key_exists($sObjClass, $aResults)) {
+ $aResults[$sObjClass] = array();
+ }
+ $aResults[$sObjClass][] = $oObj;
+ }
+ }
+
$oPage->get_tcpdf()->AddPage();
- $oPage->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:RelationGroups')));
- foreach ($aGroups as $idx => $aObjects) {
+ $oPage->get_tcpdf()->SetFontSize(10); // Reset the font size to its default
+ $oPage->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:RelationshipList')));
+ $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
+ foreach ($aResults as $sListClass => $aObjects) {
set_time_limit($iLoopTimeLimit * count($aObjects));
- $sListClass = get_class(current($aObjects));
$oSet = CMDBObjectSet::FromArray($sListClass, $aObjects);
- $sIconUrl = MetaModel::GetClassIcon($sListClass, false);
+ $oSet->SetShowObsoleteData(utils::ShowObsoleteData());
+ /* cf N°3928 - Polishing: Impact analysis - remove icons in pdf list
+ $sIconUrl = MetaModel::GetClassIcon($sListClass, false);
$sIconUrl = str_replace(utils::GetAbsoluteUrlModulesRoot(), APPROOT.'env-'.utils::GetCurrentEnvironment().'/', $sIconUrl);
- $oTitle = new Html(" ".Dict::Format('UI:RelationGroupNumber_N', (1 + $idx)), Metamodel::GetName($sListClass));
+ $oTitle = new Html(" ".Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', $oSet->Count(), Metamodel::GetName($sListClass)));*/
+ $oTitle = new Html(Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', $oSet->Count(), Metamodel::GetName($sListClass)));
$oPage->AddSubBlock(TitleUIBlockFactory::MakeStandard($oTitle, 2));
- $oPage->AddSubBlock(cmdbAbstractObject::GetDataTableFromDBObjectSet($oSet));
+ $oPage->AddSubBlock(cmdbAbstractObject::GetDataTableFromDBObjectSet($oSet, array('table_id' => $sSourceClass.'_'.$sRelation.'_'.$sDirection.'_'.$sListClass)));
+ }
+ // Then the content of the groups (one table per group)
+ if (count($aGroups) > 0) {
+ $oPage->get_tcpdf()->AddPage();
+ $oPage->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:RelationGroups')));
+ foreach ($aGroups as $idx => $aObjects) {
+ set_time_limit($iLoopTimeLimit * count($aObjects));
+ $sListClass = get_class(current($aObjects));
+ $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects);
+ $sIconUrl = MetaModel::GetClassIcon($sListClass, false);
+ $sIconUrl = str_replace(utils::GetAbsoluteUrlModulesRoot(), APPROOT.'env-'.utils::GetCurrentEnvironment().'/', $sIconUrl);
+ $oTitle = new Html(" ".Dict::Format('UI:RelationGroupNumber_N', (1 + $idx)), Metamodel::GetName($sListClass));
+ $oPage->AddSubBlock(TitleUIBlockFactory::MakeStandard($oTitle, 2));
+ $oPage->AddSubBlock(cmdbAbstractObject::GetDataTableFromDBObjectSet($oSet));
+
+ }
}
}
- }
- if ($operation == 'relation_attachment') {
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
+ if ($operation == 'relation_attachment') {
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
- // Save the generated PDF as an attachment
- $sPDF = $oPage->get_pdf();
+ // Save the generated PDF as an attachment
+ $sPDF = $oPage->get_pdf();
+ $oPage = new JsonPage();
+ $oPage->SetOutputDataOnly(true);
+ $oAttachment = MetaModel::NewObject('Attachment');
+ $oAttachment->Set('item_class', $sObjClass);
+ $oAttachment->Set('item_id', $iObjKey);
+ $oDoc = new ormDocument($sPDF, 'application/pdf', $sTitle.'.pdf');
+ $oAttachment->Set('contents', $oDoc);
+ $iAttachmentId = $oAttachment->DBInsert();
+ $aRet = array(
+ 'status' => 'ok',
+ 'att_id' => $iAttachmentId,
+ );
+ $oPage->SetData($aRet);
+ }
+ break;
+
+ case 'relation_json':
+ require_once(APPROOT.'core/simplegraph.class.inc.php');
+ require_once(APPROOT.'core/relationgraph.class.inc.php');
+ require_once(APPROOT.'core/displayablegraph.class.inc.php');
+ $sRelation = utils::ReadParam('relation', 'impacts');
+ $sDirection = utils::ReadParam('direction', 'down');
+ $iGroupingThreshold = utils::ReadParam('g', 5);
+ $sPositions = utils::ReadParam('positions', null, false, 'raw_data');
+ $aExcludedClasses = utils::ReadParam('excluded_classes', array(), false, 'raw_data');
+ $aContexts = utils::ReadParam('contexts', array(), false, 'raw_data');
+ $sContextKey = utils::ReadParam('context_key', array(), false, 'raw_data');
+ $aPositions = null;
+ if ($sPositions != null) {
+ $aPositions = json_decode($sPositions, true);
+ }
+
+ // Get the list of source objects
+ $aSources = utils::ReadParam('sources', array(), false, 'raw_data');
+ $aSourceObjects = array();
+ foreach ($aSources as $sClass => $aIDs) {
+ $oSearch = new DBObjectSearch($sClass);
+ $oSearch->AddCondition('id', $aIDs, 'IN');
+ $oSet = new DBObjectSet($oSearch);
+ while ($oObj = $oSet->Fetch()) {
+ $aSourceObjects[] = $oObj;
+ }
+ }
+
+ // Get the list of excluded objects
+ $aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
+ $aExcludedObjects = array();
+ foreach ($aExcluded as $sClass => $aIDs) {
+ $oSearch = new DBObjectSearch($sClass);
+ $oSearch->AddCondition('id', $aIDs, 'IN');
+ $oSet = new DBObjectSet($oSearch);
+ while ($oObj = $oSet->Fetch()) {
+ $aExcludedObjects[] = $oObj;
+ }
+ }
+
+ // Compute the graph
+ $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
+ if ($sDirection == 'up') {
+ $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aContexts);
+ } else {
+ $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aExcludedObjects, $aContexts);
+ }
+
+ // Remove excluded classes from the graph
+ if (count($aExcludedClasses) > 0) {
+ $oIterator = new RelationTypeIterator($oRelGraph, 'Node');
+ foreach ($oIterator as $oNode) {
+ $oObj = $oNode->GetProperty('object');
+ if ($oObj && in_array(get_class($oObj), $aExcludedClasses)) {
+ $oRelGraph->FilterNode($oNode);
+ }
+ }
+ }
+
+ $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
+ $oGraph->InitFromGraphviz();
+ if ($aPositions != null) {
+ $oGraph->UpdatePositions($aPositions);
+ }
+ $oPage->add($oGraph->GetAsJSON($sContextKey));
+ $oPage->SetContentType('application/json');
+ break;
+
+ case 'relation_groups':
+ $aGroups = utils::ReadParam('groups');
+ $iBlock = 1; // Zero is not a valid blockid
+ foreach ($aGroups as $idx => $aDefinition) {
+ $sListClass = $aDefinition['class'];
+ $oSearch = new DBObjectSearch($sListClass);
+ $oSearch->AddCondition('id', $aDefinition['keys'], 'IN');
+ $oSearch->SetShowObsoleteData(utils::ShowObsoleteData());
+ $oPage->AddUiBlock(TitleUIBlockFactory::MakeNeutral(Dict::Format('UI:RelationGroupNumber_N', (1 + $idx)), 1, "relation_group_$idx"));
+ $oBlock = new DisplayBlock($oSearch, 'list');
+ $oBlock->Display($oPage, 'group_'.$iBlock++, array(
+ 'surround_with_panel' => true,
+ 'panel_class' => $sListClass,
+ 'panel_title' => Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aDefinition['keys']), Metamodel::GetName($sListClass)),
+ 'panel_icon' => MetaModel::GetClassIcon($sListClass, false),
+ ));
+ }
+ break;
+
+ case 'relation_lists':
+ $aLists = utils::ReadParam('lists');
+ $iBlock = 1; // Zero is not a valid blockid
+ foreach ($aLists as $sListClass => $aKeys) {
+ $oSearch = new DBObjectSearch($sListClass);
+ $oSearch->AddCondition('id', $aKeys, 'IN');
+ $oSearch->SetShowObsoleteData(utils::ShowObsoleteData());
+ $oBlock = new DisplayBlock($oSearch, 'list');
+ $oBlock->Display($oPage, 'list_'.$iBlock++, array(
+ 'table_id' => 'ImpactAnalysis_'.$sListClass,
+ 'surround_with_panel' => true,
+ 'panel_class' => $sListClass,
+ 'panel_title' => Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aKeys), Metamodel::GetName($sListClass)),
+ 'panel_icon' => MetaModel::GetClassIcon($sListClass, false),
+ ));
+ }
+ break;
+
+ case 'ticket_impact':
+ require_once(APPROOT.'core/simplegraph.class.inc.php');
+ require_once(APPROOT.'core/relationgraph.class.inc.php');
+ require_once(APPROOT.'core/displayablegraph.class.inc.php');
+
+ $sRelation = utils::ReadParam('relation', 'impacts');
+ $sDirection = utils::ReadParam('direction', 'down');
+ $iGroupingThreshold = utils::ReadParam('g', 5);
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sAttCode = utils::ReadParam('attcode', 'functionalcis_list');
+ $sImpactAttCode = utils::ReadParam('impact_attcode', 'impact_code');
+ $sImpactAttCodeValue = utils::ReadParam('impact_attcode_value', 'manual');
+ $iId = (int)utils::ReadParam('id', 0, false, 'integer');
+
+ WebResourcesHelper::EnableSimpleGraphInWebPage($oPage);
+
+ // Get the list of source objects
+ $oTicket = MetaModel::GetObject($sClass, $iId);
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
+ $oExtKeyToRemote = MetaModel::GetAttributeDef($oAttDef->GetLinkedClass(), $sExtKeyToRemote);
+ $sRemoteClass = $oExtKeyToRemote->GetTargetClass();
+ $oSet = $oTicket->Get($sAttCode);
+ $aSourceObjects = array();
+ $aExcludedObjects = array();
+ while ($oLnk = $oSet->Fetch()) {
+ if ($oLnk->Get($sImpactAttCode) == 'manual') {
+ $aSourceObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote));
+ }
+ if ($oLnk->Get($sImpactAttCode) == 'not_impacted') {
+ $aExcludedObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote));
+ }
+ }
+
+ // Compute the graph
+ $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
+ if ($sDirection == 'up') {
+ $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
+ } else {
+ $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, $aExcludedObjects);
+ }
+
+ $aResults = $oRelGraph->GetObjectsByClass();
+ $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
+
+ $sContextKey = 'itop-tickets/relation_context/'.$sClass.'/'.$sRelation.'/'.$sDirection;
+ $oAppContext = new ApplicationContext();
+ $oGraph->Display($oPage, $aResults, $sRelation, $oAppContext, $aExcludedObjects, $sClass, $iId, $sContextKey, array('this' => $oTicket));
+ break;
+
+ case 'export_build':
$oPage = new JsonPage();
$oPage->SetOutputDataOnly(true);
- $oAttachment = MetaModel::NewObject('Attachment');
- $oAttachment->Set('item_class', $sObjClass);
- $oAttachment->Set('item_id', $iObjKey);
- $oDoc = new ormDocument($sPDF, 'application/pdf', $sTitle.'.pdf');
- $oAttachment->Set('contents', $oDoc);
- $iAttachmentId = $oAttachment->DBInsert();
- $aRet = array(
- 'status' => 'ok',
- 'att_id' => $iAttachmentId,
- );
- $oPage->SetData($aRet);
- }
- break;
+ $oAjaxRenderController->ExportBuild($oPage, false);
+ break;
- case 'relation_json':
- require_once(APPROOT.'core/simplegraph.class.inc.php');
- require_once(APPROOT.'core/relationgraph.class.inc.php');
- require_once(APPROOT.'core/displayablegraph.class.inc.php');
- $sRelation = utils::ReadParam('relation', 'impacts');
- $sDirection = utils::ReadParam('direction', 'down');
- $iGroupingThreshold = utils::ReadParam('g', 5);
- $sPositions = utils::ReadParam('positions', null, false, 'raw_data');
- $aExcludedClasses = utils::ReadParam('excluded_classes', array(), false, 'raw_data');
- $aContexts = utils::ReadParam('contexts', array(), false, 'raw_data');
- $sContextKey = utils::ReadParam('context_key', array(), false, 'raw_data');
- $aPositions = null;
- if ($sPositions != null)
- {
- $aPositions = json_decode($sPositions, true);
- }
+ case 'export_build_portal':
+ $oPage = new JsonPage();
+ $oPage->SetOutputDataOnly(true);
+ $oAjaxRenderController->ExportBuild($oPage, true);
+ break;
- // Get the list of source objects
- $aSources = utils::ReadParam('sources', array(), false, 'raw_data');
- $aSourceObjects = array();
- foreach($aSources as $sClass => $aIDs)
- {
- $oSearch = new DBObjectSearch($sClass);
- $oSearch->AddCondition('id', $aIDs, 'IN');
- $oSet = new DBObjectSet($oSearch);
- while ($oObj = $oSet->Fetch())
- {
- $aSourceObjects[] = $oObj;
- }
- }
-
- // Get the list of excluded objects
- $aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
- $aExcludedObjects = array();
- foreach($aExcluded as $sClass => $aIDs)
- {
- $oSearch = new DBObjectSearch($sClass);
- $oSearch->AddCondition('id', $aIDs, 'IN');
- $oSet = new DBObjectSet($oSearch);
- while ($oObj = $oSet->Fetch())
- {
- $aExcludedObjects[] = $oObj;
- }
- }
-
- // Compute the graph
- $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
- if ($sDirection == 'up')
- {
- $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aContexts);
- }
- else
- {
- $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aExcludedObjects, $aContexts);
- }
-
- // Remove excluded classes from the graph
- if (count($aExcludedClasses) > 0)
- {
- $oIterator = new RelationTypeIterator($oRelGraph, 'Node');
- foreach($oIterator as $oNode)
- {
- $oObj = $oNode->GetProperty('object');
- if ($oObj && in_array(get_class($oObj), $aExcludedClasses))
- {
- $oRelGraph->FilterNode($oNode);
+ case 'export_download':
+ $token = utils::ReadParam('token', null);
+ if ($token !== null) {
+ $oExporter = BulkExport::FindExporterFromToken($token);
+ if ($oExporter) {
+ $sMimeType = $oExporter->GetMimeType();
+ if (substr($sMimeType, 0, 5) == 'text/') {
+ $sMimeType .= ';charset='.strtolower($oExporter->GetCharacterSet());
+ }
+ $oPage = new DownloadPage('');
+ $oPage->SetContentType($sMimeType);
+ $oPage->SetContentDisposition('attachment', $oExporter->GetDownloadFileName());
+ $oPage->add(file_get_contents($oExporter->GetTmpFilePath()));
}
}
- }
+ break;
- $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
- $oGraph->InitFromGraphviz();
- if ($aPositions != null)
- {
- $oGraph->UpdatePositions($aPositions);
- }
- $oPage->add($oGraph->GetAsJSON($sContextKey));
- $oPage->SetContentType('application/json');
- break;
-
- case 'relation_groups':
- $aGroups = utils::ReadParam('groups');
- $iBlock = 1; // Zero is not a valid blockid
- foreach($aGroups as $idx => $aDefinition)
- {
- $sListClass = $aDefinition['class'];
- $oSearch = new DBObjectSearch($sListClass);
- $oSearch->AddCondition('id', $aDefinition['keys'], 'IN');
- $oSearch->SetShowObsoleteData(utils::ShowObsoleteData());
- $oPage->AddUiBlock(TitleUIBlockFactory::MakeNeutral(Dict::Format('UI:RelationGroupNumber_N', (1 + $idx)),1,"relation_group_$idx"));
- $oBlock = new DisplayBlock($oSearch, 'list');
- $oBlock->Display($oPage, 'group_'.$iBlock++, array('surround_with_panel' => true,
- 'panel_class' => $sListClass,
- 'panel_title' => Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aDefinition['keys']), Metamodel::GetName($sListClass)),
- 'panel_icon' => MetaModel::GetClassIcon($sListClass, false),
- ));
- }
- break;
-
- case 'relation_lists':
- $aLists = utils::ReadParam('lists');
- $iBlock = 1; // Zero is not a valid blockid
- foreach($aLists as $sListClass => $aKeys)
- {
- $oSearch = new DBObjectSearch($sListClass);
- $oSearch->AddCondition('id', $aKeys, 'IN');
- $oSearch->SetShowObsoleteData(utils::ShowObsoleteData());
- $oBlock = new DisplayBlock($oSearch, 'list');
- $oBlock->Display($oPage, 'list_'.$iBlock++, array('table_id' => 'ImpactAnalysis_'.$sListClass,
- 'surround_with_panel' => true,
- 'panel_class' => $sListClass,
- 'panel_title' => Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aKeys), Metamodel::GetName($sListClass)),
- 'panel_icon' => MetaModel::GetClassIcon($sListClass, false),
- ));
- }
- break;
-
- case 'ticket_impact':
- require_once(APPROOT.'core/simplegraph.class.inc.php');
- require_once(APPROOT.'core/relationgraph.class.inc.php');
- require_once(APPROOT.'core/displayablegraph.class.inc.php');
-
- $sRelation = utils::ReadParam('relation', 'impacts');
- $sDirection = utils::ReadParam('direction', 'down');
- $iGroupingThreshold = utils::ReadParam('g', 5);
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sAttCode = utils::ReadParam('attcode', 'functionalcis_list');
- $sImpactAttCode = utils::ReadParam('impact_attcode', 'impact_code');
- $sImpactAttCodeValue = utils::ReadParam('impact_attcode_value', 'manual');
- $iId = (int)utils::ReadParam('id', 0, false, 'integer');
-
- WebResourcesHelper::EnableSimpleGraphInWebPage($oPage);
-
- // Get the list of source objects
- $oTicket = MetaModel::GetObject($sClass, $iId);
- $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
- $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
- $oExtKeyToRemote = MetaModel::GetAttributeDef($oAttDef->GetLinkedClass(), $sExtKeyToRemote);
- $sRemoteClass = $oExtKeyToRemote->GetTargetClass();
- $oSet = $oTicket->Get($sAttCode);
- $aSourceObjects = array();
- $aExcludedObjects = array();
- while ($oLnk = $oSet->Fetch())
- {
- if ($oLnk->Get($sImpactAttCode) == 'manual')
- {
- $aSourceObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote));
- }
- if ($oLnk->Get($sImpactAttCode) == 'not_impacted')
- {
- $aExcludedObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote));
- }
- }
-
- // Compute the graph
- $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth');
- if ($sDirection == 'up')
- {
- $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
- }
- else
- {
- $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, $aExcludedObjects);
- }
-
- $aResults = $oRelGraph->GetObjectsByClass();
- $oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
-
- $sContextKey = 'itop-tickets/relation_context/'.$sClass.'/'.$sRelation.'/'.$sDirection;
- $oAppContext = new ApplicationContext();
- $oGraph->Display($oPage, $aResults, $sRelation, $oAppContext, $aExcludedObjects, $sClass, $iId, $sContextKey, array('this' => $oTicket));
- break;
-
- case 'export_build':
- $oPage = new JsonPage();
- $oPage->SetOutputDataOnly(true);
- $oAjaxRenderController->ExportBuild($oPage, false);
- break;
-
- case 'export_build_portal':
- $oPage = new JsonPage();
- $oPage->SetOutputDataOnly(true);
- $oAjaxRenderController->ExportBuild($oPage, true);
- break;
-
- case 'export_download':
- $token = utils::ReadParam('token', null);
- if ($token !== null) {
- $oExporter = BulkExport::FindExporterFromToken($token);
- if ($oExporter) {
- $sMimeType = $oExporter->GetMimeType();
- if (substr($sMimeType, 0, 5) == 'text/') {
- $sMimeType .= ';charset='.strtolower($oExporter->GetCharacterSet());
+ case 'export_cancel':
+ $token = utils::ReadParam('token', null);
+ if ($token !== null) {
+ $oExporter = BulkExport::FindExporterFromToken($token);
+ if ($oExporter) {
+ $oExporter->Cleanup();
}
- $oPage = new DownloadPage('');
- $oPage->SetContentType($sMimeType);
- $oPage->SetContentDisposition('attachment', $oExporter->GetDownloadFileName());
- $oPage->add(file_get_contents($oExporter->GetTmpFilePath()));
}
- }
- break;
+ $aResult = array('code' => 'error', 'percentage' => 100, 'message' => Dict::S('Core:BulkExport:ExportCancelledByUser'));
+ $oPage->add(json_encode($aResult));
+ break;
- case 'export_cancel':
- $token = utils::ReadParam('token', null);
- if ($token !== null)
- {
- $oExporter = BulkExport::FindExporterFromToken($token);
- if ($oExporter) {
- $oExporter->Cleanup();
- }
- }
- $aResult = array('code' => 'error', 'percentage' => 100, 'message' => Dict::S('Core:BulkExport:ExportCancelledByUser'));
- $oPage->add(json_encode($aResult));
- break;
-
- case 'check_lock_state':
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
- $aLockData = iTopOwnershipLock::IsLocked($sObjClass, $iObjKey);
-
- $aResult = [
- 'locked' => $aLockData['locked'],
- 'message' => '',
- ];
-
- // If lock taken by someone else, tell by who
- if (true === $aLockData['locked']) {
- // Either the contact friendlyname if the user has a contact, otherwise its login
- $sOwner = ($aLockData['owner']->Get('contactid') > 0) ? $aLockData['owner']->Get('contactid_friendlyname') : $aLockData['owner']->GetRawName();
- $aResult['message'] = Dict::Format('UI:CurrentObjectIsSoftLockedBy_User', $sOwner);
- }
-
- $oPage->SetContentType('application/json');
- $oPage->add(json_encode($aResult));
- break;
-
- // Important: Only from the backoffice AND logged in
- case 'acquire_lock':
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
-
- $aResult = iTopOwnershipLock::AcquireLock($sObjClass, $iObjKey);
- if (false === $aResult['success']) {
+ case 'check_lock_state':
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
$aLockData = iTopOwnershipLock::IsLocked($sObjClass, $iObjKey);
+
+ $aResult = [
+ 'locked' => $aLockData['locked'],
+ 'message' => '',
+ ];
+
// If lock taken by someone else, tell by who
if (true === $aLockData['locked']) {
// Either the contact friendlyname if the user has a contact, otherwise its login
$sOwner = ($aLockData['owner']->Get('contactid') > 0) ? $aLockData['owner']->Get('contactid_friendlyname') : $aLockData['owner']->GetRawName();
$aResult['message'] = Dict::Format('UI:CurrentObjectIsSoftLockedBy_User', $sOwner);
}
- }
- $oPage->SetContentType('application/json');
- $oPage->add(json_encode($aResult));
- break;
+ $oPage->SetContentType('application/json');
+ $oPage->add(json_encode($aResult));
+ break;
- case 'extend_lock':
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
- $sToken = utils::ReadParam('token', 0, false, 'raw_data');
+ // Important: Only from the backoffice AND logged in
+ case 'acquire_lock':
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
- $aResult = iTopOwnershipLock::ExtendLock($sObjClass, $iObjKey, $sToken);
- if (!$aResult['status']) {
- if ($aResult['operation'] == 'lost') {
- $sName = $aResult['owner']->GetName();
- if ($aResult['owner']->Get('contactid') != 0) {
- $sName .= ' ('.$aResult['owner']->Get('contactid_friendlyname').')';
- }
- $aResult['message'] = Dict::Format('UI:CurrentObjectIsLockedBy_User', $sName);
- $aResult['popup_message'] = Dict::Format('UI:CurrentObjectIsLockedBy_User_Explanation', $sName);
- } else {
- if ($aResult['operation'] == 'expired') {
- $aResult['message'] = Dict::S('UI:CurrentObjectLockExpired');
- $aResult['popup_message'] = Dict::S('UI:CurrentObjectLockExpired_Explanation');
+ $aResult = iTopOwnershipLock::AcquireLock($sObjClass, $iObjKey);
+ if (false === $aResult['success']) {
+ $aLockData = iTopOwnershipLock::IsLocked($sObjClass, $iObjKey);
+ // If lock taken by someone else, tell by who
+ if (true === $aLockData['locked']) {
+ // Either the contact friendlyname if the user has a contact, otherwise its login
+ $sOwner = ($aLockData['owner']->Get('contactid') > 0) ? $aLockData['owner']->Get('contactid_friendlyname') : $aLockData['owner']->GetRawName();
+ $aResult['message'] = Dict::Format('UI:CurrentObjectIsSoftLockedBy_User', $sOwner);
}
}
- }
- $oPage->SetContentType('application/json');
- $oPage->add(json_encode($aResult));
- break;
+ $oPage->SetContentType('application/json');
+ $oPage->add(json_encode($aResult));
+ break;
- case 'release_lock':
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
- $sToken = utils::ReadParam('token', 0, false, 'raw_data');
+ case 'extend_lock':
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
+ $sToken = utils::ReadParam('token', 0, false, 'raw_data');
- $bReleased = iTopOwnershipLock::ReleaseLock($sObjClass, $iObjKey, $sToken);
- $aResult = [
- 'success' => $bReleased,
- ];
+ $aResult = iTopOwnershipLock::ExtendLock($sObjClass, $iObjKey, $sToken);
+ if (!$aResult['status']) {
+ if ($aResult['operation'] == 'lost') {
+ $sName = $aResult['owner']->GetName();
+ if ($aResult['owner']->Get('contactid') != 0) {
+ $sName .= ' ('.$aResult['owner']->Get('contactid_friendlyname').')';
+ }
+ $aResult['message'] = Dict::Format('UI:CurrentObjectIsLockedBy_User', $sName);
+ $aResult['popup_message'] = Dict::Format('UI:CurrentObjectIsLockedBy_User_Explanation', $sName);
+ } else {
+ if ($aResult['operation'] == 'expired') {
+ $aResult['message'] = Dict::S('UI:CurrentObjectLockExpired');
+ $aResult['popup_message'] = Dict::S('UI:CurrentObjectLockExpired_Explanation');
+ }
+ }
+ }
- $oPage->SetContentType('application/json');
- $oPage->add(json_encode($aResult));
- break;
+ $oPage->SetContentType('application/json');
+ $oPage->add(json_encode($aResult));
+ break;
- case 'watchdog':
- $oPage->add('ok'); // Better for debugging...
- break;
+ case 'release_lock':
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjKey = (int)utils::ReadParam('obj_key', 0, false, 'integer');
+ $sToken = utils::ReadParam('token', 0, false, 'raw_data');
- case 'cke_img_upload':
- $oPage = new JsonPage();
- $oPage->SetOutputDataOnly(true);
+ $bReleased = iTopOwnershipLock::ReleaseLock($sObjClass, $iObjKey, $sToken);
+ $aResult = [
+ 'success' => $bReleased,
+ ];
- // Image uploaded via CKEditor
- $aResult = array(
- 'uploaded' => 0,
- 'fileName' => '',
- 'url' => '',
- 'icon' => '',
- 'msg' => '',
- 'att_id' => 0,
- 'preview' => 'false',
- );
+ $oPage->SetContentType('application/json');
+ $oPage->add(json_encode($aResult));
+ break;
- $sObjClass = stripslashes(utils::ReadParam('obj_class', '', false, 'class'));
- $sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
- if (empty($sObjClass))
- {
- $aResult['error'] = "Missing argument 'obj_class'";
- }
- elseif (empty($sTempId))
- {
- $aResult['error'] = "Missing argument 'temp_id'";
- }
- else
- {
- try
- {
+ case 'watchdog':
+ $oPage->add('ok'); // Better for debugging...
+ break;
+
+ case 'cke_img_upload':
+ $oPage = new JsonPage();
+ $oPage->SetOutputDataOnly(true);
+
+ // Image uploaded via CKEditor
+ $aResult = array(
+ 'uploaded' => 0,
+ 'fileName' => '',
+ 'url' => '',
+ 'icon' => '',
+ 'msg' => '',
+ 'att_id' => 0,
+ 'preview' => 'false',
+ );
+
+ $sObjClass = stripslashes(utils::ReadParam('obj_class', '', false, 'class'));
+ $sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
+ if (empty($sObjClass)) {
+ $aResult['error'] = "Missing argument 'obj_class'";
+ } elseif (empty($sTempId)) {
+ $aResult['error'] = "Missing argument 'temp_id'";
+ } else {
+ try {
+ $oDoc = utils::ReadPostedDocument('upload');
+ if (InlineImage::IsImage($oDoc->GetMimeType())) {
+ $aDimensions = null;
+ $oDoc = InlineImage::ResizeImageToFit($oDoc, $aDimensions);
+ /** @var InlineImage $oAttachment */
+ $oAttachment = MetaModel::NewObject('InlineImage');
+ $oAttachment->Set('expire', time() + MetaModel::GetConfig()->Get('draft_attachments_lifetime'));
+ $oAttachment->Set('temp_id', $sTempId);
+ $oAttachment->Set('item_class', $sObjClass);
+ $oAttachment->SetDefaultOrgId();
+ $oAttachment->Set('contents', $oDoc);
+ $oAttachment->Set('secret', sprintf('%06x', mt_rand(0, 0xFFFFFF))); // something not easy to guess
+ $iAttId = $oAttachment->DBInsert();
+
+ $aResult['uploaded'] = 1;
+ $aResult['msg'] = utils::EscapeHtml($oDoc->GetFileName());
+ $aResult['fileName'] = $oDoc->GetFileName();
+ $aResult['url'] = utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.$iAttId.'&s='.$oAttachment->Get('secret');
+ if (is_array($aDimensions)) {
+ $aResult['width'] = $aDimensions['width'];
+ $aResult['height'] = $aDimensions['height'];
+ }
+
+ IssueLog::Trace('InlineImage created', LogChannels::INLINE_IMAGE, array(
+ '$operation' => $operation,
+ '$aResult' => $aResult,
+ 'secret' => $oAttachment->Get('secret'),
+ 'temp_id' => $sTempId,
+ 'item_class' => $sObjClass,
+ 'user' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
+ ));
+ } else {
+ $aResult['error'] = $oDoc->GetFileName().' is not a valid image format.';
+ }
+ }
+ catch (FileUploadException $e) {
+ $aResult['error'] = $e->GetMessage();
+ }
+ }
+ $oPage->SetData($aResult);
+ break;
+
+ /** @noinspection PhpMissingBreakStatementInspection cke_upload_and_browse and cke_browse are chained */
+ case 'cke_upload_and_browse':
+ $sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
+ $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
+ try {
$oDoc = utils::ReadPostedDocument('upload');
- if (InlineImage::IsImage($oDoc->GetMimeType()))
- {
+ $sDocMimeType = $oDoc->GetMimeType();
+ if (!InlineImage::IsImage($sDocMimeType)) {
+ LogErrorMessage('CKE : error when uploading image in ajax.render.php, not an image',
+ array(
+ 'operation' => 'cke_upload_and_browse',
+ 'class' => $sObjClass,
+ 'ImgMimeType' => $sDocMimeType,
+ ));
+ } else {
$aDimensions = null;
$oDoc = InlineImage::ResizeImageToFit($oDoc, $aDimensions);
/** @var InlineImage $oAttachment */
@@ -2228,138 +2160,77 @@ EOF
$oAttachment->Set('secret', sprintf('%06x', mt_rand(0, 0xFFFFFF))); // something not easy to guess
$iAttId = $oAttachment->DBInsert();
- $aResult['uploaded'] = 1;
- $aResult['msg'] = utils::EscapeHtml($oDoc->GetFileName());
- $aResult['fileName'] = $oDoc->GetFileName();
- $aResult['url'] = utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.$iAttId.'&s='.$oAttachment->Get('secret');
- if (is_array($aDimensions)) {
- $aResult['width'] = $aDimensions['width'];
- $aResult['height'] = $aDimensions['height'];
- }
-
IssueLog::Trace('InlineImage created', LogChannels::INLINE_IMAGE, array(
'$operation' => $operation,
- '$aResult' => $aResult,
- 'secret' => $oAttachment->Get('secret'),
- 'temp_id' => $sTempId,
- 'item_class' => $sObjClass,
- 'user' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
- }
- else
- {
- $aResult['error'] = $oDoc->GetFileName().' is not a valid image format.';
- }
- } catch (FileUploadException $e)
- {
- $aResult['error'] = $e->GetMessage();
- }
- }
- $oPage->SetData($aResult);
- break;
-
- /** @noinspection PhpMissingBreakStatementInspection cke_upload_and_browse and cke_browse are chained */
- case 'cke_upload_and_browse':
- $sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
- $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
- try
- {
- $oDoc = utils::ReadPostedDocument('upload');
- $sDocMimeType = $oDoc->GetMimeType();
- if (!InlineImage::IsImage($sDocMimeType))
- {
- LogErrorMessage('CKE : error when uploading image in ajax.render.php, not an image',
- array(
- 'operation' => 'cke_upload_and_browse',
- 'class' => $sObjClass,
- 'ImgMimeType' => $sDocMimeType,
+ 'secret' => $oAttachment->Get('secret'),
+ 'temp_id' => $sTempId,
+ 'item_class' => $sObjClass,
+ 'user' => UserRights::GetUser(),
+ 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
+ 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
));
- } else {
- $aDimensions = null;
- $oDoc = InlineImage::ResizeImageToFit($oDoc, $aDimensions);
- /** @var InlineImage $oAttachment */
- $oAttachment = MetaModel::NewObject('InlineImage');
- $oAttachment->Set('expire', time() + MetaModel::GetConfig()->Get('draft_attachments_lifetime'));
- $oAttachment->Set('temp_id', $sTempId);
- $oAttachment->Set('item_class', $sObjClass);
- $oAttachment->SetDefaultOrgId();
- $oAttachment->Set('contents', $oDoc);
- $oAttachment->Set('secret', sprintf('%06x', mt_rand(0, 0xFFFFFF))); // something not easy to guess
- $iAttId = $oAttachment->DBInsert();
+ }
- IssueLog::Trace('InlineImage created', LogChannels::INLINE_IMAGE, array(
- '$operation' => $operation,
- 'secret' => $oAttachment->Get('secret'),
- 'temp_id' => $sTempId,
- 'item_class' => $sObjClass,
- 'user' => UserRights::GetUser(),
- 'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
- 'REQUEST_URI' => @$_SERVER['REQUEST_URI'],
- ));
+ }
+ catch (FileUploadException $e) {
+ LogErrorMessage('CKE : error when uploading image in ajax.render.php, exception occured',
+ array(
+ 'operation' => 'cke_upload_and_browse',
+ 'class' => $sObjClass,
+ 'exceptionMsg' => $e,
+ ));
+ }
+ // Fall though !! => browse
+
+ case 'cke_browse':
+ $oPage = new NiceWebPage(Dict::S('UI:BrowseInlineImages'));
+ $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/magnific-popup.css');
+ $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.magnific-popup.min.js');
+ $sImgUrl = utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL;
+
+ /** @noinspection SuspiciousAssignmentsInspection cke_upload_and_browse and cke_browse are chained */
+ $sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
+ $sClass = utils::ReadParam('obj_class', '', false, 'class');
+ $iObjectId = utils::ReadParam('obj_key', 0, false, 'integer');
+ $sCKEditorFuncNum = utils::ReadParam('CKEditorFuncNum', '');
+
+ if (empty($sTempId)) {
+ throw new SecurityException('Cannot access endpoint with empty temp_id parameter');
+ }
+ if (false === privUITransaction::IsTransactionValid($sTempId, false)) {
+ throw new SecurityException('Access rejected');
+ }
+ if (false === MetaModel::IsValidClass($sClass)) {
+ throw new CoreUnexpectedValue('Invalid object');
+ }
+ if ($iObjectId > 0) {
+ // searching for object in the DB with a count query
+ // using DBSearch so that user rights are applied !
+ $oSearch = new DBObjectSearch($sClass);
+ $oSearch->AddCondition(MetaModel::DBGetKey($sClass), $iObjectId, '=');
+ $oSet = new CMDBObjectSet($oSearch);
+ if (false === $oSet->CountExceeds(0)) {
+ throw new SecurityException(Dict::S('UI:ObjectDoesNotExist'));
+ }
}
- } catch (FileUploadException $e)
- {
- LogErrorMessage('CKE : error when uploading image in ajax.render.php, exception occured',
- array(
- 'operation' => 'cke_upload_and_browse',
- 'class' => $sObjClass,
- 'exceptionMsg' => $e,
- ));
- }
- // Fall though !! => browse
+ $sPostUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?CKEditorFuncNum='.$sCKEditorFuncNum;
- case 'cke_browse':
- $oPage = new NiceWebPage(Dict::S('UI:BrowseInlineImages'));
- $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/magnific-popup.css');
- $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.magnific-popup.min.js');
- $sImgUrl = utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL;
-
- /** @noinspection SuspiciousAssignmentsInspection cke_upload_and_browse and cke_browse are chained */
- $sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
- $sClass = utils::ReadParam('obj_class', '', false, 'class');
- $iObjectId = utils::ReadParam('obj_key', 0, false, 'integer');
- $sCKEditorFuncNum = utils::ReadParam('CKEditorFuncNum', '');
-
- if (empty($sTempId)) {
- throw new SecurityException('Cannot access endpoint with empty temp_id parameter');
- }
- if (false === privUITransaction::IsTransactionValid($sTempId, false)) {
- throw new SecurityException('Access rejected');
- }
- if (false === MetaModel::IsValidClass($sClass)) {
- throw new CoreUnexpectedValue('Invalid object');
- }
- if ($iObjectId > 0) {
- // searching for object in the DB with a count query
- // using DBSearch so that user rights are applied !
- $oSearch = new DBObjectSearch($sClass);
- $oSearch->AddCondition(MetaModel::DBGetKey($sClass), $iObjectId, '=');
- $oSet = new CMDBObjectSet($oSearch);
- if (false === $oSet->CountExceeds(0)) {
- throw new SecurityException(Dict::S('UI:ObjectDoesNotExist'));
- }
- }
-
- $sPostUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?CKEditorFuncNum='.$sCKEditorFuncNum;
-
- $oPage->add_style(
- <<add_style(
+ <<add(
- <<add(
+ <<
$sUploadLegend
@@ -2373,10 +2244,10 @@ EOF
EOF
- );
+ );
- $oPage->add_script(
- <<add_script(
+ <<add_ready_script(
- <<add_ready_script(
+ <<');
$('#upload_form').submit();
@@ -2417,270 +2288,266 @@ $('#upload_button').on('change', function() {
});
$('.img-picker').magnificPopup({type: 'image', closeOnContentClick: true });
EOF
- );
- $sOQL = "SELECT InlineImage WHERE ((temp_id = :temp_id) OR (item_class = :obj_class AND item_id = :obj_id))";
- $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('temp_id' => $sTempId, 'obj_class' => $sClass, 'obj_id' => $iObjectId));
- $oPage->add("$sAvailableImagesLegend ");
-
- if ($oSet->Count() == 0)
- {
- $oPage->add("$sNoInlineImage
");
- }
- else
- {
- while ($oAttachment = $oSet->Fetch())
- {
- $oDoc = $oAttachment->Get('contents');
- if ($oDoc->GetMainMimeType() == 'image') {
- $sDocName = addslashes(utils::EscapeHtml($oDoc->GetFileName()));
- $iAttId = $oAttachment->GetKey();
- $sSecret = $oAttachment->Get('secret');
- $oPage->add("$sInsertBtnLabel ");
- }
- }
- }
- $oPage->add(" ");
- break;
-
- // TODO 3.0.0: Move this to new ajax render controller?
- case 'cke_mentions':
- $oPage->SetContentType('application/json');
- $sMarker = utils::ReadParam('marker', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
- $sNeedle = utils::ReadParam('needle', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
- $sHostClass = utils::ReadParam('host_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
- $iHostId = (int) utils::ReadParam('host_id', 0, false, utils::ENUM_SANITIZATION_FILTER_INTEGER);
-
- // Check parameters
- if($sMarker === '') {
- throw new Exception('Invalid parameters, marker must be specified.');
- }
-
- $aMentionsAllowedClasses = MetaModel::GetConfig()->Get('mentions.allowed_classes');
- if (isset($aMentionsAllowedClasses[$sMarker]) === false) {
- throw new Exception('Invalid marker "'.$sMarker.'"');
- }
-
- $aMatches = array();
- if ($sNeedle !== '') {
- // Retrieve mentioned class from marker
- $sMentionedClass = $aMentionsAllowedClasses[$sMarker];
- if (MetaModel::IsValidClass($sMentionedClass) === false) {
- throw new Exception('Invalid class "'.$sMentionedClass.'" for marker "'.$sMarker.'"');
- }
-
- // Base search used when no trigger configured
- $oSearch = DBSearch::FromOQL("SELECT $sMentionedClass");
- $aSearchParams = ['needle' => "%$sNeedle%"];
-
- // Retrieve restricting scopes from triggers if any
- if ((strlen($sHostClass) > 0) && ($iHostId > 0)) {
- $oHostObj = MetaModel::GetObject($sHostClass, $iHostId);
- $aSearchParams['this'] = $oHostObj;
-
- $aTriggerMentionedSearches = [];
-
- $aTriggerSetParams = array('class_list' => MetaModel::EnumParentClasses($sHostClass, ENUM_PARENT_CLASSES_ALL));
- $oTriggerSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), array(), $aTriggerSetParams);
- /** @var \TriggerOnObjectMention $oTrigger */
- while ($oTrigger = $oTriggerSet->Fetch()) {
- $sTriggerMentionedOQL = $oTrigger->Get('mentioned_filter');
-
- // No filter on mentioned objects, don't restrict the scope at all, it can be any object of $sMentionedClass
- if (strlen($sTriggerMentionedOQL) === 0) {
- $aTriggerMentionedSearches = [$oSearch];
- break;
- }
-
- $oTriggerMentionedSearch = DBSearch::FromOQL($sTriggerMentionedOQL);
- $sTriggerMentionedClass = $oTriggerMentionedSearch->GetClass();
-
- // Filter is not about the mentioned class, don't mind it
- if (is_a($sMentionedClass, $sTriggerMentionedClass, true) === false) {
- continue;
- }
-
- $aTriggerMentionedSearches[] = $oTriggerMentionedSearch;
- }
-
- if (count($aTriggerMentionedSearches) > 0) {
- $oSearch = new DBUnionSearch($aTriggerMentionedSearches);
- }
- }
-
- $sSearchMainClassName = $oSearch->GetClass();
- $sSearchMainClassAlias = $oSearch->GetClassAlias();
-
- $sObjectImageAttCode = MetaModel::GetImageAttributeCode($sSearchMainClassName);
-
- // Add condition to filter on the friendlyname
- $oSearch->AddConditionExpression(
- new BinaryExpression(new FieldExpression('friendlyname', $sSearchMainClassAlias), 'LIKE', new VariableExpression('needle'))
);
+ $sOQL = "SELECT InlineImage WHERE ((temp_id = :temp_id) OR (item_class = :obj_class AND item_id = :obj_id))";
+ $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('temp_id' => $sTempId, 'obj_class' => $sClass, 'obj_id' => $iObjectId));
+ $oPage->add("$sAvailableImagesLegend ");
- $oSet = new DBObjectSet($oSearch, [], $aSearchParams);
- // Optimize fields to load
- $aObjectAttCodesToLoad = [];
- if (MetaModel::IsValidAttCode($sSearchMainClassName, $sObjectImageAttCode)) {
- $aObjectAttCodesToLoad[] = $sObjectImageAttCode;
+ if ($oSet->Count() == 0) {
+ $oPage->add("$sNoInlineImage
");
+ } else {
+ while ($oAttachment = $oSet->Fetch()) {
+ $oDoc = $oAttachment->Get('contents');
+ if ($oDoc->GetMainMimeType() == 'image') {
+ $sDocName = addslashes(utils::EscapeHtml($oDoc->GetFileName()));
+ $iAttId = $oAttachment->GetKey();
+ $sSecret = $oAttachment->Get('secret');
+ $oPage->add("$sInsertBtnLabel ");
+ }
+ }
}
- $oSet->OptimizeColumnLoad([$oSearch->GetClassAlias() => $aObjectAttCodesToLoad]);
- $oSet->SetLimit(MetaModel::GetConfig()->Get('max_autocomplete_results'));
- // Note: We have to this manually because of a bug in DBSearch not checking the user prefs. by default.
- $oSet->SetShowObsoleteData(utils::ShowObsoleteData());
+ $oPage->add(" ");
+ break;
- while ($oObject = $oSet->Fetch()) {
- // Note $oObject finalclass might be different than $sMentionedClass
- $sObjectClass = get_class($oObject);
- $iObjectId = $oObject->GetKey();
- $aMatch = [
- 'class' => $sObjectClass,
- 'id' => $iObjectId,
- 'friendlyname' => $oObject->Get('friendlyname'),
- ];
+ // TODO 3.0.0: Move this to new ajax render controller?
+ case 'cke_mentions':
+ $oPage->SetContentType('application/json');
+ $sMarker = utils::ReadParam('marker', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
+ $sNeedle = utils::ReadParam('needle', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
+ $sHostClass = utils::ReadParam('host_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
+ $iHostId = (int)utils::ReadParam('host_id', 0, false, utils::ENUM_SANITIZATION_FILTER_INTEGER);
- // Try to retrieve image for contact
- if (!empty($sObjectImageAttCode)) {
- /** @var \ormDocument $oImage */
- $oImage = $oObject->Get($sObjectImageAttCode);
- if (!$oImage->IsEmpty()) {
- $aMatch['picture_style'] = "background-image: url('".$oImage->GetDisplayURL($sObjectClass, $iObjectId, $sObjectImageAttCode)."')";
- $aMatch['initials'] = '';
- } else {
- // If no image found, fallback on initials
- $aMatch['picture_style'] = '';
- $aMatch['initials'] = utils::FormatInitialsForMedallion(utils::ToAcronym($oObject->Get('friendlyname')));
+ // Check parameters
+ if ($sMarker === '') {
+ throw new Exception('Invalid parameters, marker must be specified.');
+ }
+
+ $aMentionsAllowedClasses = MetaModel::GetConfig()->Get('mentions.allowed_classes');
+ if (isset($aMentionsAllowedClasses[$sMarker]) === false) {
+ throw new Exception('Invalid marker "'.$sMarker.'"');
+ }
+
+ $aMatches = array();
+ if ($sNeedle !== '') {
+ // Retrieve mentioned class from marker
+ $sMentionedClass = $aMentionsAllowedClasses[$sMarker];
+ if (MetaModel::IsValidClass($sMentionedClass) === false) {
+ throw new Exception('Invalid class "'.$sMentionedClass.'" for marker "'.$sMarker.'"');
+ }
+
+ // Base search used when no trigger configured
+ $oSearch = DBSearch::FromOQL("SELECT $sMentionedClass");
+ $aSearchParams = ['needle' => "%$sNeedle%"];
+
+ // Retrieve restricting scopes from triggers if any
+ if ((strlen($sHostClass) > 0) && ($iHostId > 0)) {
+ $oHostObj = MetaModel::GetObject($sHostClass, $iHostId);
+ $aSearchParams['this'] = $oHostObj;
+
+ $aTriggerMentionedSearches = [];
+
+ $aTriggerSetParams = array('class_list' => MetaModel::EnumParentClasses($sHostClass, ENUM_PARENT_CLASSES_ALL));
+ $oTriggerSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), array(), $aTriggerSetParams);
+ /** @var \TriggerOnObjectMention $oTrigger */
+ while ($oTrigger = $oTriggerSet->Fetch()) {
+ $sTriggerMentionedOQL = $oTrigger->Get('mentioned_filter');
+
+ // No filter on mentioned objects, don't restrict the scope at all, it can be any object of $sMentionedClass
+ if (strlen($sTriggerMentionedOQL) === 0) {
+ $aTriggerMentionedSearches = [$oSearch];
+ break;
+ }
+
+ $oTriggerMentionedSearch = DBSearch::FromOQL($sTriggerMentionedOQL);
+ $sTriggerMentionedClass = $oTriggerMentionedSearch->GetClass();
+
+ // Filter is not about the mentioned class, don't mind it
+ if (is_a($sMentionedClass, $sTriggerMentionedClass, true) === false) {
+ continue;
+ }
+
+ $aTriggerMentionedSearches[] = $oTriggerMentionedSearch;
+ }
+
+ if (count($aTriggerMentionedSearches) > 0) {
+ $oSearch = new DBUnionSearch($aTriggerMentionedSearches);
}
}
- $aMatches[] = $aMatch;
+ $sSearchMainClassName = $oSearch->GetClass();
+ $sSearchMainClassAlias = $oSearch->GetClassAlias();
+
+ $sObjectImageAttCode = MetaModel::GetImageAttributeCode($sSearchMainClassName);
+
+ // Add condition to filter on the friendlyname
+ $oSearch->AddConditionExpression(
+ new BinaryExpression(new FieldExpression('friendlyname', $sSearchMainClassAlias), 'LIKE', new VariableExpression('needle'))
+ );
+
+ $oSet = new DBObjectSet($oSearch, [], $aSearchParams);
+ // Optimize fields to load
+ $aObjectAttCodesToLoad = [];
+ if (MetaModel::IsValidAttCode($sSearchMainClassName, $sObjectImageAttCode)) {
+ $aObjectAttCodesToLoad[] = $sObjectImageAttCode;
+ }
+ $oSet->OptimizeColumnLoad([$oSearch->GetClassAlias() => $aObjectAttCodesToLoad]);
+ $oSet->SetLimit(MetaModel::GetConfig()->Get('max_autocomplete_results'));
+ // Note: We have to this manually because of a bug in DBSearch not checking the user prefs. by default.
+ $oSet->SetShowObsoleteData(utils::ShowObsoleteData());
+
+ while ($oObject = $oSet->Fetch()) {
+ // Note $oObject finalclass might be different than $sMentionedClass
+ $sObjectClass = get_class($oObject);
+ $iObjectId = $oObject->GetKey();
+ $aMatch = [
+ 'class' => $sObjectClass,
+ 'id' => $iObjectId,
+ 'friendlyname' => $oObject->Get('friendlyname'),
+ ];
+
+ // Try to retrieve image for contact
+ if (!empty($sObjectImageAttCode)) {
+ /** @var \ormDocument $oImage */
+ $oImage = $oObject->Get($sObjectImageAttCode);
+ if (!$oImage->IsEmpty()) {
+ $aMatch['picture_style'] = "background-image: url('".$oImage->GetDisplayURL($sObjectClass, $iObjectId, $sObjectImageAttCode)."')";
+ $aMatch['initials'] = '';
+ } else {
+ // If no image found, fallback on initials
+ $aMatch['picture_style'] = '';
+ $aMatch['initials'] = utils::FormatInitialsForMedallion(utils::ToAcronym($oObject->Get('friendlyname')));
+ }
+ }
+
+ $aMatches[] = $aMatch;
+ }
}
- }
- $oPage->add(json_encode($aMatches));
- break;
+ $oPage->add(json_encode($aMatches));
+ break;
- case 'custom_fields_update':
- $oPage->SetContentType('application/json');
- $sAttCode = utils::ReadParam('attcode', '');
- $aRequestedFields = utils::ReadParam('requested_fields', array());
- $sRequestedFieldsFormPath = utils::ReadParam('form_path', '');
- $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
+ case 'custom_fields_update':
+ $oPage->SetContentType('application/json');
+ $sAttCode = utils::ReadParam('attcode', '');
+ $aRequestedFields = utils::ReadParam('requested_fields', array());
+ $sRequestedFieldsFormPath = utils::ReadParam('form_path', '');
+ $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
- $aResult = array();
+ $aResult = array();
- try
- {
- $oWizardHelper = WizardHelper::FromJSON($sJson);
- $oObj = $oWizardHelper->GetTargetObject();
+ try {
+ $oWizardHelper = WizardHelper::FromJSON($sJson);
+ $oObj = $oWizardHelper->GetTargetObject();
- $oOrmCustomFieldValue = $oObj->Get($sAttCode);
- $oForm = $oOrmCustomFieldValue->GetForm();
- $oSubForm = $oForm->FindSubForm($sRequestedFieldsFormPath);
- $oRenderer = new ConsoleFormRenderer($oSubForm);
- $aRenderRes = $oRenderer->Render($aRequestedFields);
+ $oOrmCustomFieldValue = $oObj->Get($sAttCode);
+ $oForm = $oOrmCustomFieldValue->GetForm();
+ $oSubForm = $oForm->FindSubForm($sRequestedFieldsFormPath);
+ $oRenderer = new ConsoleFormRenderer($oSubForm);
+ $aRenderRes = $oRenderer->Render($aRequestedFields);
- $aResult['form']['updated_fields'] = $aRenderRes;
- }
- catch (Exception $e) {
- $aResult['error'] = $e->getMessage();
- }
- $oPage->add(json_encode($aResult));
- break;
+ $aResult['form']['updated_fields'] = $aRenderRes;
+ }
+ catch (Exception $e) {
+ $aResult['error'] = $e->getMessage();
+ }
+ $oPage->add(json_encode($aResult));
+ break;
- //--------------------------------
- // Preferences
- //--------------------------------
- /** @internal */
- case 'preferences.set_user_picture':
- $oPage = new JsonPage();
- try {
- $oController = new PreferencesController();
- $aResult = $oController->SetUserPicture();
- $aResult['success'] = true;
- }
- catch (Exception $oException) {
- $aResult = [
- 'success' => false,
- 'error_message' => $oException->getMessage(),
- ];
- }
- $oPage->SetData($aResult);
- break;
+ //--------------------------------
+ // Preferences
+ //--------------------------------
+ /** @internal */
+ case 'preferences.set_user_picture':
+ $oPage = new JsonPage();
+ try {
+ $oController = new PreferencesController();
+ $aResult = $oController->SetUserPicture();
+ $aResult['success'] = true;
+ }
+ catch (Exception $oException) {
+ $aResult = [
+ 'success' => false,
+ 'error_message' => $oException->getMessage(),
+ ];
+ }
+ $oPage->SetData($aResult);
+ break;
- //--------------------------------
- // Activity panel
- //--------------------------------
- /** @internal */
- case 'activity_panel.save_state':
- $oPage = new JsonPage();
- try {
- $oController = new ActivityPanelController();
- $oController->SaveState();
- $aResult = [
- 'success' => true,
- ];
- }
- catch (Exception $oException) {
- $aResult = [
- 'success' => false,
- 'error_message' => $oException->getMessage(),
- ];
- }
- $oPage->SetData($aResult);
- break;
+ //--------------------------------
+ // Activity panel
+ //--------------------------------
+ /** @internal */
+ case 'activity_panel.save_state':
+ $oPage = new JsonPage();
+ try {
+ $oController = new ActivityPanelController();
+ $oController->SaveState();
+ $aResult = [
+ 'success' => true,
+ ];
+ }
+ catch (Exception $oException) {
+ $aResult = [
+ 'success' => false,
+ 'error_message' => $oException->getMessage(),
+ ];
+ }
+ $oPage->SetData($aResult);
+ break;
- /** @internal */
- case 'activity_panel.add_caselog_entries':
- $oPage = new JsonPage();
- try {
- $oController = new ActivityPanelController();
- $aResult = $oController->AddCaseLogsEntries();
- }
- catch (Exception $oException) {
- $aResult = [
- 'success' => false,
- 'error_message' => $oException->getMessage(),
- ];
- }
- $oPage->SetData($aResult);
- break;
+ /** @internal */
+ case 'activity_panel.add_caselog_entries':
+ $oPage = new JsonPage();
+ try {
+ $oController = new ActivityPanelController();
+ $aResult = $oController->AddCaseLogsEntries();
+ }
+ catch (Exception $oException) {
+ $aResult = [
+ 'success' => false,
+ 'error_message' => $oException->getMessage(),
+ ];
+ }
+ $oPage->SetData($aResult);
+ break;
- /** @internal */
- case 'activity_panel.load_more_entries':
- $oPage = new JsonPage();
- try {
- $oController = new ActivityPanelController();
- $aResult = $oController->LoadMoreEntries();
- }
- catch (Exception $oException) {
- $aResult = [
- 'success' => false,
- 'error_message' => $oException->getMessage(),
- ];
- }
- $oPage->SetData($aResult);
- break;
+ /** @internal */
+ case 'activity_panel.load_more_entries':
+ $oPage = new JsonPage();
+ try {
+ $oController = new ActivityPanelController();
+ $aResult = $oController->LoadMoreEntries();
+ }
+ catch (Exception $oException) {
+ $aResult = [
+ 'success' => false,
+ 'error_message' => $oException->getMessage(),
+ ];
+ }
+ $oPage->SetData($aResult);
+ break;
- //--------------------------------
- // Navigation menu
- //--------------------------------
- case 'get_menus_count':
- $oPage = new JsonPage();
- $oPage->SetOutputDataOnly(true);
- $oAjaxRenderController->GetMenusCount($oPage);
- break;
+ //--------------------------------
+ // Navigation menu
+ //--------------------------------
+ case 'get_menus_count':
+ $oPage = new JsonPage();
+ $oPage->SetOutputDataOnly(true);
+ $oAjaxRenderController->GetMenusCount($oPage);
+ break;
- //--------------------------------
- // Object
- //--------------------------------
- /** @internal */
- case 'object.modify':
- $oController = new ObjectController();
- $oPage = $oController->Modify();
- break;
+ //--------------------------------
+ // Object
+ //--------------------------------
+ /** @internal */
+ case 'object.modify':
+ $oController = new ObjectController();
+ $oPage = $oController->Modify();
+ break;
- default:
- $oPage->p("Invalid query.");
+ default:
+ $oPage->p("Invalid query.");
+ }
}
$oKPI->ComputeAndReport('Data fetch and format');
$oPage->output();
diff --git a/sources/Controller/AbstractController.php b/sources/Controller/AbstractController.php
index e2f4b6939..40f2b1f16 100644
--- a/sources/Controller/AbstractController.php
+++ b/sources/Controller/AbstractController.php
@@ -10,20 +10,16 @@ namespace Combodo\iTop\Controller;
* Class AbstractController
*
* Abstract controller to centralize common features of business controllers which are still to be defined.
+ * Note that this can be extended by "TwigBase" controllers or standalone controllers.
*
* @author Guillaume Lajarige
* @package Combodo\iTop\Controller
* @since 3.1.0
*/
-class AbstractController
+abstract class AbstractController implements iController
{
/**
- * It works if your JavaScript library sets an X-Requested-With HTTP header.
- * It is known to work with common JavaScript frameworks: {@link https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript}
- *
- * @see \Symfony\Component\HttpFoundation\Request::isXmlHttpRequest() Inspired by
- *
- * @return bool True if the current request is an XmlHttpRequest (eg. an AJAX request)
+ * @inheritDoc
*/
public function IsHandlingXmlHttpRequest(): bool
{
diff --git a/sources/Controller/Base/Layout/ObjectController.php b/sources/Controller/Base/Layout/ObjectController.php
index b52f855cf..a341abc21 100644
--- a/sources/Controller/Base/Layout/ObjectController.php
+++ b/sources/Controller/Base/Layout/ObjectController.php
@@ -11,6 +11,7 @@ use ApplicationException;
use cmdbAbstractObject;
use CMDBObjectSet;
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
+use Combodo\iTop\Controller\AbstractController;
use Dict;
use iTopWebPage;
use MetaModel;
@@ -27,12 +28,9 @@ use WebPage;
* @since 3.1.0
* @package Combodo\iTop\Controller\Base\Layout
*/
-class ObjectController extends \Combodo\iTop\Controller\AbstractController
+class ObjectController extends AbstractController
{
- public function View()
- {
-
- }
+ public const ROUTE_NAMESPACE = 'object';
/**
* @return \iTopWebPage|\AjaxPage Object edit form in its webpage
@@ -41,15 +39,12 @@ class ObjectController extends \Combodo\iTop\Controller\AbstractController
* @throws \CoreException
* @throws \SecurityException
*/
- public function Modify()
+ public function OperationModify()
{
$bPrintable = utils::ReadParam('printable', '0') === '1';
$sClass = utils::ReadParam('class', '', false, 'class');
$sId = utils::ReadParam('id', '');
- $sClass = 'Person';
- $sId = 6;
-
// Check parameters
if (utils::IsNullOrEmptyString($sClass) || utils::IsNullOrEmptyString($sId))
{
diff --git a/sources/Controller/iController.php b/sources/Controller/iController.php
new file mode 100644
index 000000000..2a1b1638e
--- /dev/null
+++ b/sources/Controller/iController.php
@@ -0,0 +1,30 @@
+
+ * @since 3.1.0
+ * @package Combodo\iTop\Controller
+ */
+interface iController
+{
+ /**
+ * @var string|null Meant for overlaoding. Route namespace, what will prefix the "route" parameter to define in which namespoce the operation is to be executed. If left to `null`, the controller will be ignored.
+ */
+ public const ROUTE_NAMESPACE = null;
+
+ /**
+ * It works if your JavaScript library sets an X-Requested-With HTTP header.
+ * It is known to work with common JavaScript frameworks: {@link https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript}
+ *
+ * @see \Symfony\Component\HttpFoundation\Request::isXmlHttpRequest() Inspired by
+ *
+ * @return bool True if the current request is an XmlHttpRequest (eg. an AJAX request)
+ */
+ public function IsHandlingXmlHttpRequest(): bool;
+}
diff --git a/sources/Router/Router.php b/sources/Router/Router.php
new file mode 100644
index 000000000..4fcebb63e
--- /dev/null
+++ b/sources/Router/Router.php
@@ -0,0 +1,183 @@
+
+ * @package Combodo\iTop\Router
+ * @since 3.1.0
+ * @internal
+ */
+class Router
+{
+ /** @var \Combodo\iTop\Router\Router|null Singleton instance */
+ protected static ?Router $oSingleton = null;
+
+ /**
+ * @return $this The singleton instance of the router
+ */
+ public static function GetInstance()
+ {
+ if (null === static::$oSingleton) {
+ static::$oSingleton = new static();
+ }
+
+ return static::$oSingleton;
+ }
+
+ /**********************/
+ /* Non-static methods */
+ /**********************/
+
+ /**
+ * Singleton pattern, can't use the constructor. Use {@see \Combodo\iTop\Router\Router::GetInstance()} instead.
+ *
+ * @return void
+ */
+ private function __construct()
+ {
+ // Don't do anything, we don't want to be initialized
+ }
+
+ /**
+ * @param string $sRoute
+ *
+ * @return bool True if there is a matching handler for $sRoute
+ */
+ public function CanDispatchRoute(string $sRoute): bool
+ {
+ return $this->GetDispatchSpecsForRoute($sRoute) !== null;
+ }
+
+ /**
+ * Dispatch the current request to the matching handler for $sRoute
+ *
+ * @param string $sRoute
+ *
+ * @return mixed Response from the route's handler, can be anything.
+ * Even though it can be anything, in most cases, response will either be:
+ * - A \WebPage for usual backoffice operations
+ * - null for TwigBase backoffice operations
+ */
+ public function DispatchRoute(string $sRoute)
+ {
+ $aMethodSpecs = $this->GetDispatchSpecsForRoute($sRoute);
+ $mResponse = call_user_func_array([new $aMethodSpecs[0](), $aMethodSpecs[1]], []);
+
+ return $mResponse;
+ }
+
+ /**
+ * @param string $sRoute
+ *
+ * @return array{sControllerFQCN, sOperationMethodName}|null The FQCN controller and operation method matching $sRoute, null if no matching handler
+ */
+ public function GetDispatchSpecsForRoute(string $sRoute)
+ {
+ $aRouteParts = $this->GetRouteParts($sRoute);
+ if (is_null($aRouteParts)) {
+ return null;
+ }
+
+ $sRouteNamespace = $aRouteParts['namespace'];
+ $sRouteOperation = $aRouteParts['operation'];
+ $sControllerFQCN = $this->FindControllerFromRouteNamespace($sRouteNamespace);
+ if (utils::IsNullOrEmptyString($sControllerFQCN)) {
+ return null;
+ }
+
+ $sOperationMethodName = $this->MakeOperationMethodNameFromOperation($sRouteOperation);
+ $aMethodSpecs = [$sControllerFQCN, $sOperationMethodName];
+ if (false === is_callable($aMethodSpecs)) {
+ return null;
+ }
+
+ return $aMethodSpecs;
+ }
+
+ /**
+ * @param string $sRoute
+ *
+ * @return array{namespace: string, operation: string}|null Route parts (namespace and operation) if route can be parsed, null otherwise
+ */
+ public function GetRouteParts(string $sRoute)
+ {
+ if (utils::IsNullOrEmptyString($sRoute)) {
+ return null;
+ }
+
+ $sRouteNamespace = $this->GetRouteNamespace($sRoute);
+ $sRouteOperation = $this->GetRouteOperation($sRoute);
+ if (utils::IsNullOrEmptyString($sRouteNamespace) || utils::IsNullOrEmptyString($sRouteOperation)) {
+ return null;
+ }
+
+ return ['namespace' => $sRouteNamespace, 'operation' => $sRouteOperation];
+ }
+
+ /**
+ * @param string $sRoute
+ *
+ * @return string|null Namespace of the route (eg. "object" for "object.modify") if route can be parsed null otherwise
+ */
+ public function GetRouteNamespace(string $sRoute): ?string
+ {
+ $mSeparatorPos = strripos($sRoute, '.', -1);
+ if (false === $mSeparatorPos) {
+ return null;
+ }
+
+ return substr($sRoute, 0, $mSeparatorPos);
+ }
+
+ /**
+ * @param string $sRoute
+ *
+ * @return string|null Operation of the route (eg. "modify" for "object.modify") if route can be parsed null otherwise
+ */
+ public function GetRouteOperation(string $sRoute): ?string
+ {
+ $mSeparatorPos = strripos($sRoute, '.', -1);
+ if (false === $mSeparatorPos) {
+ return null;
+ }
+
+ return substr($sRoute, $mSeparatorPos + 1);
+ }
+
+ /**
+ * @param string $sRouteNamespace {@see static::$sRouteNamespace}
+ *
+ * @return string|null The FQCN of the controller matching the $sRouteNamespace, null if none matching.
+ */
+ protected function FindControllerFromRouteNamespace(string $sRouteNamespace): ?string
+ {
+ foreach (utils::GetClassesForInterface('Combodo\iTop\Controller\iController', '', ['[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]']) as $sControllerFQCN) {
+ if ($sControllerFQCN::ROUTE_NAMESPACE === $sRouteNamespace) {
+ return $sControllerFQCN;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $sOperation
+ *
+ * @return string The method name for the $sOperation regarding the convention
+ */
+ protected function MakeOperationMethodNameFromOperation(string $sOperation): string
+ {
+ return 'Operation'.utils::ToCamelCase($sOperation);
+ }
+}
\ No newline at end of file
diff --git a/test/sources/Router/RouterTest.php b/test/sources/Router/RouterTest.php
new file mode 100644
index 000000000..82f7c6115
--- /dev/null
+++ b/test/sources/Router/RouterTest.php
@@ -0,0 +1,205 @@
+
+ * @since 3.1.0
+ * @covers \Combodo\iTop\Router\Router
+ */
+class RouterTest extends ItopTestCase
+{
+ /**
+ * @dataProvider CanDispatchRouteProvider
+ * @covers \Combodo\iTop\Router\Router::CanDispatchRoute
+ *
+ * @param string $sRoute
+ * @param $bExpectedResult
+ *
+ * @return void
+ */
+ public function testCanDispatchRoute(string $sRoute, $bExpectedResult): void
+ {
+ $oRouter = Router::GetInstance();
+ $bTestedResult = $oRouter->CanDispatchRoute($sRoute);
+
+ $sRouteNamespace = $oRouter->GetRouteNamespace($sRoute);
+ $sRouteOperation = $oRouter->GetRouteOperation($sRoute);
+ $aRouteParts = $oRouter->GetRouteParts($sRoute);
+ $sControllerFQCN = $this->InvokeNonPublicMethod(get_class($oRouter), 'FindControllerFromRouteNamespace', $oRouter, ['object']);
+ $sMethodName = $this->InvokeNonPublicMethod(get_class($oRouter), 'MakeOperationMethodNameFromOperation', $oRouter, ['modify']);
+ $aDispatchSpecs = $oRouter->GetDispatchSpecsForRoute($sRoute);
+
+$this->debug($sRoute);
+$this->debug($sRouteNamespace);
+$this->debug($sRouteOperation);
+$this->debug($aRouteParts);
+$this->debug($sControllerFQCN);
+$this->debug($sMethodName);
+$this->debug(is_callable([$sControllerFQCN, $sMethodName]) ? 'true' : 'false');
+$this->debug($aDispatchSpecs);
+$this->debug($bTestedResult);
+ $this->assertEquals($bExpectedResult, $bTestedResult, "Dispatch capability for '$sRoute' was not the expected one. Got ".var_export($bTestedResult, true).", expected ".var_export($bExpectedResult, true));
+ }
+
+ public function CanDispatchRouteProvider(): array
+ {
+ return [
+ 'Existing handler' => [
+ 'object.modify',
+ true,
+ ],
+ 'Existing controller but unknown operation' => [
+ 'object.modify_me_please',
+ false,
+ ],
+ 'Unknown controller' => [
+ 'foo.bar',
+ false,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider GetRouteNamespaceProvider
+ * @covers \Combodo\iTop\Router\Router::GetRouteNamespace
+ *
+ * @param string $sRoute
+ * @param string|null $sExpectedNamespace
+ *
+ * @return void
+ */
+ public function testGetRouteNamespace(string $sRoute, ?string $sExpectedNamespace): void
+ {
+ $oRouter = Router::GetInstance();
+ $sTestedNamespace = $oRouter->GetRouteNamespace($sRoute);
+
+ $this->assertEquals($sExpectedNamespace, $sTestedNamespace, "Namespace found for '$sRoute' was not the expected one. Got '$sTestedNamespace', expected '$sExpectedNamespace'.");
+ }
+
+ public function GetRouteNamespaceProvider(): array
+ {
+ return [
+ 'Operation without namespace' => [
+ 'some_operation',
+ null,
+ ],
+ 'Operation with namespace' => [
+ 'some_namespace.some_operation',
+ 'some_namespace',
+ ],
+ 'Operation with multi-levels namespace' => [
+ 'some.deep.namespace.some_operation',
+ 'some.deep.namespace',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider GetRouteOperationProvider
+ * @covers \Combodo\iTop\Router\Router::GetRouteOperation
+ *
+ * @param string $sRoute
+ * @param string|null $sExpectedOperation
+ *
+ * @return void
+ */
+ public function testGetRouteOperation(string $sRoute, ?string $sExpectedOperation): void
+ {
+ $oRouter = Router::GetInstance();
+ $sTestedOperation = $oRouter->GetRouteOperation($sRoute);
+
+ $this->assertEquals($sExpectedOperation, $sTestedOperation, "Operation found for '$sRoute' was not the expected one. Got '$sTestedOperation', expected '$sExpectedOperation'.");
+ }
+
+ public function GetRouteOperationProvider(): array
+ {
+ return [
+ 'Operation without namespace' => [
+ 'some_operation',
+ null,
+ ],
+ 'Operation with namespace' => [
+ 'some_namespace.some_operation',
+ 'some_operation',
+ ],
+ 'Operation with multi-levels namespace' => [
+ 'some.deep.namespace.some_operation',
+ 'some_operation',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider FindControllerFromRouteNamespaceProvider
+ * @covers \Combodo\iTop\Router\Router::FindControllerFromRouteNamespace
+ *
+ * @param string $sRouteNamespace
+ * @param string $sExpectedControllerFQCN
+ *
+ * @return void
+ */
+ public function testFindControllerFromRouteNamespace(string $sRoute, ?string $sExpectedControllerFQCN): void
+ {
+ $oRouter = Router::GetInstance();
+ $sRouteNamespace = $oRouter->GetRouteNamespace($sRoute);
+
+ $sTestedControllerFQCN = $this->InvokeNonPublicMethod(get_class($oRouter), 'FindControllerFromRouteNamespace', $oRouter, [$sRouteNamespace]);
+
+ $this->assertEquals($sExpectedControllerFQCN, $sTestedControllerFQCN, "Controller found for '$sRouteNamespace' was not the expected one. Got '$sTestedControllerFQCN', expected '$sExpectedControllerFQCN'.");
+ }
+
+ public function FindControllerFromRouteNamespaceProvider(): array
+ {
+ return [
+ 'Object controller' => [
+ 'object.modify',
+ 'Combodo\iTop\Controller\Base\Layout\ObjectController',
+ ],
+ 'Unknown controller' => [
+ 'something_that_should_not_exist_in_the_default_package.foo',
+ null,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider GetOperationMethodNameFromRouteOperationProvider
+ * @covers \Combodo\iTop\Router\Router::MakeOperationMethodNameFromOperation
+ *
+ * @param string $sRoute
+ * @param string $sExpectedMethodName
+ *
+ * @return void
+ */
+ public function testGetOperationMethodNameFromRouteOperation(string $sRoute, string $sExpectedMethodName): void
+ {
+ $oRouter = Router::GetInstance();
+ $aRouteParts = $oRouter->GetRouteParts($sRoute);
+
+ $sTestedMethodName = $this->InvokeNonPublicMethod(get_class($oRouter), 'MakeOperationMethodNameFromOperation', $oRouter, [$aRouteParts[1]]);
+
+ $this->assertEquals($sExpectedMethodName, $sTestedMethodName, "Operation method name '$aRouteParts[1]' was not matching the expected one. Got '$sTestedMethodName', expected '$sExpectedMethodName'.");
+ }
+
+ public function GetOperationMethodNameFromRouteOperationProvider(): array
+ {
+ return [
+ 'Simple operation' => [
+ 'object.modify',
+ 'OperationModify',
+ ],
+ 'Operation with an underscore' => [
+ 'object.apply_modify',
+ 'OperationApplyModify',
+ ],
+ ];
+ }
+}
\ No newline at end of file