User tests: Successful: Unsuccessful:
Joomla\CMS\Access\Access then this PR should be B/C.Joomla\CMS\Access\AccessControl as a replacement for Joomla\CMS\Access\Access.I would like to do it in similar way as modern router, but
only developers of 3rd party extension will decide which way want to go.
In this part I have not decided yet, I do not know if I'm doing it right.
You can still use Access class as before, but protected methods/variables may be missing.
Most 3rd party extensions, which does not use advanced access managements shouldn't see any difference.
This Access methods are proxy to the new methods in AccessControl, there are slight differences:
getGroupsByUser() - the new method returns items in reverse ordergetAuthorisedViewLevels() - the new method returns array_combine($oldResult, $oldResult), it means that you get levels in the keys and values of the array.getActionsFromFile() - only a proxy to the same codegetActionsFromData() - only a proxy to the same codepreloadComponents() - acts as a proxy but fills in its own protected variables, will use more memorycheckGroup() - acts as a proxy, cleans input data, AccessControl::checkGroup does not.The next methods are totally rewritten in the new AccessControl class, has different parameters, use a new structure of data, get less memory:
check()getAssetRules()To not duplicate memory consumption I suggest to use only new methods in all extensions.
There is a new method in Joomla\CMS\User:
public function isAuthorised($action, $assetKey = null, $extension = null, $nested = true)
and the old method looks like:
public function authorise($action, $assetname = null)
{
        return $this->isAuthorised($action, $assetname);
}The new method has a few more arguments to be more flexible.
The $extension argument (ex. com_content) is used as a fallback if $assetKey (asset_id) does not exist.
The $nested is used to optimization, for example modules always has level 1. Then we can always set $nested = false to generate simpler sql query.
Instead of load from database single row or all rows that match name LIKE 'com_content.%'
this PR use UNION and LEFT JOIN statement to emulate WITH RECURSIVE , example:
SELECT a5.id, a5.name, a5.rules, a5.parent_id, a5.level
FROM `j40_assets` AS `a0`
LEFT JOIN `j40_assets` AS `a1` ON a1.id = a0.parent_id AND a1.id != 1
LEFT JOIN `j40_assets` AS `a2` ON a2.id = a1.parent_id AND a2.id != 1
LEFT JOIN `j40_assets` AS `a3` ON a3.id = a2.parent_id AND a3.id != 1
LEFT JOIN `j40_assets` AS `a4` ON a4.id = a3.parent_id AND a4.id != 1
LEFT JOIN `j40_assets` AS `a5` ON a5.id IN (a0.id, a1.id, a2.id, a3.id, a4.id, a4.parent_id)
WHERE a0.id = 78
ORDER BY a5.lftResult:
id	name	rules	parent_id	level
8	com_content	{"core.admin":{"7":1},"core.manage":{"6":1},"core.create":{"3":1},"core.edit":{"4":1},"core.edit.state":{"5":1},"core.execute.transition":{"6":1,"5":1}}	1	1
74	com_content.category.8	{}	8	2
78	com_content.article.3	{}	74	3
For this example the nested variable can be set even to 2 (article->category), but by default is 5.
If assets are more nested then joomla will check whether parent_id has been loaded and if not then generates the next query
based on level depth to load the rest of missing parents.
For category view to load all article assets joomla will use:
SELECT b.id, b.name, b.rules, b.parent_id, b.level
FROM (
SELECT a5.id
FROM `j40_assets` AS `a0`
LEFT JOIN `j40_assets` AS `a1` ON a1.id = a0.parent_id AND a1.id != 1
LEFT JOIN `j40_assets` AS `a2` ON a2.id = a1.parent_id AND a2.id != 1
LEFT JOIN `j40_assets` AS `a3` ON a3.id = a2.parent_id AND a3.id != 1
LEFT JOIN `j40_assets` AS `a4` ON a4.id = a3.parent_id AND a4.id != 1
LEFT JOIN `j40_assets` AS `a5` ON a5.id IN (a0.id, a1.id, a2.id, a3.id, a4.id, a4.parent_id)
WHERE a0.id = 78
UNION (
SELECT a5.id
FROM `j40_assets` AS `a0`
LEFT JOIN `j40_assets` AS `a1` ON a1.id = a0.parent_id AND a1.id != 1
LEFT JOIN `j40_assets` AS `a2` ON a2.id = a1.parent_id AND a2.id != 1
LEFT JOIN `j40_assets` AS `a3` ON a3.id = a2.parent_id AND a3.id != 1
LEFT JOIN `j40_assets` AS `a4` ON a4.id = a3.parent_id AND a4.id != 1
LEFT JOIN `j40_assets` AS `a5` ON a5.id IN (a0.id, a1.id, a2.id, a3.id, a4.id, a4.parent_id)
WHERE a0.id = 79)
UNION (
SELECT a5.id
FROM `j40_assets` AS `a0`
LEFT JOIN `j40_assets` AS `a1` ON a1.id = a0.parent_id AND a1.id != 1
LEFT JOIN `j40_assets` AS `a2` ON a2.id = a1.parent_id AND a2.id != 1
LEFT JOIN `j40_assets` AS `a3` ON a3.id = a2.parent_id AND a3.id != 1
LEFT JOIN `j40_assets` AS `a4` ON a4.id = a3.parent_id AND a4.id != 1
LEFT JOIN `j40_assets` AS `a5` ON a5.id IN (a0.id, a1.id, a2.id, a3.id, a4.id, a4.parent_id)
WHERE a0.id = 80)
UNION (
SELECT a5.id
FROM `j40_assets` AS `a0`
LEFT JOIN `j40_assets` AS `a1` ON a1.id = a0.parent_id AND a1.id != 1
LEFT JOIN `j40_assets` AS `a2` ON a2.id = a1.parent_id AND a2.id != 1
LEFT JOIN `j40_assets` AS `a3` ON a3.id = a2.parent_id AND a3.id != 1
LEFT JOIN `j40_assets` AS `a4` ON a4.id = a3.parent_id AND a4.id != 1
LEFT JOIN `j40_assets` AS `a5` ON a5.id IN (a0.id, a1.id, a2.id, a3.id, a4.id, a4.parent_id)
WHERE a0.id = 81)) AS pks
LEFT JOIN `j40_assets` AS `b` ON b.id = pks.id
ORDER BY b.lftThe query will only load assets that are required for articles.
The result:
id 	name 	rules 	parent_id 	level
8	com_content	{"core.admin":{"7":1},"core.manage":{"6":1},"core.create":{"3":1},"core.edit":{"4":1},"core.edit.sta...	1	1
74	com_content.category.8	{}	8	2
78	com_content.article.3	{}	74	3
79	com_content.article.4	{}	74	3
80	com_content.article.5	{}	74	3
81	com_content.article.6	{}	74	3
Below table describes situation when you are logged (as not Super User).
| Available Action | Supported by Access | Supported by AccessControl | 
|---|---|---|
| Preload components | Yes | Yes | 
| Preload all assets per component | Yes | No | 
| Preload only specified asset rules, ex. for 'com_content.article.1' | No. Always preload all assets per component, ex: ... WHERE name LIKE 'com_content.%'. It takes a lots of memory. | Only load asset of article and parent assets (in one query) | 
| Preload only assets for modules on visited page | No. Load all asset rows. May take a lot of memory if you have a lot of modules in database | Only preload selected assets (in one query) | 
| Preload only assets for articles in category view | No. Only preload all assets per component. | Preload only assets for selected articles and its parents. Can preload it in one query using UNION sql statement. | 
| Number of sql queries | Low ( Components+com_content.%+com_modules.%= 3 queries) | In the worse case one per asset but we can use preload to load a few assets in one sql query. ( Components+only required component items assets+only active modules= 3 queries | 
| Total loaded #__assetsrows | Very high | Low (preload components + only required rows) | 
| Memory usage | Very High | Low | 
| Speed of queries | Slow because of load a big amount of rows | Quite fast | 
| Allows for custom preload | No | Yes - you can put a list of asset name or asset id to preload. E. g. foreach ($assets as $id) $acl->addAssetIdToPreload($id) | 
| Article asset fallback | Only directly to com_contentcomponent asset | First fallback to category, if not exists then fallback to com_contentcomponent asset | 
Check ACL Permission (categories, articles, general) before and after patch.
Joomla should work as before.
Access class| Status | New | ⇒ | Pending | 
| Category | ⇒ | Administration com_categories com_content com_modules Modules Front End Libraries Plugins | 
| Labels | Added: 
? | ||
 
                 
                I will update it soon. Maybe next week.
| Title | 
 | ||||||
 
                It is not active due to lack of time.
| Status | Pending | ⇒ | Closed | 
| Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2019-05-05 19:12:52 | 
| Closed_By | ⇒ | csthomas | |
| Labels | Removed: 
J4 Issue | ||
is this still an active wip?