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.
 *
 * @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;
}