mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
Dashboard: optimized group by (done by MySQL) + proto of a group by on 2 dimensions
SVN:trunk[2041]
This commit is contained in:
@@ -373,20 +373,63 @@ abstract class DashletGroupBy extends Dashlet
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery);
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
|
||||
if (preg_match('/^(.*):(.*)$/', $sGroupBy, $aMatches))
|
||||
{
|
||||
$sAttCode = $aMatches[1];
|
||||
$sFunction = $aMatches[2];
|
||||
|
||||
switch($sFunction)
|
||||
{
|
||||
case 'hour':
|
||||
$sGroupByLabel = 'Hour of '.$sAttCode. ' (0-23)';
|
||||
$sGroupByExpr = "DATE_FORMAT($sClassAlias.$sAttCode, '%H')"; // 0 -> 31
|
||||
break;
|
||||
|
||||
case 'month':
|
||||
$sGroupByLabel = 'Month of '.$sAttCode. ' (1 - 12)';
|
||||
$sGroupByExpr = "DATE_FORMAT($sClassAlias.$sAttCode, '%m')"; // 0 -> 31
|
||||
break;
|
||||
|
||||
case 'day_of_week':
|
||||
$sGroupByLabel = 'Day of week for '.$sAttCode. ' (sunday to saturday)';
|
||||
$sGroupByExpr = "DATE_FORMAT($sClassAlias.$sAttCode, '%w')";
|
||||
break;
|
||||
|
||||
case 'day_of_month':
|
||||
$sGroupByLabel = 'Day of month for'.$sAttCode;
|
||||
$sGroupByExpr = "DATE_FORMAT($sClassAlias.$sAttCode, '%e')"; // 0 -> 31
|
||||
break;
|
||||
|
||||
default:
|
||||
$sGroupByLabel = 'Unknown group by function '.$sFunction;
|
||||
$sGroupByExpr = $sClassAlias.'.'.$sAttCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAttCode = $sGroupBy;
|
||||
|
||||
$sGroupByExpr = $sClassAlias.'.'.$sAttCode;
|
||||
$sGroupByLabel = MetaModel::GetLabel($oFilter->GetClass(), $sAttCode);
|
||||
}
|
||||
|
||||
switch($sStyle)
|
||||
{
|
||||
case 'bars':
|
||||
$sXML = '<itopblock BlockClass="DisplayBlock" type="open_flash_chart" parameters="chart_type:bars;chart_title:'.$sTitle.';group_by:'.$sGroupBy.'" asynchronous="false" encoding="text/oql">'.$sQuery.'</itopblock>';
|
||||
$sXML = '<itopblock BlockClass="DisplayBlock" type="open_flash_chart" parameters="chart_type:bars;chart_title:'.$sGroupByLabel.';group_by:'.$sGroupByExpr.';group_by_label:'.$sGroupByLabel.'" asynchronous="false" encoding="text/oql">'.$sQuery.'</itopblock>';
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
case 'pie':
|
||||
$sXML = '<itopblock BlockClass="DisplayBlock" type="open_flash_chart" parameters="chart_type:pie;chart_title:'.$sTitle.';group_by:'.$sGroupBy.'" asynchronous="false" encoding="text/oql">'.$sQuery.'</itopblock>';
|
||||
$sXML = '<itopblock BlockClass="DisplayBlock" type="open_flash_chart" parameters="chart_type:pie;chart_title:'.$sGroupByLabel.';group_by:'.$sGroupByExpr.';group_by_label:'.$sGroupByLabel.'" asynchronous="false" encoding="text/oql">'.$sQuery.'</itopblock>';
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
case 'table':
|
||||
default:
|
||||
$sHtmlTitle = htmlentities(Dict::S($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
|
||||
$sXML = '<itopblock BlockClass="DisplayBlock" type="count" parameters="group_by:'.$sGroupBy.'" asynchronous="false" encoding="text/oql">'.$sQuery.'</itopblock>';
|
||||
$sXML = '<itopblock BlockClass="DisplayBlock" type="count" parameters="group_by:'.$sGroupByExpr.';group_by_label:'.$sGroupByLabel.'" asynchronous="false" encoding="text/oql">'.$sQuery.'</itopblock>';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -429,10 +472,11 @@ abstract class DashletGroupBy extends Dashlet
|
||||
|
||||
if ($oAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
//date_format(start_date, '%d')
|
||||
$aGroupBy['date_of_'.$sAttCode] = 'Day of '.$oAttDef->GetLabel();
|
||||
$aGroupBy[$sAttCode.':hour'] = $oAttDef->GetLabel().' (hour)';
|
||||
$aGroupBy[$sAttCode.':month'] = $oAttDef->GetLabel().' (month)';
|
||||
$aGroupBy[$sAttCode.':day_of_week'] = $oAttDef->GetLabel().' (day of week)';
|
||||
$aGroupBy[$sAttCode.':day_of_month'] = $oAttDef->GetLabel().' (day of month)';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -719,3 +763,92 @@ class DashletBadge extends Dashlet
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DashletProto extends Dashlet
|
||||
{
|
||||
public function __construct($sId)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->aProperties['class'] = 'Foo';
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sClass = $this->aProperties['class'];
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL('SELECT FunctionalCI AS fci');
|
||||
$sGroupBy1 = 'status';
|
||||
$sGroupBy2 = 'org_id_friendlyname';
|
||||
$sHtmlTitle = "Hardcoded on $sGroupBy1 and $sGroupBy2...";
|
||||
|
||||
$sAlias = $oFilter->GetClassAlias();
|
||||
|
||||
$oGroupByExp1 = new FieldExpression($sGroupBy1, $sAlias);
|
||||
$sGroupByLabel1 = MetaModel::GetLabel($oFilter->GetClass(), $sGroupBy1);
|
||||
|
||||
$oGroupByExp2 = new FieldExpression($sGroupBy2, $sAlias);
|
||||
$sGroupByLabel2 = MetaModel::GetLabel($oFilter->GetClass(), $sGroupBy2);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp1;
|
||||
$aGroupBy['grouped_by_2'] = $oGroupByExp2;
|
||||
$sSql = MetaModel::MakeGroupByQuery($oFilter, array(), $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$iTotalCount = 0;
|
||||
$aData = array();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
foreach ($aRes as $aRow)
|
||||
{
|
||||
$iCount = $aRow['_itop_count_'];
|
||||
$iTotalCount += $iCount;
|
||||
|
||||
$sValue1 = $aRow['grouped_by_1'];
|
||||
$sValue2 = $aRow['grouped_by_2'];
|
||||
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = clone $oFilter;
|
||||
$oCondition = new BinaryExpression($oGroupByExp1, '=', new ScalarExpression($sValue1));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$oCondition = new BinaryExpression($oGroupByExp2, '=', new ScalarExpression($sValue2));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$sFilter = urlencode($oSubsetSearch->serialize());
|
||||
$aData[] = array (
|
||||
'group1' => htmlentities($sValue1, ENT_QUOTES, 'UTF-8'),
|
||||
'group2' => htmlentities($sValue2, ENT_QUOTES, 'UTF-8'),
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"
|
||||
); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group1' => array('label' => $sGroupByLabel1, 'description' => ''),
|
||||
'group2' => array('label' => $sGroupByLabel2, 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
|
||||
);
|
||||
|
||||
|
||||
$oPage->add('<div style="text-align:center" class="dashlet-content">');
|
||||
|
||||
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
|
||||
$oPage->p(Dict::Format('UI:Pagination:HeaderNoSelection', $iTotalCount));
|
||||
$oPage->table($aAttribs, $aData);
|
||||
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function GetPropertiesFields(DesignerForm $oForm)
|
||||
{
|
||||
$oField = new DesignerTextField('class', 'Class', $this->aProperties['class']);
|
||||
$oForm->AddField($oField);
|
||||
}
|
||||
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
'label' => 'Test3D',
|
||||
'icon' => 'images/xxxxxx.png',
|
||||
'description' => 'Group by on two dimensions',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,34 +347,51 @@ class DisplayBlock
|
||||
case 'count':
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
$iTotalCount = $this->m_oSet->Count();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $aRow)
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
$sLabels[$sValue] = $oObj->GetAsHtml($sGroupByField);
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sLabels[$sValue] = htmlentities($sValue, ENT_QUOTES, 'UTF-8');
|
||||
$aGroupBy[$sValue] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
|
||||
$aData = array();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
foreach($aGroupBy as $sValue => $iCount)
|
||||
{
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = clone $this->m_oFilter;
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$sFilter = urlencode($oSubsetSearch->serialize());
|
||||
|
||||
$aData[] = array ( 'group' => $sLabels[$sValue],
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => MetaModel::GetLabel($this->m_oFilter->GetClass(), $sGroupByField), 'description' => ''),
|
||||
'group' => array('label' => $sGroupByLabel, 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
@@ -748,35 +765,60 @@ EOF
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sHtml .= "<div id=\"my_chart_$sId{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
|
||||
$oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }");
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$sUrl = urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".$sFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".$sFilter);
|
||||
}
|
||||
|
||||
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_$sId{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
|
||||
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
{\"data-file\":\"".$sUrl."\"}, {wmode: 'transparent'} );\n");
|
||||
$iChartCounter++;
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $aRow)
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sLabels[$sValue] = htmlentities($sValue, ENT_QUOTES, 'UTF-8');
|
||||
$aGroupBy[$sValue] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$idx = 0;
|
||||
$aURLs = array();
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$oDrillDownFilter = clone $this->m_oFilter;
|
||||
$oDrillDownFilter->AddCondition($sGroupByField, $sValue, '=');
|
||||
$aURLs[$idx] = $oDrillDownFilter->serialize();
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = clone $this->m_oFilter;
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$aURLs[$idx] = $oSubsetSearch->serialize();
|
||||
$idx++;
|
||||
}
|
||||
$sURLList = '';
|
||||
@@ -810,21 +852,35 @@ EOF
|
||||
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $aRow)
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sLabels[$sValue] = htmlentities($sValue, ENT_QUOTES, 'UTF-8');
|
||||
$aGroupBy[$sValue] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$maxValue = 0;
|
||||
@@ -876,21 +932,35 @@ EOF
|
||||
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $aRow)
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sLabels[$sValue] = htmlentities($sValue, ENT_QUOTES, 'UTF-8');
|
||||
$aGroupBy[$sValue] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
|
||||
@@ -951,12 +951,14 @@ class QueryBuilderExpressions
|
||||
{
|
||||
protected $m_oConditionExpr;
|
||||
protected $m_aSelectExpr;
|
||||
protected $m_aGroupByExpr;
|
||||
protected $m_aJoinFields;
|
||||
|
||||
public function __construct($oCondition)
|
||||
public function __construct($oCondition, $aGroupByExpr = null)
|
||||
{
|
||||
$this->m_oConditionExpr = $oCondition;
|
||||
$this->m_aSelectExpr = array();
|
||||
$this->m_aGroupByExpr = $aGroupByExpr;
|
||||
$this->m_aJoinFields = array();
|
||||
}
|
||||
|
||||
@@ -965,6 +967,11 @@ class QueryBuilderExpressions
|
||||
return $this->m_aSelectExpr;
|
||||
}
|
||||
|
||||
public function GetGroupBy()
|
||||
{
|
||||
return $this->m_aGroupByExpr;
|
||||
}
|
||||
|
||||
public function GetCondition()
|
||||
{
|
||||
return $this->m_oConditionExpr;
|
||||
@@ -998,6 +1005,13 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
if ($this->m_aGroupByExpr)
|
||||
{
|
||||
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aJoinFields as $oExpression)
|
||||
{
|
||||
$oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
@@ -1011,6 +1025,13 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
if ($this->m_aGroupByExpr)
|
||||
{
|
||||
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aGroupByExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
@@ -1024,6 +1045,13 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
if ($this->m_aGroupByExpr)
|
||||
{
|
||||
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aGroupByExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);
|
||||
|
||||
@@ -1933,7 +1933,81 @@ abstract class MetaModel
|
||||
return $aScalarArgs;
|
||||
}
|
||||
|
||||
public static function MakeGroupByQuery(DBObjectSearch $oFilter, $aArgs, $aGroupByExpr)
|
||||
{
|
||||
$aAttToLoad = array();
|
||||
$oSelect = self::MakeSelectStructure($oFilter, array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr);
|
||||
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderGroupBy($aScalarArgs);
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $sOqlQuery);
|
||||
throw $e;
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
|
||||
public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false)
|
||||
{
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
// and make sure that the ordering columns are going to be selected
|
||||
//
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
if ($sFieldAlias != 'id')
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetFirstJoinedClass()));
|
||||
}
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
$sFirstClassAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
if (self::IsValidAttCode($oFilter->GetClass(), $sFieldAlias))
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($oFilter->GetClass(), $sFieldAlias);
|
||||
foreach($oAttDef->GetOrderBySQLExpressions($sFirstClassAlias) as $sSQLExpression)
|
||||
{
|
||||
$aOrderSpec[$sSQLExpression] = $bAscending;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aOrderSpec['`'.$sFirstClassAlias.$sFieldAlias.'`'] = $bAscending;
|
||||
}
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sFirstClassAlias][$sFieldAlias]))
|
||||
{
|
||||
$aAttToLoad[$sFirstClassAlias][$sFieldAlias] = MetaModel::GetAttributeDef($oFilter->GetFirstJoinedClass(), $sFieldAlias);
|
||||
}
|
||||
}
|
||||
|
||||
$oSelect = self::MakeSelectStructure($oFilter, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $sOqlQuery);
|
||||
throw $e;
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
|
||||
protected static function MakeSelectStructure(DBObjectSearch $oFilter, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null)
|
||||
{
|
||||
// Hide objects that are not visible to the current user
|
||||
//
|
||||
@@ -1984,6 +2058,13 @@ abstract class MetaModel
|
||||
$sRawId = $sOqlQuery.'|'.implode(',', array_keys($aAttributes));
|
||||
}
|
||||
}
|
||||
if (!is_null($aGroupByExpr))
|
||||
{
|
||||
foreach($aGroupByExpr as $sAlias => $oExpr)
|
||||
{
|
||||
$sRawId = 'g:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
$sOqlId = md5($sRawId);
|
||||
}
|
||||
else
|
||||
@@ -2029,48 +2110,25 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
// and make sure that the ordering columns are going to be selected
|
||||
//
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
if ($sFieldAlias != 'id')
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetFirstJoinedClass()));
|
||||
}
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
$sFirstClassAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
if (self::IsValidAttCode($oFilter->GetClass(), $sFieldAlias))
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($oFilter->GetClass(), $sFieldAlias);
|
||||
foreach($oAttDef->GetOrderBySQLExpressions($sFirstClassAlias) as $sSQLExpression)
|
||||
{
|
||||
$aOrderSpec[$sSQLExpression] = $bAscending;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aOrderSpec['`'.$sFirstClassAlias.$sFieldAlias.'`'] = $bAscending;
|
||||
}
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sFirstClassAlias][$sFieldAlias]))
|
||||
{
|
||||
$aAttToLoad[$sFirstClassAlias][$sFieldAlias] = MetaModel::GetAttributeDef($oFilter->GetFirstJoinedClass(), $sFieldAlias);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($oSelect))
|
||||
{
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties, $aGroupByExpr);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, $aAttToLoad, array(), true /* main query */);
|
||||
$oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelect->SetSourceOQL($sOqlQuery);
|
||||
if ($aGroupByExpr)
|
||||
{
|
||||
$aCols = $oBuild->m_oQBExpressions->GetGroupBy();
|
||||
$oSelect->SetGroupBy($aCols);
|
||||
$oSelect->SetSelect($aCols);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
}
|
||||
|
||||
$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
|
||||
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
@@ -2101,22 +2159,6 @@ abstract class MetaModel
|
||||
$oSelect->AddInnerJoin($oSelectExt, 'id', $aExtendedDataSpec['join_key'] /*, $sTableAlias*/);
|
||||
}
|
||||
|
||||
// Go
|
||||
//
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
//echo "<p>MakeQuery: $sRes</p>";
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $sOqlQuery);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (self::$m_bTraceQueries)
|
||||
{
|
||||
$sQueryId = md5($sRes);
|
||||
@@ -2140,7 +2182,7 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
return $sRes;
|
||||
return $oSelect;
|
||||
}
|
||||
|
||||
public static function ShowQueryTrace()
|
||||
@@ -2205,6 +2247,8 @@ abstract class MetaModel
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, null, array(), true /* main query */);
|
||||
$oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderDelete($aScalarArgs);
|
||||
}
|
||||
@@ -2215,11 +2259,13 @@ abstract class MetaModel
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, null, $aValues, true /* main query */);
|
||||
$oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderUpdate($aScalarArgs);
|
||||
}
|
||||
|
||||
private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false)
|
||||
private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQueryUNUSED = false)
|
||||
{
|
||||
// Note: query class might be different than the class of the filter
|
||||
// -> this occurs when we are linking our class to an external class (referenced by, or pointing to)
|
||||
@@ -2442,14 +2488,6 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Translate the conditions... and go
|
||||
//
|
||||
if ($bIsMainQuery)
|
||||
{
|
||||
$oSelectBase->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelectBase->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
}
|
||||
|
||||
// That's all... cross fingers and we'll get some working query
|
||||
|
||||
//MyHelpers::var_dump_html($oSelectBase, true);
|
||||
|
||||
@@ -32,10 +32,10 @@ class QueryBuilderContext
|
||||
|
||||
public $m_oQBExpressions;
|
||||
|
||||
public function __construct($oFilter, $aModifierProperties)
|
||||
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null)
|
||||
{
|
||||
$this->m_oRootFilter = $oFilter;
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria());
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria(), $aGroupByExpr);
|
||||
|
||||
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
|
||||
$this->m_aTableAliases = array();
|
||||
|
||||
@@ -41,6 +41,7 @@ class SQLQuery
|
||||
private $m_sTable = '';
|
||||
private $m_sTableAlias = '';
|
||||
private $m_aFields = array();
|
||||
private $m_aGroupBy = array();
|
||||
private $m_oConditionExpr = null;
|
||||
private $m_bToDelete = true; // The current table must be listed for deletion ?
|
||||
private $m_aValues = array(); // Values to set in case of an update query
|
||||
@@ -62,6 +63,7 @@ class SQLQuery
|
||||
$this->m_sTable = $sTable;
|
||||
$this->m_sTableAlias = $sTableAlias;
|
||||
$this->m_aFields = $aFields;
|
||||
$this->m_aGroupBy = null;
|
||||
$this->m_oConditionExpr = null;
|
||||
$this->m_bToDelete = $bToDelete;
|
||||
$this->m_aValues = $aValues;
|
||||
@@ -125,11 +127,12 @@ class SQLQuery
|
||||
}
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
echo "From ...<br/>\n";
|
||||
echo "<pre style=\"font-size: smaller;\">\n";
|
||||
print_r($aFrom);
|
||||
@@ -141,6 +144,11 @@ class SQLQuery
|
||||
$this->m_aFields = $aExpressions;
|
||||
}
|
||||
|
||||
public function SetGroupBy($aExpressions)
|
||||
{
|
||||
$this->m_aGroupBy = $aExpressions;
|
||||
}
|
||||
|
||||
public function SetCondition($oConditionExpr)
|
||||
{
|
||||
$this->m_oConditionExpr = $oConditionExpr;
|
||||
@@ -235,11 +243,12 @@ class SQLQuery
|
||||
// The goal will be to complete the list as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = arry();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
// Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ...
|
||||
|
||||
@@ -270,11 +279,12 @@ class SQLQuery
|
||||
// The goal will be to complete the list as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sValues = self::ClauseValues($aSetValues);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
@@ -287,11 +297,12 @@ class SQLQuery
|
||||
// The goal will be to complete the lists as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
@@ -328,6 +339,27 @@ class SQLQuery
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
// Interface, build the SQL query
|
||||
public function RenderGroupBy($aArgs = array())
|
||||
{
|
||||
// The goal will be to complete the lists as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
$sSelect = self::ClauseSelect($aFields);
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
$sGroupBy = self::ClauseGroupBy($aGroupBy);
|
||||
$sSQL = "SELECT $sSelect, COUNT(*) AS _itop_count_ FROM $sFrom WHERE $sWhere GROUP BY $sGroupBy";
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
private static function ClauseSelect($aFields)
|
||||
{
|
||||
$aSelect = array();
|
||||
@@ -339,6 +371,12 @@ class SQLQuery
|
||||
return $sSelect;
|
||||
}
|
||||
|
||||
private static function ClauseGroupBy($aGroupBy)
|
||||
{
|
||||
$sRes = implode(', ', $aGroupBy);
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
private static function ClauseDelete($aDelTableAliases)
|
||||
{
|
||||
$aDelTables = array();
|
||||
@@ -415,14 +453,14 @@ class SQLQuery
|
||||
}
|
||||
|
||||
// Purpose: prepare the query data, once for all
|
||||
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
|
||||
private function privRender(&$aFrom, &$aFields, &$aGroupBy, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
|
||||
{
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
|
||||
$oCondition = $this->m_oConditionExpr;
|
||||
return $sTableAlias;
|
||||
}
|
||||
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aGroupBy, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
{
|
||||
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
|
||||
|
||||
@@ -506,6 +544,13 @@ class SQLQuery
|
||||
{
|
||||
$aFields["`$sAlias`"] = $oExpression->Render();
|
||||
}
|
||||
if ($this->m_aGroupBy)
|
||||
{
|
||||
foreach($this->m_aGroupBy as $sAlias => $oExpression)
|
||||
{
|
||||
$aGroupBy["`$sAlias`"] = $oExpression->Render();
|
||||
}
|
||||
}
|
||||
if ($this->m_bToDelete)
|
||||
{
|
||||
$aDelTables[] = "`{$this->m_sTableAlias}`";
|
||||
@@ -528,7 +573,7 @@ class SQLQuery
|
||||
{
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user