|
@@ -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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|