mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 15:22:17 +02:00
Portal: Performance optimization on ManageBrick
SVN:trunk[4718]
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
namespace Combodo\iTop\Portal\Controller;
|
namespace Combodo\iTop\Portal\Controller;
|
||||||
|
|
||||||
|
use Combodo\iTop\Portal\Helper\ScopeValidatorHelper;
|
||||||
use \Silex\Application;
|
use \Silex\Application;
|
||||||
use \Symfony\Component\HttpFoundation\Request;
|
use \Symfony\Component\HttpFoundation\Request;
|
||||||
use \UserRights;
|
use \UserRights;
|
||||||
@@ -267,8 +268,8 @@ class ManageBrickController extends BrickController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restricting query to allowed scope on each classes
|
// Restricting query to allowed scope on each classes
|
||||||
// Note : Will need to moved the scope restriction on queries elsewhere when we consider grouping on something else than finalclass
|
// Note: Will need to moved the scope restriction on queries elsewhere when we consider grouping on something else than finalclass
|
||||||
// Note : We now get view scope instead of edit scope as we allowed users to view/edit objects in the brick regarding their rights
|
// Note: We now get view scope instead of edit scope as we allowed users to view/edit objects in the brick regarding their rights
|
||||||
$oScopeQuery = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $aGroupingAreasValue['value'], UR_ACTION_READ);
|
$oScopeQuery = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $aGroupingAreasValue['value'], UR_ACTION_READ);
|
||||||
if ($oScopeQuery !== null)
|
if ($oScopeQuery !== null)
|
||||||
{
|
{
|
||||||
@@ -284,7 +285,7 @@ class ManageBrickController extends BrickController
|
|||||||
$oAreaQuery = null;
|
$oAreaQuery = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$aQueries[$sKey] = $oAreaQuery;
|
$aQueries[$sKey] = $oAreaQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing appropriate data loading mode if we are in auto
|
// Testing appropriate data loading mode if we are in auto
|
||||||
@@ -346,11 +347,12 @@ class ManageBrickController extends BrickController
|
|||||||
|
|
||||||
$oSet->OptimizeColumnLoad($aColumnsToLoad);
|
$oSet->OptimizeColumnLoad($aColumnsToLoad);
|
||||||
$oSet->SetOrderByClasses();
|
$oSet->SetOrderByClasses();
|
||||||
|
SecurityHelper::PreloadForCache($oApp, $oSet->GetFilter(), $aColumnsToLoad[$oQuery->GetClassAlias()] /* preloading only extkeys from the main class */);
|
||||||
$aSets[$sKey] = $oSet;
|
$aSets[$sKey] = $oSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieving and preparing datas for rendering
|
// Retrieving and preparing data for rendering
|
||||||
$aGroupingAreasData = array();
|
$aGroupingAreasData = array();
|
||||||
foreach ($aSets as $sKey => $oSet)
|
foreach ($aSets as $sKey => $oSet)
|
||||||
{
|
{
|
||||||
@@ -373,6 +375,7 @@ class ManageBrickController extends BrickController
|
|||||||
|
|
||||||
// Getting items
|
// Getting items
|
||||||
$aItems = array();
|
$aItems = array();
|
||||||
|
$aItemsIds = array();
|
||||||
// ... For each item
|
// ... For each item
|
||||||
/** @var DBObject $oCurrentRow */
|
/** @var DBObject $oCurrentRow */
|
||||||
while ($oCurrentRow = $oSet->Fetch())
|
while ($oCurrentRow = $oSet->Fetch())
|
||||||
@@ -457,8 +460,18 @@ class ManageBrickController extends BrickController
|
|||||||
'attributes' => $aItemAttrs,
|
'attributes' => $aItemAttrs,
|
||||||
'highlight_class' => $oCurrentRow->GetHilightClass()
|
'highlight_class' => $oCurrentRow->GetHilightClass()
|
||||||
);
|
);
|
||||||
|
$aItemsIds = $oCurrentRow->GetKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we retrieved items, we check which can be edited, which can be view and which cannot be opened
|
||||||
|
//
|
||||||
|
// Note: Now that we do checks here and not through the SecurityHelper while fetching objects, we might bypass datamodel security regarding the object class!
|
||||||
|
// $oScopeQuery = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sCurrentClass, UR_ACTION_MODIFY);
|
||||||
|
// if($oSearchEditableItems !== null)
|
||||||
|
// {
|
||||||
|
// $oSearchEditableItems->A
|
||||||
|
// }
|
||||||
|
|
||||||
$aGroupingAreasData[$sKey] = array(
|
$aGroupingAreasData[$sKey] = array(
|
||||||
'sId' => $sKey,
|
'sId' => $sKey,
|
||||||
'sTitle' => $aGroupingAreasValues[$sKey]['label'],
|
'sTitle' => $aGroupingAreasValues[$sKey]['label'],
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ use \UserRights;
|
|||||||
use \Dict;
|
use \Dict;
|
||||||
use \IssueLog;
|
use \IssueLog;
|
||||||
use \MetaModel;
|
use \MetaModel;
|
||||||
|
use \DBSearch;
|
||||||
|
use \DBObjectSearch;
|
||||||
use \DBObjectSet;
|
use \DBObjectSet;
|
||||||
use \FieldExpression;
|
use \FieldExpression;
|
||||||
use \VariableExpression;
|
use \VariableExpression;
|
||||||
@@ -48,6 +50,10 @@ class SecurityHelper
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the current user is allowed to do the $sAction on an $sObjectClass object (with optionnal $sObjectId id)
|
* Returns true if the current user is allowed to do the $sAction on an $sObjectClass object (with optionnal $sObjectId id)
|
||||||
|
* Checks are:
|
||||||
|
* - Has a scope query for the $sObjectClass / $sAction
|
||||||
|
* - Optionally, if $sObjectId provided: Is object within scope for $sObjectClass / $sObjectId / $sAction
|
||||||
|
* - Is allowed by datamodel for $sObjectClass / $sAction
|
||||||
*
|
*
|
||||||
* @param Silex\Application $oApp
|
* @param Silex\Application $oApp
|
||||||
* @param string $sAction Must be in UR_ACTION_READ|UR_ACTION_MODIFY|UR_ACTION_CREATE
|
* @param string $sAction Must be in UR_ACTION_READ|UR_ACTION_MODIFY|UR_ACTION_CREATE
|
||||||
@@ -155,4 +161,105 @@ class SecurityHelper
|
|||||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sObjectClass, $sStimulusCode, $oInstanceSet) : UR_ALLOWED_NO;
|
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sObjectClass, $sStimulusCode, $oInstanceSet) : UR_ALLOWED_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preloads scope objects cache with objects from $oQuery
|
||||||
|
*
|
||||||
|
* @param Application $oApp
|
||||||
|
* @param DBSearch $oSet
|
||||||
|
* @param array $aExtKeysToPreload
|
||||||
|
*/
|
||||||
|
public static function PreloadForCache(Application $oApp, DBSearch $oSearch, $aExtKeysToPreload = null)
|
||||||
|
{
|
||||||
|
$sObjectClass = $oSearch->GetClass();
|
||||||
|
$aObjectIds = array();
|
||||||
|
$aExtKeysIds = array();
|
||||||
|
$aColumnsToLoad = array();
|
||||||
|
|
||||||
|
if($aExtKeysToPreload !== null)
|
||||||
|
{
|
||||||
|
foreach($aExtKeysToPreload as $sAttCode)
|
||||||
|
{
|
||||||
|
/** @var \AttributeDefinition $oAttDef */
|
||||||
|
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
|
||||||
|
if($oAttDef->IsExternalKey())
|
||||||
|
{
|
||||||
|
$aExtKeysIds[$oAttDef->GetTargetClass()] = array();
|
||||||
|
$aColumnsToLoad[] = $sAttCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieving IDs of all objects
|
||||||
|
// Note: We have to clone $oSet otherwise the source object will be modified
|
||||||
|
$oSet = new DBObjectSet($oSearch);
|
||||||
|
$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => $aColumnsToLoad));
|
||||||
|
while($oCurrentRow = $oSet->Fetch())
|
||||||
|
{
|
||||||
|
// Note: By presetting value to false, it is quicker to find which objects where not returned by the scope query later
|
||||||
|
$aObjectIds[$oCurrentRow->GetKey()] = false;
|
||||||
|
|
||||||
|
// Preparing ExtKeys to preload
|
||||||
|
foreach($aColumnsToLoad as $sAttCode)
|
||||||
|
{
|
||||||
|
$iExtKey = $oCurrentRow->Get($sAttCode);
|
||||||
|
if($iExtKey > 0)
|
||||||
|
{
|
||||||
|
/** @var \AttributeExternalKey $oAttDef */
|
||||||
|
$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
|
||||||
|
if(!in_array($iExtKey, $aExtKeysIds[$oAttDef->GetTargetClass()]))
|
||||||
|
{
|
||||||
|
$aExtKeysIds[$oAttDef->GetTargetClass()][] = $iExtKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(array(UR_ACTION_READ, UR_ACTION_MODIFY) as $sScopeAction)
|
||||||
|
{
|
||||||
|
// Retrieving scope query
|
||||||
|
/** @var DBSearch $oScopeQuery */
|
||||||
|
$oScopeQuery = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sObjectClass, $sScopeAction);
|
||||||
|
if($oScopeQuery !== null)
|
||||||
|
{
|
||||||
|
// Restricting scope if specified
|
||||||
|
if(!empty($aObjectIds))
|
||||||
|
{
|
||||||
|
$oScopeQuery->AddCondition('id', array_keys($aObjectIds), 'IN');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preparing object set
|
||||||
|
$oScopeSet = new DBObjectSet($oScopeQuery);
|
||||||
|
$oScopeSet->OptimizeColumnLoad(array());
|
||||||
|
|
||||||
|
// Checking objects status
|
||||||
|
$aScopeObjectIds = $aObjectIds;
|
||||||
|
while($oCurrentRow = $oScopeSet->Fetch())
|
||||||
|
{
|
||||||
|
$aScopeObjectIds[$oCurrentRow->GetKey()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating cache
|
||||||
|
if(!isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass]))
|
||||||
|
{
|
||||||
|
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = $aScopeObjectIds;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass] = array_merge_recursive(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass], $aScopeObjectIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preloading ExtKeys
|
||||||
|
foreach($aExtKeysIds as $sTargetClass => $aTargetIds)
|
||||||
|
{
|
||||||
|
if(!empty($aTargetIds))
|
||||||
|
{
|
||||||
|
$oTargetSearch = new DBObjectSearch($sTargetClass);
|
||||||
|
$oTargetSearch->AddCondition('id', $aTargetIds, 'IN');
|
||||||
|
|
||||||
|
static::PreloadForCache($oApp, $oTargetSearch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user