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.lft
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.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.lft
The 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 #__assets rows |
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_content component asset |
First fallback to category, if not exists then fallback to com_content component asset |
Check ACL Permission (categories, articles, general) before and after patch.
Joomla should work as before.
Access
classStatus | 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?