? ? ? Pending

User tests: Successful: Unsuccessful:

avatar laoneo
laoneo
21 Mar 2017

Summary of Changes

A task on the roadmap of Joomla 4 is to namespace the libraries and extensions in the core. This move is complicated as we don't want to break all extensions and make a very hard BC break in J4.

A target should be to make the transition for the core and the extension developers as painless as possible. The most important point is that the extension developers are not forced to develop their extensions from scratch or have to maintain two code bases for J3 and J4.

The approach

The approach is to namespace the classes in the libraries/joomla and libraries/cms folder like in this pr #14155 and to create an alias for the none namespaced class in a classmap file. For example JModelList can still be used but it is proxied to Joomla\Cms\Model\ListModel. It is planed to do that for 3.8, that the extension developers can use the same code base for their extensions in the Joomla 3 series and in Joomla 4.
At the same time we will carry on the none namespaced aliases to J4, which means that any none namespaced extension will run on J4.

What's the problem?

JLoader, which is the Joomla class loader, has a little feature which does allow to override core classes. More details about that topic can be found here. This is problematic for the move to namespaces. As we have now a different name for a class.

If an extension is overriding JModelList, then it would mean we can't change any code in core of Joomla 3.8 to use Joomla\Cms\Model\ListModel. It is also not possible for any extension to run namespaced in 3.8, otherwise it would not be compatible with extensions which do overrides core classes. This will end up that the extension dev (if wants to use the same code base) needs to use the none namespaced version also in Joomla 4. But then it is again not compatible with the extensions which do override the namespaced core classes in J4.

If we say, ok, then lets just make it possible to override the namespaced version only, we are breaking BC for 3.8.

The solution

The class loader needs to be able to handle overrides for aliases. Assume an extension is overriding JModelList. If the code or an extension uses the class JModelList or Joomla\Cms\Model\ListModel, then in both cases the override of JModelList needs to be used. The same goes when an override is registered for Joomla\Cms\Model\ListModel. Then code which is using JModelList or Joomla\Cms\Model\ListModel in core or an extension must use the namespaced override class.

Example

I'v prepared an override plugin in a test repo which does override the list model classes. Basically it does:

public function onAfterInitialise()
{
	JLoader::register('JModelList', __DIR__ . '/NoneNsListModel.php');
	JLoader::register('Joomla\\Cms\\Model\\ListModel', __DIR__ . '/NsListModel.php');
}

It can be downloaded from here. If you install and activate that plugin on the 3.8 branch with this patch, then you should see a message which shows that the none namespaced override is called on every list model in the back end
image

If you do the changes from the test instructions in the file components/com_content/models/articles.php to use the namespaced list model, then you should see the following message when you go to Content -> Articles
image

The plugin has settings which do allow to control if the namespaced or none namespaced override should be registered.
image

THIS PLUGIN IS ONLY FOR DEMONSTRATION PURPOSES.

What is done in this pr?

  • When an override is done for an alias, then it is detected and correctly loaded.
  • Unit tests for the override behavior for case 1 and case 2 in the testing instructions below.
  • The Joomla namespace /libraries/src is loaded trough JLoaderand not anymore trough composer. Like that we keep the two worlds separated. Composer is managing the external libraries (vendor dir) while JLoader is managing the core classes. So we don't have to introduce class overriding in composer.
  • A bug is fixed in the JLoader::load() function where an if check never returns true because it makes no sense to do a test on a lower case class name.
  • Duplicate code is unified in a new function JLoader::stripFirstBackslash().

Testing Instructions

Case 1

Set Override JModelList to yes and Override Joomla\CMS\Model\ListModel to yes.

Case 2

Set Override JModelList to no and Override Joomla\CMS\Model\ListModel to yes.

Case 3

Set Override JModelList to yes and Override Joomla\CMS\Model\ListModel to no.

Case 4

Set Override JModelList to no and Override Joomla\CMS\Model\ListModel to no.

Expected result

Case 1

On every list in the back end the green message box should be displayed except on the articles list the yellow box for the ContentModelArticles should be displayed.

Case 2

On every list in the back end the yellow message box should be displayed.

Case 3

On every list in the back end the green message box should be displayed.

Case 4

No override message box should be displayed.

Actual result

Case 1

On every list in the back end the green message box should be displayed except on the articles list, there no box should be displayed.

Case 2

On every list in the back end no message box should be displayed.

Case 3

On every list in the back end the green message box should be displayed except on the articles list, there no box should be displayed.

Case 4

No override message box should be displayed.

Deprecation

This changes are basically needed for Joomla 3.8. If we want to support only overrides for the namespaced version, we can then revert back some changes in Joomla 4.

If we want to completely get rid of overriding core classes, then we can deprecate it right now in JLoader and remove the code in Joomla 5 at earliest then.

Performance

There is a minimal performance loss in the composer classloader wrapper, as an extra lookup is made to detect if an override exists in JLoader for a namespaced class.

Warning

This pr should not encourage people to do class overrides as it is NOT the right approach to hook itself into the core!! It just deals with a feature which interferes with the transition to namespaces.

avatar laoneo laoneo - open - 21 Mar 2017
avatar laoneo laoneo - change - 21 Mar 2017
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 21 Mar 2017
Category Libraries
avatar laoneo laoneo - change - 21 Mar 2017
The description was changed
avatar laoneo laoneo - edited - 21 Mar 2017
avatar laoneo laoneo - change - 21 Mar 2017
The description was changed
avatar laoneo laoneo - edited - 21 Mar 2017
avatar yvesh
yvesh - comment - 21 Mar 2017

One general question: Are we doing any single class loading in 4? or are we going to use the composer autoloader on the whole folder?

avatar laoneo
laoneo - comment - 21 Mar 2017

As for the current set up composer does load the whole folder https://github.com/joomla/joomla-cms/blob/3.8-dev/composer.json#L22. Why?

avatar dgt41
dgt41 - comment - 21 Mar 2017

Lazy loading, from a dev's perspective ;)

avatar yvesh
yvesh - comment - 21 Mar 2017

Because do we need JLoader than any longer? And @dgt41 this is implied :P

avatar laoneo
laoneo - comment - 21 Mar 2017

Now I get it. Don't know if composer offers that alias support.

avatar yvesh
yvesh - comment - 21 Mar 2017

Not sure either, overriding is a bit against some principles (extend not override SOLID (the o)), so there is probably no easy way

What you can do definitely is namespace overriding.. But this is not always just one class :-/

https://getcomposer.org/apidoc/1.0.0/Composer/Autoload/ClassLoader.html

avatar laoneo laoneo - change - 22 Mar 2017
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - change - 22 Mar 2017
Category Libraries Libraries External Library
avatar laoneo laoneo - change - 22 Mar 2017
Labels Added: ?
avatar laoneo laoneo - edited - 22 Mar 2017
avatar laoneo
laoneo - comment - 22 Mar 2017

Changed the pr the way, that the Joomla namespace in src is loaded trough JLoader and not anymore trough composer. So we don't have to introduce class overriding in composer. I would like to have the worlds separated. Composer is managing the external dependencies (vendor dir) and JLoader the core. I think it can be dangerous when we start to replace JLoader trough composer. I try to avoid another vendor lock in.
As when in 5 years the next new kick ass classloader dependency manager comes out we don't have to take care about BC when we want to replace composer then, as it is not exposed to the core.

933366f 22 Mar 2017 avatar laoneo CS
avatar laoneo laoneo - change - 22 Mar 2017
The description was changed
avatar joomla-cms-bot joomla-cms-bot - change - 22 Mar 2017
Category Libraries External Library External Library Libraries Unit Tests
avatar laoneo laoneo - change - 22 Mar 2017
The description was changed
avatar laoneo laoneo - edited - 22 Mar 2017
avatar wilsonge wilsonge - change - 27 Mar 2017
Labels Added: ?
avatar wilsonge wilsonge - change - 27 Mar 2017
Status Pending Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2017-03-27 08:25:17
Closed_By wilsonge
avatar wilsonge wilsonge - close - 27 Mar 2017
avatar wilsonge wilsonge - merge - 27 Mar 2017
avatar wilsonge
wilsonge - comment - 27 Mar 2017

Thanks for being patient with this. i know I've held you up on this for nearly two weeks!

Add a Comment

Login with GitHub to post a comment