🌐 Update nl.dictionary.itop.ui.php (#125)

This commit is contained in:
Thomas Casteleyn
2020-05-13 14:38:32 +02:00
committed by GitHub
parent 48c5698f08
commit 23afee514d
16 changed files with 262 additions and 68 deletions

View File

@@ -101,7 +101,7 @@ if ($sMode == 'install')
$oMysqli = new mysqli($sDBServer, $sDBUser, $sDBPwd);
if ($oMysqli->connect_errno)
{
die("Cannot connect to the MySQL server (".$mysqli->connect_errno . ") ".$mysqli->connect_error."\nExiting");
die("Cannot connect to the MySQL server (".$oMysqli->connect_errno . ") ".$oMysqli->connect_error."\nExiting");
}
else
{

View File

@@ -37,57 +37,68 @@ If you want to use another license, you may [create an extension][wiki new ext].
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
## 🔀 Branch model
## 🔀 iTop branch model
TL;DR:
> **create a fork from iTop main repository,
> create a branch based on the develop branch**
When we first start with Git, we were using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. As
there was some confusions about branches to use for current developed release and previous maintained release, and also because we were
using just a very few of the GitFlow commands, we decided to add just a little modification to this branch model : since april 2020
we don't have anymore a `master` branch.
We are using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. That means we have in our repo those
main branches:
Here are the branches we use and their meaning :
- develop: ongoing development version
- release/\*: if present, that means we are working on a beta version
- master: previous stable version
- support/\*: maintenance branches for older versions
- `develop`: ongoing development version
- `release/*`: if present, that means we are working on a alpha/beta/rc version for shipping
- `support/*`: maintenance branches for older versions
For example, if no beta version is currently ongoing we could have:
For example, if no version is currently prepared for shipping we could have:
- develop containing future 2.8.0 version
- master containing 2.7.x maintenance version
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
- `develop` containing future 2.8.0 version
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
In this example, when 2.8.0-beta is shipped that will become:
- develop: future 2.9.0 version
- release/2.8: 2.8.0-beta
- master: 2.7.x maintenance version
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
- `develop`: future 2.9.0 version
- `release/2.8`: 2.8.0-beta
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
And when 2.8.0 final will be out:
- develop: future 2.9.0 version
- master: 2.8.x maintenance version
- support/2.7 : 2.7.x maintenance version
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
- `develop`: future 2.9.0 version
- `support/2.8`: 2.8.x maintenance version (will host developments for 2.8.1)
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
Most of the time you should based your developments on the develop branch.
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
Also note that we have a "micro-version" concept : each of those versions have a very small amount of modifications. They are made from
`support/*` branches as well. For example 2.6.2-1 and 2.6.2-2 were made from the `support/2.6.2` branch.
## Coding
### 🎨 PHP styleguide
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
### 🌐 Translations
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
### Where to start ?
1. Create a fork from our repository (see [Working with forks - GitHub Help](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks))
2. Create a branch in this fork, based on the develop branch
3. Code !
Do create a dedicated branch for each modification you want to propose : if you don't it will be very hard to merge back your work !
Most of the time you should based your developments on the develop branch.
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
### 🎨 PHP styleguide
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
### ✅ Tests
Please create tests that covers as much as possible the code you're submitting.

View File

@@ -128,6 +128,7 @@ We would like to give a special thank you to the people from the community who c
- Schirrmann, Pascal
- Seki, Shoji
- Shilov, Vladimir
- Tahri, Ahmed R. (Ousret)
- Tulio, Marco
- Turrubiates, Miguel

View File

@@ -20,6 +20,8 @@
class DataTable
{
protected $iListId; // Unique ID inside the web page
/** @var string */
private $sDatatableContainerId;
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
protected $oSet; // The set of objects to display
protected $aClassAliases; // The aliases (alias => class) inside the set
@@ -29,10 +31,10 @@ class DataTable
protected $bShowObsoleteData;
/**
* @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display
* @param $aClassAliases array The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
* @param string $iListId Unique ID for this div/table in the page
* @param DBObjectSet $oSet The set of data to display
* @param array$aClassAliases The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param string $sTableId A string (or null) identifying this table in order to persist its settings
*
* @throws \CoreException
* @throws \MissingQueryArgument
@@ -42,6 +44,7 @@ class DataTable
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
$this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery
$this->sDatatableContainerId = 'datatable_'.utils::GetSafeId($iListId);
$this->oSet = $oSet;
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
@@ -165,7 +168,7 @@ class DataTable
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
$sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">";
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
@@ -201,7 +204,7 @@ class DataTable
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
}
$sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
$oPage->add_ready_script("$('#{$this->sDatatableContainerId}').datatable($sJSOptions);");
return $sHtml;
}
@@ -418,15 +421,15 @@ EOF;
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\">&nbsp;".Dict::S('UI:ForAllLists').'</label></p>';
$sHtml .= "</fieldset>";
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
$sHtml .= '<button type="button" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '<button type="button" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '</td><td style="text-align:center;">';
$sHtml .= '<button type="submit" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '<button type="submit" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '</td></tr></table>';
$sHtml .= "</form>";
$sHtml .= "</div>";
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });");
return $sHtml;
}
@@ -745,12 +748,25 @@ EOF;
}
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
$oPage->add_ready_script(
<<<EOF
var oTable = $('#{$this->iListId} table.listResults');
<<<JS
var oTable = $('#{$this->sDatatableContainerId} table.listResults');
oTable.tableHover();
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, table_id: '{$this->iListId}', columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
EOF
);
oTable
.tablesorter({ $sHeaders widgets: ['myZebra', 'truncatedList']})
.tablesorterPager({
container: $('#pager{$this->iListId}'),
totalRows:$iCount,
size: $iPageSize,
filter: '$sOQL',
extra_params: '$sExtraParams',
select_mode: '$sSelectModeJS',
displayKey: $sDisplayKey,
table_id: '{$this->sDatatableContainerId}',
columns: $sJSColumns,
class_aliases: $sJSClassAliases $sCssCount
});
JS
);
if ($sFakeSortList != '')
{
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");

View File

@@ -636,14 +636,22 @@ HTML
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
$bHasChildLeafs = $this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
$oPage->add('</td></tr></table>');
$oPage->add('</div>');
if ($bHasChildLeafs)
{
$oPage->add('<div class="treecontrol" id="treecontrolid"><a href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a> | <a href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></div>');
}
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\">&nbsp;&nbsp;");
$oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
$oPage->add('</div></div>');
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\n");
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n");
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
}
@@ -673,6 +681,18 @@ HTML
}
}
/**
* @param WebPage $oP
* @param \DBObjectSet $oSet
* @param string $sParentAttCode
* @param string $currValue
*
* @return bool true if there are at least one child leaf, false if only roots nodes are present
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
{
$aTree = array();
@@ -701,6 +721,9 @@ HTML
{
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
}
$bHasOnlyRootNodes = (count($aTree) === 1);
return !$bHasOnlyRootNodes;
}
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
@@ -728,7 +751,7 @@ HTML
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'>&nbsp;';
}
}
$oP->add('<li>'.$sSelect.'<label for="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'">'.$aNodes[$id]->GetName().'</label>');
$oP->add('<li class="closed">'.$sSelect.'<label for="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'">'.$aNodes[$id]->GetName().'</label>');
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
$oP->add("</li>\n");
}

View File

@@ -2914,9 +2914,9 @@ abstract class DBObject implements iDisplay
}
}
/*
* Persist an object to the DB, for the first time
*
/**
* Persist an object to the DB, for the first time
*
* @api
* @see DBWrite
*

View File

@@ -304,8 +304,12 @@ class EMail
$oHeaders = $this->m_oMessage->getHeaders();
switch(strtolower($sKey))
{
case 'return-path':
$this->m_oMessage->setReturnPath($sValue);
break;
default:
$oHeaders->addTextHeader($sKey, $sValue);
$oHeaders->addTextHeader($sKey, $sValue);
}
}
}

View File

@@ -3891,3 +3891,16 @@ input:checked + .slider:before {
}
}
}
.ui-dialog .ui-dialog-content .treecontrol {
padding-bottom:0.3em;
padding-left: 0.2em;
margin-top: -0.3em;
padding-top: 0;
}
.ui-dialog .ui-dialog-content .treecontrol a {
font-size: small;
}

View File

@@ -1,5 +1,8 @@
{
"license": "AGPLv3",
"config": {
"classmap-authoritative": true
},
"autoload": {
"psr-4": {
"Combodo\\iTop\\Portal\\": "src/"

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<information>
<version>2.7.0</version>
<version>2.8.0-dev</version>
</information>

View File

@@ -423,6 +423,8 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Button:More' => 'More',
'UI:Button:Less' => 'Less',
'UI:Button:Wait' => 'Please wait while updating fields',
'UI:Treeview:CollapseAll' => 'Collapse All',
'UI:Treeview:ExpandAll' => 'Expand All',
'UI:SearchToggle' => 'Search',
'UI:ClickToCreateNew' => 'Create a new %1$s',

View File

@@ -845,7 +845,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'UI:ModificationTitle_Class_Object' => 'Aanpassen van %1$s: <span class="hilite">%2$s</span>',
'UI:ClonePageTitle_Object_Class' => 'ITOP_APPLICATION_SHORT - Kloon %1$s - %2$s aanpassing',
'UI:CloneTitle_Class_Object' => 'Klonen van %1$s: <span class="hilite">%2$s</span>',
'UI:CreationPageTitle_Class' => 'ITOP_APPLICATION_SHORT - Nieuwe %1$s aangemaakt',
'UI:CreationPageTitle_Class' => 'ITOP_APPLICATION_SHORT - %1$s aanmaken',
'UI:CreationTitle_Class' => '%1$s aanmaken',
'UI:SelectTheTypeOf_Class_ToCreate' => 'Selecteer het type %1$s dat moet worden aangemaakt:',
'UI:Class_Object_NotUpdated' => 'Geen verandering waargenomen, %1$s (%2$s) is <strong>niet</strong> aangepast.',

View File

@@ -261,7 +261,7 @@ class MFModule
while (($sFile = readdir($hDir)) !== false)
{
$aMatches = array();
if (preg_match("/^[^\\.]+.dict.".$this->sName.".php$/i", $sFile,
if (preg_match("/^[^\\.]+.dict.".$this->sName.'.php$/i', $sFile,
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
{
$aDictionaries[] = $this->sRootDir.'/'.$sFile;
@@ -1855,7 +1855,7 @@ class MFElement extends Combodo\iTop\DesignElement
* Extracts some nodes from the DOM (active nodes only !!!)
*
* @param string $sXPath A XPath expression
* @param $sId
* @param string $sId
*
* @return DOMNodeList
*/
@@ -1867,7 +1867,7 @@ class MFElement extends Combodo\iTop\DesignElement
/**
* Returns the node directly under the given node
*
* @param $sTagName
* @param string $sTagName
* @param bool $bMustExist
*
* @return MFElement
@@ -1903,7 +1903,7 @@ class MFElement extends Combodo\iTop\DesignElement
*
* @param string $sElementName
*
* @return array|null|string
* @return array|string if no subnode is found, return current node text, else return results as array
* @throws \DOMFormatException
*/
public function GetNodeAsArrayOfItems($sElementName = 'items')
@@ -2068,6 +2068,8 @@ class MFElement extends Combodo\iTop\DesignElement
/**
* Check if the current node is under a node 'added' or 'altered'
* Usage: In such a case, the change must not be tracked
*
* @return boolean true if `_alteration` flag is set on any parent of the current node
*/
public function IsInDefinition()
{
@@ -2104,14 +2106,14 @@ class MFElement extends Combodo\iTop\DesignElement
return false;
}
static $aTraceAttributes = null;
protected static $aTraceAttributes = null;
/**
* Enable/disable the trace on changed nodes
*
* @param array aAttributes Array of attributes (key => value) to be added onto any changed node
*/
static public function SetTrace($aAttributes = null)
public static function SetTrace($aAttributes = null)
{
self::$aTraceAttributes = $aAttributes;
}
@@ -2582,9 +2584,9 @@ class MFDocument extends \Combodo\iTop\DesignDocument
}
/**
* @param $sXPath
* @param $sId
* @param null $oContextNode
* @param string $sXPath
* @param string $sId
* @param \DOMNode $oContextNode
*
* @return \DOMNodeList
*/

View File

@@ -0,0 +1,72 @@
<?php
namespace Combodo\iTop\Test\UnitTest\Core;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class BulkChangeTest extends ItopDataTestCase
{
const CREATE_TEST_ORG = true;
protected function setUp()
{
parent::setUp();
require_once(APPROOT.'core/coreexception.class.inc.php');
require_once(APPROOT.'core/bulkchange.class.inc.php');
}
//bug 2888: csv import / data synchro issue with password validation
public function testPasswordBulkChangeIssue()
{
/** @var Personn $oPerson */
$oPerson = $this->createObject('Person', array(
'first_name' => 'isaac',
'name' => 'asimov',
'email' => 'isaac.asimov@fundation.org',
'org_id' => $this->getTestOrgId(),
));
$aData = array(
array($oPerson->Get("first_name"),
$oPerson->Get("name"),
$oPerson->Get("email"),
"EN US",
"iasimov",
"harryseldon",
"profileid->name:Administrator"
)
);
$aAttributes = array("language" => 3, "login" => 4, "password" => 5, "profile_list" => 6);
$aExtKeys = array("contactid" =>
array("first_name" => 0, "name" => 1, "email" => 2));
$oBulk = new \BulkChange(
"UserLocal",
$aData,
$aAttributes,
$aExtKeys,
array("login"),
null,
null,
"Y-m-d H:i:s", // date format
true // localize
);
$oChange = \CMDBObject::GetCurrentChange();
$aRes = $oBulk->Process($oChange);
static::assertNotNull($aRes);
foreach ($aRes as $aRow)
{
if (array_key_exists('__STATUS__', $aRow))
{
$sStatus = $aRow['__STATUS__'];
$this->assertFalse(strstr($sStatus->GetDescription(), "CoreCannotSaveObjectException"), "CSVimport/Datasynchro: Password validation failed with: " . $sStatus->GetDescription());
}
}
}
}

View File

@@ -56,6 +56,9 @@ class DBSearchTest extends ItopDataTestCase
protected function setUp()
{
parent::setUp();
require_once(APPROOT.'application/itopwebpage.class.inc.php');
require_once(APPROOT.'application/displayblock.class.inc.php');
}
/**
@@ -656,4 +659,33 @@ class DBSearchTest extends ItopDataTestCase
static::assertEquals('', $sExceptionClass);
}
/**
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function testSelectInWithVariableExpressions()
{
$aReq = array(array(1, 0, 0), array(1, 1, 3), array(1, 2, 1), array(1, 0, 1), array(1, 1, 0), array(1, 2, 1));
$sOrgs = $this->init_db(3, 4, $aReq);
$allOrgIds = explode(",", $sOrgs);
$TwoOrgIdsOnly = array($allOrgIds[0], $allOrgIds[1]);
$oSearch = DBSearch::FromOQL("SELECT UserRequest WHERE org_id IN (:org_ids)");
self::assertNotNull($oSearch);
$oSet = new \CMDBObjectSet($oSearch, array(), array('org_ids'=> $TwoOrgIdsOnly));
static::assertEquals(4, $oSet->Count());
$_SERVER['REQUEST_URI']='FAKE_REQUEST_URI' ;
$_SERVER['REQUEST_METHOD']='FAKE_REQUEST_METHOD';
$oP = new \iTopWebPage("test");
$oBlock = new \DisplayBlock($oSet->GetFilter(), 'list', false);
$sHtml = $oBlock->GetDisplay($oP, 'package_table', array ('menu'=>true, 'display_limit'=>false));
$iHtmlUserRequestLineCount = substr_count($sHtml, '<tr><td data-object-class="UserRequest"');
static::assertEquals(4, $iHtmlUserRequestLineCount, "Failed Generated html :" . $sHtml);
$oP->output();
}
}

View File

@@ -79,7 +79,7 @@ try
utils::UseParamFile();
$oKPI->ComputeAndReport('Data model loaded');
$iRet = LoginWebPage::DoLogin(false, false, LoginWebPage::EXIT_RETURN); // Starting with iTop 2.2.0 portal users are no longer allowed to access the REST/JSON API
$oKPI->ComputeAndReport('User login');
@@ -130,11 +130,26 @@ try
{
throw new Exception("Missing parameter 'json_data'", RestResult::MISSING_JSON);
}
$aJsonData = @json_decode($sJsonString);
if ($aJsonData == null)
if (is_string($sJsonString))
{
throw new Exception("Parameter json_data is not a valid JSON structure", RestResult::INVALID_JSON);
}
$aJsonData = @json_decode($sJsonString);
}
elseif(is_array($sJsonString))
{
$aJsonData = (object) $sJsonString;
$sJsonString = json_encode($aJsonData);
}
else
{
$aJsonData = null;
}
if ($aJsonData == null)
{
throw new Exception('Parameter json_data is not a valid JSON structure', RestResult::INVALID_JSON);
}
$oKPI->ComputeAndReport('Parameters validated');