Back to Access class

Method getAssetRules

public static \Joomla\CMS\Access\Rules
getAssetRules
(mixed $assetKey, mixed $recursive = false, mixed $recursiveParentAsset = true, mixed $preload = true)
Method to return the Rules object for an asset. The returned object can optionally hold only the rules explicitly set for the asset or the summation of all inherited rules from parent assets and explicit rules.
Parameters
  • int|string $assetKey The asset key (asset id or asset name). null fallback to root asset.
  • bool $recursive True to return the rules object with inherited rules.
  • bool $recursiveParentAsset True to calculate the rule also based on inherited component/extension rules.
  • bool $preload Indicates whether preloading should be used.
Returns
  • \Joomla\CMS\Access\Rules Rules object for the asset.
Since
  • 1.7.0
-
  • The non preloading code will be removed in 4.0. All asset rules should use asset preloading.
Class: Access
Project: Joomla

Method getAssetRules - Source code

/**
 * Method to return the Rules object for an asset. The returned object can optionally hold
 * only the rules explicitly set for the asset or the summation of all inherited rules from
 * parent assets and explicit rules.
 *
 * @param   integer|string  $assetKey              The asset key (asset id or asset name). null fallback to root asset.
 * @param   boolean         $recursive             True to return the rules object with inherited rules.
 * @param   boolean         $recursiveParentAsset  True to calculate the rule also based on inherited component/extension rules.
 * @param   boolean         $preload               Indicates whether preloading should be used.
 *
 * @return  Rules  Rules object for the asset.
 *
 * @since   1.7.0
 * @note    The non preloading code will be removed in 4.0. All asset rules should use asset preloading.
 */
public static function getAssetRules($assetKey, $recursive = false, $recursiveParentAsset = true, $preload = true)
{
    // Auto preloads the components assets and root asset (if chosen).
    if ($preload) {
        self::preload('components');
    }
    // When asset key is null fallback to root asset.
    $assetKey = self::cleanAssetKey($assetKey);
    // Auto preloads assets for the asset type (if chosen).
    if ($preload) {
        self::preload(self::getAssetType($assetKey));
    }
    // Get the asset id and name.
    $assetId = self::getAssetId($assetKey);
    // If asset rules already cached em memory return it (only in full recursive mode).
    if ($recursive && $recursiveParentAsset && $assetId && isset(self::$assetRules[$assetId])) {
        return self::$assetRules[$assetId];
    }
    // Get the asset name and the extension name.
    $assetName = self::getAssetName($assetKey);
    $extensionName = self::getExtensionNameFromAsset($assetName);
    // If asset id does not exist fallback to extension asset, then root asset.
    if (!$assetId) {
        if ($extensionName && $assetName !== $extensionName) {
            Log::add('No asset found for ' . $assetName . ', falling back to ' . $extensionName, Log::WARNING, 'assets');
            return self::getAssetRules($extensionName, $recursive, $recursiveParentAsset, $preload);
        }
        if (self::$rootAssetId !== null && $assetName !== self::$preloadedAssets[self::$rootAssetId]) {
            Log::add('No asset found for ' . $assetName . ', falling back to ' . self::$preloadedAssets[self::$rootAssetId], Log::WARNING, 'assets');
            return self::getAssetRules(self::$preloadedAssets[self::$rootAssetId], $recursive, $recursiveParentAsset, $preload);
        }
    }
    // Almost all calls can take advantage of preloading.
    if ($assetId && isset(self::$preloadedAssets[$assetId])) {
        !JDEBUG ?: Profiler::getInstance('Application')->mark('Before Access::getAssetRules (id:' . $assetId . ' name:' . $assetName . ')');
        // Collects permissions for each asset
        $collected = array();
        // If not in any recursive mode. We only want the asset rules.
        if (!$recursive && !$recursiveParentAsset) {
            $collected = array(self::$assetPermissionsParentIdMapping[$extensionName][$assetId]->rules);
        } else {
            $ancestors = array_reverse(self::getAssetAncestors($extensionName, $assetId));
            foreach ($ancestors as $id) {
                // There are no rules for this ancestor
                if (!isset(self::$assetPermissionsParentIdMapping[$extensionName][$id])) {
                    continue;
                }
                // If full recursive mode, but not recursive parent mode, do not add the extension asset rules.
                if ($recursive && !$recursiveParentAsset && self::$assetPermissionsParentIdMapping[$extensionName][$id]->name === $extensionName) {
                    continue;
                }
                // If not full recursive mode, but recursive parent mode, do not add other recursion rules.
                if (!$recursive && $recursiveParentAsset && self::$assetPermissionsParentIdMapping[$extensionName][$id]->name !== $extensionName && (int) self::$assetPermissionsParentIdMapping[$extensionName][$id]->id !== $assetId) {
                    continue;
                }
                // If empty asset to not add to rules.
                if (self::$assetPermissionsParentIdMapping[$extensionName][$id]->rules === '{}') {
                    continue;
                }
                $collected[] = self::$assetPermissionsParentIdMapping[$extensionName][$id]->rules;
            }
        }
        /**
         * Hashing the collected rules allows us to store
         * only one instance of the Rules object for
         * Assets that have the same exact permissions...
         * it's a great way to save some memory.
         */
        $hash = md5(implode(',', $collected));
        if (!isset(self::$assetRulesIdentities[$hash])) {
            $rules = new Rules();
            $rules->mergeCollection($collected);
            self::$assetRulesIdentities[$hash] = $rules;
        }
        // Save asset rules to memory cache(only in full recursive mode).
        if ($recursive && $recursiveParentAsset) {
            self::$assetRules[$assetId] = self::$assetRulesIdentities[$hash];
        }
        !JDEBUG ?: Profiler::getInstance('Application')->mark('After Access::getAssetRules (id:' . $assetId . ' name:' . $assetName . ')');
        return self::$assetRulesIdentities[$hash];
    }
    // Non preloading code. Use old slower method, slower. Only used in rare cases (if any) or without preloading chosen.
    Log::add('Asset ' . $assetKey . ' permissions fetch without preloading (slower method).', Log::INFO, 'assets');
    !JDEBUG ?: Profiler::getInstance('Application')->mark('Before Access::getAssetRules (assetKey:' . $assetKey . ')');
    // There's no need to process it with the recursive method for the Root Asset ID.
    if ((int) $assetKey === 1) {
        $recursive = false;
    }
    // Get the database connection object.
    $db = Factory::getDbo();
    // Build the database query to get the rules for the asset.
    $query = $db->getQuery(true)->select($db->quoteName($recursive ? 'b.rules' : 'a.rules', 'rules'))->from($db->quoteName('#__assets', 'a'));
    // If the asset identifier is numeric assume it is a primary key, else lookup by name.
    if (is_numeric($assetKey)) {
        $query->where($db->quoteName('a.id') . ' = :asset', 'OR')->bind(':asset', $assetKey, ParameterType::INTEGER);
    } else {
        $query->where($db->quoteName('a.name') . ' = :asset', 'OR')->bind(':asset', $assetKey);
    }
    if ($recursiveParentAsset && ($extensionName !== $assetKey || is_numeric($assetKey))) {
        $query->where($db->quoteName('a.name') . ' = :extension')->bind(':extension', $extensionName);
    }
    // If we want the rules cascading up to the global asset node we need a self-join.
    if ($recursive) {
        $query->where($db->quoteName('a.parent_id') . ' = 0')->join('LEFT', $db->quoteName('#__assets', 'b'), $db->quoteName('b.lft') . ' <= ' . $db->quoteName('a.lft') . ' AND ' . $db->quoteName('b.rgt') . ' >= ' . $db->quoteName('a.rgt'))->order($db->quoteName('b.lft'));
    }
    // Execute the query and load the rules from the result.
    $result = $db->setQuery($query)->loadColumn();
    // Get the root even if the asset is not found and in recursive mode
    if (empty($result)) {
        $rootId = (new Asset($db))->getRootId();
        $query->clear()->select($db->quoteName('rules'))->from($db->quoteName('#__assets'))->where($db->quoteName('id') . ' = :rootId')->bind(':rootId', $rootId, ParameterType::INTEGER);
        $result = $db->setQuery($query)->loadColumn();
    }
    // Instantiate and return the Rules object for the asset rules.
    $rules = new Rules();
    $rules->mergeCollection($result);
    !JDEBUG ?: Profiler::getInstance('Application')->mark('Before Access::getAssetRules <strong>Slower</strong> (assetKey:' . $assetKey . ')');
    return $rules;
}