mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-17 06:18:44 +02:00
Advanced Search
SVN:b1162[5388]
This commit is contained in:
@@ -45,6 +45,7 @@ require_once(APPROOT.'/application/ui.extkeywidget.class.inc.php');
|
||||
require_once(APPROOT.'/application/ui.htmleditorwidget.class.inc.php');
|
||||
require_once(APPROOT.'/application/datatable.class.inc.php');
|
||||
require_once(APPROOT.'/sources/renderer/console/consoleformrenderer.class.inc.php');
|
||||
require_once(APPROOT.'/sources/application/search/searchform.class.inc.php');
|
||||
|
||||
abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
{
|
||||
@@ -1530,235 +1531,7 @@ EOF
|
||||
|
||||
public static function GetSearchForm(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
||||
{
|
||||
static $iSearchFormId = 0;
|
||||
$bMultiSelect = false;
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sHtml = '';
|
||||
$numCols=4;
|
||||
$sClassName = $oSet->GetFilter()->GetClass();
|
||||
|
||||
// Romain: temporarily removed the tab "OQL query" because it was not finalized
|
||||
// (especially when used to add a link)
|
||||
/*
|
||||
$sHtml .= "<div class=\"mini_tabs\" id=\"mini_tabs{$iSearchFormId}\"><ul>
|
||||
<li><a href=\"#\" onClick=\"$('div.mini_tab{$iSearchFormId}').toggle();$('#mini_tabs{$iSearchFormId} ul li a').toggleClass('selected');\">".Dict::S('UI:OQLQueryTab')."</a></li>
|
||||
<li><a class=\"selected\" href=\"#\" onClick=\"$('div.mini_tab{$iSearchFormId}').toggle();$('#mini_tabs{$iSearchFormId} ul li a').toggleClass('selected');\">".Dict::S('UI:SimpleSearchTab')."</a></li>
|
||||
</ul></div>\n";
|
||||
*/
|
||||
// Simple search form
|
||||
if (isset($aExtraParams['currentId']))
|
||||
{
|
||||
$sSearchFormId = $aExtraParams['currentId'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$iSearchFormId = $oPage->GetUniqueId();
|
||||
$sSearchFormId = 'SimpleSearchForm'.$iSearchFormId;
|
||||
$sHtml .= "<div id=\"ds_$sSearchFormId\" class=\"mini_tab{$iSearchFormId}\">\n";
|
||||
}
|
||||
// Check if the current class has some sub-classes
|
||||
if (isset($aExtraParams['baseClass']))
|
||||
{
|
||||
$sRootClass = $aExtraParams['baseClass'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRootClass = $sClassName;
|
||||
}
|
||||
$aSubClasses = MetaModel::GetSubclasses($sRootClass);
|
||||
if (count($aSubClasses) > 0)
|
||||
{
|
||||
$aOptions = array();
|
||||
$aOptions[MetaModel::GetName($sRootClass)] = "<option value=\"$sRootClass\">".MetaModel::GetName($sRootClass)."</options>\n";
|
||||
foreach($aSubClasses as $sSubclassName)
|
||||
{
|
||||
$aOptions[MetaModel::GetName($sSubclassName)] = "<option value=\"$sSubclassName\">".MetaModel::GetName($sSubclassName)."</options>\n";
|
||||
}
|
||||
$aOptions[MetaModel::GetName($sClassName)] = "<option selected value=\"$sClassName\">".MetaModel::GetName($sClassName)."</options>\n";
|
||||
ksort($aOptions);
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sClassesCombo = "<select name=\"class\" onChange=\"ReloadSearchForm('$sSearchFormId', this.value, '$sRootClass', '$sContext')\">\n".implode('', $aOptions)."</select>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClassesCombo = MetaModel::GetName($sClassName);
|
||||
}
|
||||
$oUnlimitedFilter = new DBObjectSearch($sClassName);
|
||||
$sAction = (isset($aExtraParams['action'])) ? $aExtraParams['action'] : utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
|
||||
$sHtml .= "<form id=\"fs_{$sSearchFormId}\" action=\"{$sAction}\">\n"; // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
|
||||
$sHtml .= "<h2>".Dict::Format('UI:SearchFor_Class_Objects', $sClassesCombo)."</h2>\n";
|
||||
$index = 0;
|
||||
$sHtml .= "<div>\n";
|
||||
$aMapCriteria = array();
|
||||
$aList = MetaModel::GetZListItems($sClassName, 'standard_search');
|
||||
$aConsts = $oSet->ListConstantFields(); // Some fields are constants based on the query/context
|
||||
$sClassAlias = $oSet->GetFilter()->GetClassAlias();
|
||||
foreach($aList as $sFilterCode)
|
||||
{
|
||||
//$oAppContext->Reset($sFilterCode); // Make sure the same parameter will not be passed twice
|
||||
$sHtml .= '<div class="SearchAttribute" style="white-space: nowrap;padding:5px;display:inline-block;">';
|
||||
$sFilterValue = isset($aConsts[$sClassAlias][$sFilterCode]) ? $aConsts[$sClassAlias][$sFilterCode] : '';
|
||||
$sFilterValue = utils::ReadParam($sFilterCode, $sFilterValue, false, 'raw_data');
|
||||
$sFilterOpCode = null; // Use the default 'loose' OpCode
|
||||
if (empty($sFilterValue))
|
||||
{
|
||||
if (isset($aMapCriteria[$sFilterCode]))
|
||||
{
|
||||
if (count($aMapCriteria[$sFilterCode]) > 1)
|
||||
{
|
||||
$sFilterValue = Dict::S('UI:SearchValue:Mixed');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sFilterValue = $aMapCriteria[$sFilterCode][0]['value'];
|
||||
$sFilterOpCode = $aMapCriteria[$sFilterCode][0]['opcode'];
|
||||
}
|
||||
// Todo: Investigate...
|
||||
if ($sFilterCode != 'company')
|
||||
{
|
||||
$oUnlimitedFilter->AddCondition($sFilterCode, $sFilterValue, $sFilterOpCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sFilterCode);
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
$oKeyAttDef = $oAttDef->GetFinalAttDef();
|
||||
$sKeyAttClass = $oKeyAttDef->GetHostClass();
|
||||
$sKeyAttCode = $oKeyAttDef->GetCode();
|
||||
|
||||
$sTargetClass = $oKeyAttDef->GetTargetClass();
|
||||
$oSearch = new DBObjectSearch($sTargetClass);
|
||||
$oSearch->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oAllowedValues = new DBObjectSet($oSearch);
|
||||
|
||||
$iFieldSize = $oKeyAttDef->GetMaxSize();
|
||||
$iMaxComboLength = $oKeyAttDef->GetMaximumComboLength();
|
||||
$sHtml .= "<label>".MetaModel::GetFilterLabel($sKeyAttClass, $sKeyAttCode).":</label> ";
|
||||
$aExtKeyParams = $aExtraParams;
|
||||
$aExtKeyParams['iFieldSize'] = $oKeyAttDef->GetMaxSize();
|
||||
$aExtKeyParams['iMinChars'] = $oKeyAttDef->GetMinAutoCompleteChars();
|
||||
$sHtml .= UIExtKeyWidget::DisplayFromAttCode($oPage, $sKeyAttCode, $sKeyAttClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sSearchFormId.'search_'.$sFilterCode, false, $sFilterCode, '', $aExtKeyParams, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedValues = MetaModel::GetAllowedValues_flt($sClassName, $sFilterCode, $aExtraParams);
|
||||
if (is_null($aAllowedValues))
|
||||
{
|
||||
// Any value is possible, display an input box
|
||||
$sHtml .= "<label>".MetaModel::GetFilterLabel($sClassName, $sFilterCode).":</label> <input class=\"textSearch\" name=\"$sFilterCode\" value=\"".htmlentities($sFilterValue, ENT_QUOTES, 'utf-8')."\"/>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
//Enum field, display a multi-select combo
|
||||
$sValue = "<select class=\"multiselect\" size=\"1\" name=\"{$sFilterCode}[]\" multiple>\n";
|
||||
$bMultiSelect = true;
|
||||
//$sValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
|
||||
asort($aAllowedValues);
|
||||
foreach($aAllowedValues as $key => $value)
|
||||
{
|
||||
if (is_array($sFilterValue) && in_array($key, $sFilterValue))
|
||||
{
|
||||
$sSelected = ' selected';
|
||||
}
|
||||
else if ($sFilterValue == $key)
|
||||
{
|
||||
$sSelected = ' selected';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = '';
|
||||
}
|
||||
$sValue .= "<option value=\"$key\"$sSelected>$value</option>\n";
|
||||
}
|
||||
$sValue .= "</select>\n";
|
||||
$sHtml .= "<label>".MetaModel::GetFilterLabel($sClassName, $sFilterCode).":</label> $sValue\n";
|
||||
}
|
||||
}
|
||||
unset($aExtraParams[$sFilterCode]);
|
||||
|
||||
// Finally, add a tooltip if one is defined for this attribute definition
|
||||
$sTip = $oAttDef->GetHelpOnSmartSearch();
|
||||
if (strlen($sTip) > 0)
|
||||
{
|
||||
$sTip = addslashes($sTip);
|
||||
$sTip = str_replace(array("\n", "\r"), " ", $sTip);
|
||||
// :input does represent in form visible input (INPUT, SELECT, TEXTAREA)
|
||||
$oPage->add_ready_script("$('form#fs_$sSearchFormId :input[name={$sFilterCode}]').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
$index++;
|
||||
$sHtml .= '</div> ';
|
||||
}
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<p align=\"right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Search')."\"></p>\n";
|
||||
if (isset($aExtraParams['table_id']))
|
||||
{
|
||||
// Rename to avoid collisions...
|
||||
$aExtraParams['_table_id_'] = $aExtraParams['table_id'];
|
||||
unset($aExtraParams['table_id']);
|
||||
}
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
if (is_scalar($sValue))
|
||||
{
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
}
|
||||
$sHtml .= "<input type=\"hidden\" name=\"class\" value=\"$sClassName\" />\n";
|
||||
$sHtml .= "<input type=\"hidden\" name=\"dosearch\" value=\"1\" />\n";
|
||||
$sHtml .= "<input type=\"hidden\" name=\"operation\" value=\"search_form\" />\n";
|
||||
$sHtml .= $oAppContext->GetForForm();
|
||||
$sHtml .= "</form>\n";
|
||||
if (!isset($aExtraParams['currentId']))
|
||||
{
|
||||
$sHtml .= "</div><!-- Simple search form -->\n";
|
||||
}
|
||||
if ($bMultiSelect)
|
||||
{
|
||||
$aOptions = array(
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
|
||||
}
|
||||
/*
|
||||
// OQL query builder
|
||||
$sHtml .= "<div id=\"OQLQuery{$iSearchFormId}\" style=\"display:none\" class=\"mini_tab{$iSearchFormId}\">\n";
|
||||
$sHtml .= "<h1>".Dict::S('UI:OQLQueryBuilderTitle')."</h1>\n";
|
||||
$sHtml .= "<form id=\"formOQL{$iSearchFormId}\"><table style=\"width:80%;\"><tr style=\"vertical-align:top\">\n";
|
||||
$sHtml .= "<td style=\"text-align:right\"><label>SELECT </label><select name=\"oql_class\">";
|
||||
$aClasses = MetaModel::EnumChildClasses($sClassName, ENUM_CHILD_CLASSES_ALL);
|
||||
$sSelectedClass = utils::ReadParam('oql_class', $sClassName, false, 'class');
|
||||
$sOQLClause = utils::ReadParam('oql_clause', '', false, 'raw_data');
|
||||
asort($aClasses);
|
||||
foreach($aClasses as $sChildClass)
|
||||
{
|
||||
$sSelected = ($sChildClass == $sSelectedClass) ? 'selected' : '';
|
||||
$sHtml.= "<option value=\"$sChildClass\" $sSelected>".MetaModel::GetName($sChildClass)."</option>\n";
|
||||
}
|
||||
$sHtml .= "</select> </td><td>\n";
|
||||
$sHtml .= "<textarea name=\"oql_clause\" style=\"width:100%\">$sOQLClause</textarea></td></tr>\n";
|
||||
$sHtml .= "<tr><td colspan=\"2\" style=\"text-align:right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Query')."\"></td></tr>\n";
|
||||
$sHtml .= "<input type=\"hidden\" name=\"dosearch\" value=\"1\" />\n";
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
if (is_scalar($sValue))
|
||||
{
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
|
||||
}
|
||||
}
|
||||
$sHtml .= "<input type=\"hidden\" name=\"operation\" value=\"search_oql\" />\n";
|
||||
$sHtml .= $oAppContext->GetForForm();
|
||||
$sHtml .= "</table></form>\n";
|
||||
$sHtml .= "</div><!-- OQL query form -->\n";
|
||||
*/
|
||||
return $sHtml;
|
||||
return \Combodo\iTop\Application\Search\SearchForm::GetSearchForm($oPage, $oSet, $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,6 +111,8 @@ define('LINKSET_EDITMODE_ADDREMOVE', 4); // The "linked" objects can be added/re
|
||||
*/
|
||||
abstract class AttributeDefinition
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = 'raw';
|
||||
|
||||
public function GetType()
|
||||
{
|
||||
return Dict::S('Core:'.get_class($this));
|
||||
@@ -122,6 +124,16 @@ abstract class AttributeDefinition
|
||||
|
||||
abstract public function GetEditClass();
|
||||
|
||||
/**
|
||||
* Return the search widget type corresponding to this attribute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetSearchType()
|
||||
{
|
||||
return static::SEARCH_WIDGET_TYPE;
|
||||
}
|
||||
|
||||
protected $m_sCode;
|
||||
private $m_aParams = array();
|
||||
protected $m_sHostClass = '!undefined!';
|
||||
@@ -2085,6 +2097,8 @@ class AttributeBoolean extends AttributeInteger
|
||||
*/
|
||||
class AttributeString extends AttributeDBField
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = 'string';
|
||||
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
@@ -3433,6 +3447,8 @@ class AttributeTemplateHTML extends AttributeText
|
||||
*/
|
||||
class AttributeEnum extends AttributeString
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = 'enum';
|
||||
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
@@ -4526,6 +4542,8 @@ class AttributeDeadline extends AttributeDateTime
|
||||
*/
|
||||
class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = 'external_key';
|
||||
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("targetclass", "is_null_allowed", "on_target_delete"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 Combodo SARL
|
||||
// Copyright (c) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -21,11 +21,12 @@ class MissingQueryArgument extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
abstract class Expression
|
||||
{
|
||||
/**
|
||||
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
|
||||
**/
|
||||
**/
|
||||
public function DeepClone()
|
||||
{
|
||||
return unserialize(serialize($this));
|
||||
@@ -38,6 +39,16 @@ abstract class Expression
|
||||
// recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True
|
||||
abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oSearch
|
||||
* @param array $aArgs
|
||||
* @param bool $bRetrofitParams
|
||||
* @param AttributeDefinition $oAttDef
|
||||
*
|
||||
* @return array parameters for the search form
|
||||
*/
|
||||
abstract public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null);
|
||||
|
||||
/**
|
||||
* Recursively browse the expression tree
|
||||
* @param Closure $callback
|
||||
@@ -46,7 +57,7 @@ abstract class Expression
|
||||
abstract public function Browse(Closure $callback);
|
||||
|
||||
abstract public function ApplyParameters($aArgs);
|
||||
|
||||
|
||||
// recursively builds an array of class => fieldname
|
||||
abstract public function ListRequiredFields();
|
||||
|
||||
@@ -54,10 +65,10 @@ abstract class Expression
|
||||
abstract public function CollectUsedParents(&$aTable);
|
||||
|
||||
abstract public function IsTrue();
|
||||
|
||||
|
||||
// recursively builds an array of [classAlias][fieldName] => value
|
||||
abstract public function ListConstantFields();
|
||||
|
||||
|
||||
public function RequiresField($sClass, $sFieldName)
|
||||
{
|
||||
// #@# todo - optimize : this is called quite often when building a single query !
|
||||
@@ -71,6 +82,12 @@ abstract class Expression
|
||||
return base64_encode($this->Render());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sValue
|
||||
*
|
||||
* @return Expression
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function unserialize($sValue)
|
||||
{
|
||||
return self::FromOQL(base64_decode($sValue));
|
||||
@@ -119,22 +136,56 @@ abstract class Expression
|
||||
{
|
||||
return new BinaryExpression($this, 'OR', $oExpr);
|
||||
}
|
||||
|
||||
|
||||
abstract public function RenameParam($sOldName, $sNewName);
|
||||
abstract public function RenameAlias($sOldName, $sNewName);
|
||||
|
||||
/**
|
||||
* Make the most relevant label, given the value of the expression
|
||||
*
|
||||
* @param DBSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @param DBSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @return The label
|
||||
*/
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
return $sDefault;
|
||||
}
|
||||
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return array(
|
||||
'widget' => AttributeDefinition::SEARCH_WIDGET_TYPE,
|
||||
'oql' => $this->Render($aArgs, $bRetrofitParams),
|
||||
'source' => get_class($this),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split binary expression on given operator
|
||||
*
|
||||
* @param Expression $oExpr
|
||||
* @param string $sOperator
|
||||
* @param array $aAndExpr
|
||||
*
|
||||
* @return array of expressions
|
||||
*/
|
||||
public static function Split($oExpr, $sOperator = 'AND', &$aAndExpr = array())
|
||||
{
|
||||
if (($oExpr instanceof BinaryExpression) && ($oExpr->GetOperator() == $sOperator))
|
||||
{
|
||||
static::Split($oExpr->GetLeftExpr(), $sOperator, $aAndExpr);
|
||||
static::Split($oExpr->GetRightExpr(), $sOperator, $aAndExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAndExpr[] = $oExpr;
|
||||
}
|
||||
|
||||
return $aAndExpr;
|
||||
}
|
||||
}
|
||||
|
||||
class SQLExpression extends Expression
|
||||
@@ -151,6 +202,11 @@ class SQLExpression extends Expression
|
||||
return false;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -165,7 +221,7 @@ class SQLExpression extends Expression
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
@@ -183,12 +239,12 @@ class SQLExpression extends Expression
|
||||
public function CollectUsedParents(&$aTable)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
// Do nothing, since there is nothing to rename
|
||||
@@ -244,7 +300,7 @@ class BinaryExpression extends Expression
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function GetLeftExpr()
|
||||
{
|
||||
return $this->m_oLeftExpr;
|
||||
@@ -260,6 +316,27 @@ class BinaryExpression extends Expression
|
||||
return $this->m_sOperator;
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
$sOperator = Dict::S($this->GetOperator(), " {$this->GetOperator()} ");
|
||||
$oLeftExpr = $this->GetLeftExpr();
|
||||
if ($oLeftExpr instanceof FieldExpression)
|
||||
{
|
||||
$oAttDef = $oLeftExpr->GetAttDef($oSearch->GetJoinedClasses());
|
||||
}
|
||||
$oRightExpr = $this->GetRightExpr();
|
||||
if ($oRightExpr instanceof FieldExpression)
|
||||
{
|
||||
$oAttDef = $oRightExpr->GetAttDef($oSearch->GetJoinedClasses());
|
||||
}
|
||||
|
||||
$sLeft = $oLeftExpr->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
$sRight = $oRightExpr->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
|
||||
return "({$sLeft}{$sOperator}{$sRight})";
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -295,7 +372,7 @@ class BinaryExpression extends Expression
|
||||
$this->m_oRightExpr->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
$this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
@@ -321,7 +398,7 @@ class BinaryExpression extends Expression
|
||||
$this->GetLeftExpr()->CollectUsedParents($aTable);
|
||||
$this->GetRightExpr()->CollectUsedParents($aTable);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List all constant expression of the form <field> = <scalar> or <field> = :<variable>
|
||||
* Could be extended to support <field> = <function><constant_expression>
|
||||
@@ -355,7 +432,7 @@ class BinaryExpression extends Expression
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->GetLeftExpr()->RenameParam($sOldName, $sNewName);
|
||||
@@ -367,6 +444,41 @@ class BinaryExpression extends Expression
|
||||
$this->GetLeftExpr()->RenameAlias($sOldName, $sNewName);
|
||||
$this->GetRightExpr()->RenameAlias($sOldName, $sNewName);
|
||||
}
|
||||
|
||||
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
$oLeftExpr = $this->GetLeftExpr();
|
||||
$oRightExpr = $this->GetRightExpr();
|
||||
if ($oLeftExpr instanceof FieldExpression && $oRightExpr instanceof FieldExpression)
|
||||
{
|
||||
// Default criterion (Field OPE Field) is not supported
|
||||
return parent::GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
}
|
||||
if ($oLeftExpr instanceof FieldExpression)
|
||||
{
|
||||
$oAttDef = $oLeftExpr->GetAttDef($oSearch->GetJoinedClasses());
|
||||
}
|
||||
if ($oRightExpr instanceof FieldExpression)
|
||||
{
|
||||
$oAttDef = $oRightExpr->GetAttDef($oSearch->GetJoinedClasses());
|
||||
}
|
||||
|
||||
if (is_null($oAttDef))
|
||||
{
|
||||
return parent::GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
}
|
||||
|
||||
$aCriteriaLeft = $oLeftExpr->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
$aCriteriaRight = $oRightExpr->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
|
||||
$aCriteria = array_merge($aCriteriaLeft, $aCriteriaRight);
|
||||
|
||||
$aCriteria['operator'] = $this->GetOperator();
|
||||
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
|
||||
|
||||
return $aCriteria;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -390,6 +502,11 @@ class UnaryExpression extends Expression
|
||||
return $this->m_value;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -404,7 +521,7 @@ class UnaryExpression extends Expression
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
@@ -427,7 +544,7 @@ class UnaryExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
// Do nothing
|
||||
@@ -451,6 +568,39 @@ class ScalarExpression extends UnaryExpression
|
||||
parent::__construct($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $oSearch
|
||||
* @param array $aArgs
|
||||
* @param bool $bRetrofitParams
|
||||
* @param AttributeDefinition $oAttDef
|
||||
*
|
||||
* @return array|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
if (!is_null($oAttDef))
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
try
|
||||
{
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTarget = $oAttDef->GetTargetClass();
|
||||
$oObj = MetaModel::GetObject($sTarget, $this->m_value);
|
||||
|
||||
return $oObj->Get("friendlyname");
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return $oAttDef->GetAsPlainText($this->m_value);
|
||||
}
|
||||
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -469,6 +619,37 @@ class ScalarExpression extends UnaryExpression
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
$aValue = array('value' => $this->GetValue());
|
||||
if (!is_null($oAttDef))
|
||||
{
|
||||
switch (true)
|
||||
{
|
||||
case $oAttDef->IsExternalKey():
|
||||
try
|
||||
{
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTarget = $oAttDef->GetTargetClass();
|
||||
$oObj = MetaModel::GetObject($sTarget, $this->GetValue());
|
||||
|
||||
$aValue['label'] = $oObj->Get("friendlyname");
|
||||
|
||||
} catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$aValue['label'] = $oAttDef->GetAsPlainText($this->GetValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array('values' => array($aValue));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TrueExpression extends ScalarExpression
|
||||
@@ -525,6 +706,43 @@ class FieldExpression extends UnaryExpression
|
||||
$this->m_value = $sParent.'.'.$this->m_sName;
|
||||
}
|
||||
|
||||
private function GetClassName($aClasses = array())
|
||||
{
|
||||
if (isset($aClasses[$this->m_sParent]))
|
||||
{
|
||||
return $aClasses[$this->m_sParent];
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->m_sParent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oSearch
|
||||
* @param array $aArgs
|
||||
* @param bool $bRetrofitParams
|
||||
* @param AttributeDefinition $oAttDef
|
||||
*
|
||||
* @return array|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
if (empty($this->m_sParent))
|
||||
{
|
||||
return "`{$this->m_sName}`";
|
||||
}
|
||||
$sClass = $this->GetClassName($oSearch->GetJoinedClasses());
|
||||
$sAttName = MetaModel::GetLabel($sClass, $this->m_sName);
|
||||
if ($sClass != $oSearch->GetClass())
|
||||
{
|
||||
$sAttName = MetaModel::GetName($sClass).':'.$sAttName;
|
||||
}
|
||||
|
||||
return $sAttName;
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -535,6 +753,22 @@ class FieldExpression extends UnaryExpression
|
||||
return "`{$this->m_sParent}`.`{$this->m_sName}`";
|
||||
}
|
||||
|
||||
public function GetAttDef($aClasses = array())
|
||||
{
|
||||
if (!empty($this->m_sParent))
|
||||
{
|
||||
$sClass = $this->GetClassName($aClasses);
|
||||
$aAttDefs = MetaModel::ListAttributeDefs($sClass);
|
||||
if (isset($aAttDefs[$this->m_sName]))
|
||||
{
|
||||
return $aAttDefs[$this->m_sName];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function ListRequiredFields()
|
||||
{
|
||||
return array($this->m_sParent.'.'.$this->m_sName);
|
||||
@@ -565,8 +799,9 @@ class FieldExpression extends UnaryExpression
|
||||
if (!array_key_exists($this->m_sParent, $aTranslationData))
|
||||
{
|
||||
if ($bMatchAll) throw new CoreException('Unknown parent id in translation table', array('parent_id' => $this->m_sParent, 'translation_table' => array_keys($aTranslationData)));
|
||||
|
||||
return clone $this;
|
||||
}
|
||||
}
|
||||
if (!array_key_exists($this->m_sName, $aTranslationData[$this->m_sParent]))
|
||||
{
|
||||
if (!array_key_exists('*', $aTranslationData[$this->m_sParent]))
|
||||
@@ -595,12 +830,13 @@ class FieldExpression extends UnaryExpression
|
||||
|
||||
/**
|
||||
* Make the most relevant label, given the value of the expression
|
||||
*
|
||||
* @param DBSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @param DBSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @return The label
|
||||
*/
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
$sAttCode = $this->GetName();
|
||||
@@ -646,6 +882,12 @@ class FieldExpression extends UnaryExpression
|
||||
$this->m_sParent = $sNewName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return array('ref' => $this->GetParent().'.'.$this->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
// Has been resolved into an SQL expression
|
||||
@@ -678,7 +920,68 @@ class VariableExpression extends UnaryExpression
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetName() {return $this->m_sName;}
|
||||
public function GetName()
|
||||
{
|
||||
return $this->m_sName;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
$sValue = $this->m_value;
|
||||
if (!is_null($aArgs) && (array_key_exists($this->m_sName, $aArgs)))
|
||||
{
|
||||
$sValue = $aArgs[$this->m_sName];
|
||||
}
|
||||
elseif (($iPos = strpos($this->m_sName, '->')) !== false)
|
||||
{
|
||||
$sParamName = substr($this->m_sName, 0, $iPos);
|
||||
$oObj = null;
|
||||
$sAttCode = 'id';
|
||||
if (array_key_exists($sParamName.'->object()', $aArgs))
|
||||
{
|
||||
$sAttCode = substr($this->m_sName, $iPos + 2);
|
||||
$oObj = $aArgs[$sParamName.'->object()'];
|
||||
}
|
||||
elseif (array_key_exists($sParamName, $aArgs))
|
||||
{
|
||||
$sAttCode = substr($this->m_sName, $iPos + 2);
|
||||
$oObj = $aArgs[$sParamName];
|
||||
}
|
||||
if (!is_null($oObj))
|
||||
{
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
$sValue = $oObj->Get("friendlyname");
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sAttCode);
|
||||
}
|
||||
|
||||
return $sValue;
|
||||
}
|
||||
}
|
||||
if (!is_null($oAttDef))
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
try
|
||||
{
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTarget = $oAttDef->GetTargetClass();
|
||||
$oObj = MetaModel::GetObject($sTarget, $sValue);
|
||||
|
||||
return $oObj->Get("friendlyname");
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return $oAttDef->GetAsPlainText($sValue);
|
||||
}
|
||||
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
@@ -729,7 +1032,7 @@ class VariableExpression extends UnaryExpression
|
||||
$this->m_sName = $sNewName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetAsScalar($aArgs)
|
||||
{
|
||||
$oRet = null;
|
||||
@@ -798,6 +1101,11 @@ class ListExpression extends Expression
|
||||
return $this->m_aExpressions;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -833,7 +1141,7 @@ class ListExpression extends Expression
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
@@ -861,7 +1169,7 @@ class ListExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
|
||||
public function CollectUsedParents(&$aTable)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
@@ -879,7 +1187,7 @@ class ListExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$aRes = array();
|
||||
@@ -887,7 +1195,7 @@ class ListExpression extends Expression
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameAlias($sOldName, $sNewName)
|
||||
{
|
||||
@@ -896,7 +1204,23 @@ class ListExpression extends Expression
|
||||
{
|
||||
$oExpr->RenameAlias($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
$aValues = array();
|
||||
|
||||
foreach($this->m_aExpressions as $oExpression)
|
||||
{
|
||||
$aCrit = $oExpression->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef);
|
||||
if (array_key_exists('values', $aCrit))
|
||||
{
|
||||
$aValues = array_merge($aValues, $aCrit['values']);
|
||||
}
|
||||
}
|
||||
|
||||
return array('values' => $aValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -927,6 +1251,11 @@ class FunctionExpression extends Expression
|
||||
return $this->m_aArgs;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -990,7 +1319,7 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
|
||||
public function CollectUsedParents(&$aTable)
|
||||
{
|
||||
foreach ($this->m_aArgs as $oExpr)
|
||||
@@ -1008,7 +1337,7 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
foreach ($this->m_aArgs as $key => $oExpr)
|
||||
@@ -1027,12 +1356,13 @@ class FunctionExpression extends Expression
|
||||
|
||||
/**
|
||||
* Make the most relevant label, given the value of the expression
|
||||
*
|
||||
* @param DBSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @param DBSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @return The label
|
||||
*/
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
static $aWeekDayToString = null;
|
||||
@@ -1124,6 +1454,11 @@ class IntervalExpression extends Expression
|
||||
return $this->m_sUnit;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -1147,7 +1482,7 @@ class IntervalExpression extends Expression
|
||||
$this->m_oValue->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
$this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
@@ -1171,16 +1506,16 @@ class IntervalExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oValue->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameAlias($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oValue->RenameAlias($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CharConcatExpression extends Expression
|
||||
@@ -1203,6 +1538,11 @@ class CharConcatExpression extends Expression
|
||||
return $this->m_aExpressions;
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -1210,7 +1550,7 @@ class CharConcatExpression extends Expression
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
|
||||
// Concat will be globally NULL if one single argument is null !
|
||||
// Concat will be globally NULL if one single argument is null !
|
||||
$aRes[] = "COALESCE($sCol, '')";
|
||||
}
|
||||
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
|
||||
@@ -1293,7 +1633,7 @@ class CharConcatExpression extends Expression
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameAlias($sOldName, $sNewName)
|
||||
{
|
||||
@@ -1301,7 +1641,7 @@ class CharConcatExpression extends Expression
|
||||
{
|
||||
$oExpr->RenameAlias($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1315,6 +1655,10 @@ class CharConcatWSExpression extends CharConcatExpression
|
||||
parent::__construct($aExpressions);
|
||||
}
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
return $this->Render($aArgs, $bRetrofitParams);
|
||||
}
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -1322,7 +1666,7 @@ class CharConcatWSExpression extends CharConcatExpression
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
|
||||
// Concat will be globally NULL if one single argument is null !
|
||||
// Concat will be globally NULL if one single argument is null !
|
||||
$aRes[] = "COALESCE($sCol, '')";
|
||||
}
|
||||
$sSep = CMDBSource::Quote($this->m_separator);
|
||||
@@ -1502,6 +1846,7 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
|
||||
foreach($this->m_aClassIds as $sClass => $oExpression)
|
||||
{
|
||||
$this->m_aClassIds[$sClass] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
|
||||
206
sources/application/search/searchform.class.inc.php
Normal file
206
sources/application/search/searchform.class.inc.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2018 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Application\Search;
|
||||
|
||||
|
||||
use ApplicationContext;
|
||||
use AttributeDefinition;
|
||||
use CMDBObjectSet;
|
||||
use CoreException;
|
||||
use DBObjectSearch;
|
||||
use Dict;
|
||||
use Expression;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use TrueExpression;
|
||||
use utils;
|
||||
use WebPage;
|
||||
|
||||
class SearchForm
|
||||
{
|
||||
public static function GetSearchForm(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
||||
{
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClassName = $oSet->GetFilter()->GetClass();
|
||||
|
||||
// Simple search form
|
||||
if (isset($aExtraParams['currentId']))
|
||||
{
|
||||
$sSearchFormId = $aExtraParams['currentId'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$iSearchFormId = $oPage->GetUniqueId();
|
||||
$sSearchFormId = 'SimpleSearchForm'.$iSearchFormId;
|
||||
$sHtml .= "<div id=\"ds_$sSearchFormId\" class=\"mini_tab{$iSearchFormId}\">\n";
|
||||
}
|
||||
// Check if the current class has some sub-classes
|
||||
if (isset($aExtraParams['baseClass']))
|
||||
{
|
||||
$sRootClass = $aExtraParams['baseClass'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRootClass = $sClassName;
|
||||
}
|
||||
$aSubClasses = MetaModel::GetSubclasses($sRootClass);
|
||||
if (count($aSubClasses) > 0)
|
||||
{
|
||||
$aOptions = array();
|
||||
$aOptions[MetaModel::GetName($sRootClass)] = "<option value=\"$sRootClass\">".MetaModel::GetName($sRootClass)."</options>\n";
|
||||
foreach($aSubClasses as $sSubclassName)
|
||||
{
|
||||
$aOptions[MetaModel::GetName($sSubclassName)] = "<option value=\"$sSubclassName\">".MetaModel::GetName($sSubclassName)."</options>\n";
|
||||
}
|
||||
$aOptions[MetaModel::GetName($sClassName)] = "<option selected value=\"$sClassName\">".MetaModel::GetName($sClassName)."</options>\n";
|
||||
ksort($aOptions);
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sClassesCombo = "<select name=\"class\" onChange=\"ReloadSearchForm('$sSearchFormId', this.value, '$sRootClass', '$sContext')\">\n".implode('',
|
||||
$aOptions)."</select>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClassesCombo = MetaModel::GetName($sClassName);
|
||||
}
|
||||
$sAction = (isset($aExtraParams['action'])) ? $aExtraParams['action'] : utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
|
||||
$sHtml .= "<form id=\"fs_{$sSearchFormId}\" action=\"{$sAction}\">\n"; // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
|
||||
$sHtml .= "<h2>".Dict::Format('UI:SearchFor_Class_Objects', $sClassesCombo)."</h2>\n";
|
||||
$sHtml .= "<div id=\"fs_{$sSearchFormId}_criterion_outer\">\n";
|
||||
$sHtml .= "</div>\n";
|
||||
|
||||
|
||||
$sPrimaryClassName = $oSet->GetClass();
|
||||
$sPrimaryClassAlias = $oSet->GetClassAlias();
|
||||
|
||||
|
||||
$aFields = self::GetFields($sPrimaryClassName, $sPrimaryClassAlias);
|
||||
$oSearch = $oSet->GetFilter();
|
||||
$aCriterion = self::GetCriterion($oSearch);
|
||||
|
||||
$oBaseSearch = $oSearch->DeepClone();
|
||||
$oBaseSearch->ResetCondition();
|
||||
|
||||
$aSearchParams = array(
|
||||
'criterion_outer_selector' => "#fs_{$sSearchFormId}_criterion_outer",
|
||||
array(
|
||||
'search' => array(
|
||||
'fields' => $aFields,
|
||||
'criterion' => $aCriterion,
|
||||
'base_oql' => $oBaseSearch->ToOQL(),
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
$oPage->add_ready_script('$("fs_'.$sSearchFormId.'").search_form_handler('.json_encode($aSearchParams).');');
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sClassName
|
||||
*
|
||||
* @param $sClassAlias
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function GetFields($sClassName, $sClassAlias)
|
||||
{
|
||||
$aFields = array();
|
||||
try
|
||||
{
|
||||
$aList = MetaModel::GetZListItems($sClassName, 'standard_search');
|
||||
$aAttrDefs = MetaModel::ListAttributeDefs($sClassName);
|
||||
foreach($aList as $sFilterCode)
|
||||
{
|
||||
$aField = array();
|
||||
$aField['code'] = $sFilterCode;
|
||||
$aField['class'] = $sClassName;
|
||||
$aField['class_alias'] = $sClassAlias;
|
||||
$aField['label'] = Dict::S('Class:'.$sClassName.'/Attribute:'.$sFilterCode);
|
||||
if (array_key_exists($sFilterCode, $aAttrDefs))
|
||||
{
|
||||
$oAttrDef = $aAttrDefs[$sFilterCode];
|
||||
$aField['widget'] = $oAttrDef->GetSearchType();
|
||||
$aField['allowed_values'] = self::GetFieldAllowedValues($oAttrDef);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aField['widget'] = AttributeDefinition::SEARCH_WIDGET_TYPE;
|
||||
}
|
||||
$aFields[$sClassAlias.'.'.$sFilterCode] = $aField;
|
||||
}
|
||||
} catch (CoreException $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
|
||||
return $aFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $oAttrDef
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function GetFieldAllowedValues($oAttrDef)
|
||||
{
|
||||
if (method_exists($oAttrDef, 'GetAllowedValuesAsObjectSet'))
|
||||
{
|
||||
$oSet = $oAttrDef->GetAllowedValuesAsObjectSet();
|
||||
if ($oSet->Count() > MetaModel::GetConfig()->Get('max_combo_length'))
|
||||
{
|
||||
return array('autocomplete' => true);
|
||||
}
|
||||
}
|
||||
|
||||
return array('values' => $oAttrDef->GetAllowedValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oSearch
|
||||
*/
|
||||
public static function GetCriterion($oSearch)
|
||||
{
|
||||
$oExpression = $oSearch->GetCriteria();
|
||||
|
||||
$aOrCriterion = array();
|
||||
$aORExpressions = Expression::Split($oExpression, 'OR');
|
||||
foreach($aORExpressions as $oORSubExpr)
|
||||
{
|
||||
$aAndCriterion = array();
|
||||
$aAndExpressions = Expression::Split($oORSubExpr, 'AND');
|
||||
foreach($aAndExpressions as $oAndSubExpr)
|
||||
{
|
||||
if ($oAndSubExpr instanceof TrueExpression)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$aAndCriterion[] = $oAndSubExpr->GetCriterion($oSearch);
|
||||
}
|
||||
$aOrCriterion[] = array('and' => $aAndCriterion);
|
||||
}
|
||||
|
||||
return array('or' => $aOrCriterion);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2018 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Application\Search;
|
||||
|
||||
|
||||
use CMDBObjectSet;
|
||||
use CoreException;
|
||||
use Dict;
|
||||
use MetaModel;
|
||||
use WebPage;
|
||||
|
||||
class SearchForm
|
||||
{
|
||||
public static function GetSearchForm(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
||||
{
|
||||
$sHtml = '';
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sClassName
|
||||
*
|
||||
* @throws CoreException
|
||||
*/
|
||||
public static function GetFields($sClassName)
|
||||
{
|
||||
$aFields = array();
|
||||
$aList = MetaModel::GetZListItems($sClassName, 'standard_search');
|
||||
$aAttrDefs = MetaModel::ListAttributeDefs($sClassName);
|
||||
foreach($aList as $sFilterCode)
|
||||
{
|
||||
$aField = array();
|
||||
$aField['code'] = $sFilterCode;
|
||||
$aField['class'] = $sClassName;
|
||||
$aField['class_alias'] = $sClassName;
|
||||
$aField['label'] = Dict::S('Class:'.$sClassName.'/Attribute:'.$sFilterCode);
|
||||
}
|
||||
|
||||
return $aFields;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,11 +36,46 @@ class SearchFormTest extends ItopDataTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
require_once(APPROOT."sources/application/search/searchform.class.php");
|
||||
require_once(APPROOT."sources/application/search/searchform.class.inc.php");
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function testGetFields()
|
||||
{
|
||||
$this->debug(SearchForm::GetFields('Contact'));
|
||||
$aFields = SearchForm::GetFields('Contact', 'Contact');
|
||||
$this->debug(json_encode($aFields, JSON_PRETTY_PRINT));
|
||||
$this->assertCount(7, $aFields);
|
||||
|
||||
$oSearch = \DBSearch::FromOQL("SELECT Contact AS C WHERE C.status = 'active'");
|
||||
$aFields = SearchForm::GetFields($oSearch->GetClass(), $oSearch->GetClassAlias());
|
||||
$this->debug(json_encode($aFields, JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider GetCriterionProvider
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testGetCriterion($sOQL, $iOrCount)
|
||||
{
|
||||
$aCriterion = SearchForm::GetCriterion(\DBObjectSearch::FromOQL($sOQL));
|
||||
$this->debug($sOQL);
|
||||
$this->debug(json_encode($aCriterion, JSON_PRETTY_PRINT));
|
||||
$this->assertCount($iOrCount, $aCriterion['or']);
|
||||
}
|
||||
|
||||
public function GetCriterionProvider()
|
||||
{
|
||||
return array(
|
||||
array('OQL' => "SELECT Contact", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active'", 1),
|
||||
array('OQL' => "SELECT Contact AS C WHERE C.status = 'active'", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active' AND name LIKE 'toto%'", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active' AND org_id = 3", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status IN ('active', 'inactive')", 1),
|
||||
array('OQL' => "SELECT Contact WHERE status = 'active' OR name LIKE 'toto%'", 2),
|
||||
array('OQL' => "SELECT UserRequest WHERE DATE_SUB(NOW(), INTERVAL 14 DAY) < start_date", 1),
|
||||
array('OQL' => "SELECT UserRequest WHERE start_date > '2017-01-01' AND start_date < '2018-01-01'", 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user