mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-17 06:18:44 +02:00
Portal: Performance optimization on ManageBrick
SVN:trunk[4718]
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace Combodo\iTop\Portal\Controller;
|
||||
|
||||
use Combodo\iTop\Portal\Helper\ScopeValidatorHelper;
|
||||
use \Silex\Application;
|
||||
use \Symfony\Component\HttpFoundation\Request;
|
||||
use \UserRights;
|
||||
@@ -267,8 +268,8 @@ class ManageBrickController extends BrickController
|
||||
}
|
||||
|
||||
// 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 : We now get view scope instead of edit scope as we allowed users to view/edit objects in the brick regarding their rights
|
||||
// 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
|
||||
$oScopeQuery = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $aGroupingAreasValue['value'], UR_ACTION_READ);
|
||||
if ($oScopeQuery !== null)
|
||||
{
|
||||
@@ -284,7 +285,7 @@ class ManageBrickController extends BrickController
|
||||
$oAreaQuery = null;
|
||||
}
|
||||
|
||||
$aQueries[$sKey] = $oAreaQuery;
|
||||
$aQueries[$sKey] = $oAreaQuery;
|
||||
}
|
||||
|
||||
// Testing appropriate data loading mode if we are in auto
|
||||
@@ -346,11 +347,12 @@ class ManageBrickController extends BrickController
|
||||
|
||||
$oSet->OptimizeColumnLoad($aColumnsToLoad);
|
||||
$oSet->SetOrderByClasses();
|
||||
SecurityHelper::PreloadForCache($oApp, $oSet->GetFilter(), $aColumnsToLoad[$oQuery->GetClassAlias()] /* preloading only extkeys from the main class */);
|
||||
$aSets[$sKey] = $oSet;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieving and preparing datas for rendering
|
||||
// Retrieving and preparing data for rendering
|
||||
$aGroupingAreasData = array();
|
||||
foreach ($aSets as $sKey => $oSet)
|
||||
{
|
||||
@@ -373,6 +375,7 @@ class ManageBrickController extends BrickController
|
||||
|
||||
// Getting items
|
||||
$aItems = array();
|
||||
$aItemsIds = array();
|
||||
// ... For each item
|
||||
/** @var DBObject $oCurrentRow */
|
||||
while ($oCurrentRow = $oSet->Fetch())
|
||||
@@ -457,8 +460,18 @@ class ManageBrickController extends BrickController
|
||||
'attributes' => $aItemAttrs,
|
||||
'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(
|
||||
'sId' => $sKey,
|
||||
'sTitle' => $aGroupingAreasValues[$sKey]['label'],
|
||||
|
||||
@@ -26,6 +26,8 @@ use \UserRights;
|
||||
use \Dict;
|
||||
use \IssueLog;
|
||||
use \MetaModel;
|
||||
use \DBSearch;
|
||||
use \DBObjectSearch;
|
||||
use \DBObjectSet;
|
||||
use \FieldExpression;
|
||||
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)
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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