User tests: Successful: Unsuccessful:
This is a first approach to namespace com_content with the current architecture. It is fully BC and will support extensions running on J3 with none namespaced classes.
On the back end, com_content has the following namespace, according to the document from Odense:
Joomla\Component\Content\Admin
The single entry file administrator/components/com_content/content.php was deleted and replaced with a dispatcher file. The dispatcher itself was changed to load the correct controller according to the task, like that the JControllerLegacy::getInstance()
function is only used when the component has the legacy set up.
All controllers are in the Controller folder and are the same classes as in the none namespaced version. The only exception is the ContentController
which has now the name Content
.
The models are moved files from the models
folder to Model
.
The tables are moved files from the tables
folder to Table
. Additionally there is a new table Article
which extends from JTableContent
because I think JTableContent
should not exist and on a later stage being moved to Joomla\Component\Content\Admin\Table\Article
.
Every view does have it's own namespace and for every format there is a single class. This is again according to the decisions from Odense.
Fields, forms and layout files are moved to the resources folders. Like that we have a clear separation between classes and resources. I was unsure if fields should get also their own namespace or if it should be treated as a resource, so I put them into resources.
This will be done in a new pr as not everybody agrees with that approach.
As something is resetting the namespace value in the extensions table you need to manually run the following query after installation:
UPDATE `sites_cms`.`j_extensions` SET `namespace` = 'Joomla\\Component\\Content' WHERE `j_extensions`.`extension_id` =22;
@mbabker any clue what?
Open Content -> Articles in the back end and play around with it.
Same behavior as with the none namespaced ones.
Status | New | ⇒ | Pending |
Category | ⇒ | Administration com_content |
Did you test it against the Joomla 4 branch?
No, haven't noticed its about 4.
Title |
|
Did you perhaps consider using aliases in some compat layer?
class_alias('Joomla\Component\Content\Admin\Controller\Article', 'ContentControllerArticle');
If they are needed, then for sure we will add them to the classmap file.
I'm asking because 3p extensions like modules similar to mod_article_latest may be using com_content classes
Since I work on a similar thing in PR #14258, I would like to make a comparison between the two PRs (only related to MVC layer only) base on a quick look at your PR code:
The code of method createModel (and createView) is coupled with the current controller namespace, so it is not possible to get a backend model from frontend controller and vice versa . You also assume that the namespace model and view class always exist (it is just RFC, I know)
In some place, you need to run code to get the component name. I think we can safely store $option as a property of the controller - get from controller input - and pass it to model, view while creating, that would help detecting the component easier.
Just a minor thing, your structure requires change to the JComponentHelper to support two kinds of component end point file:
With my propose, no change needed to JComponentHelper. We still have one file content.php with this code
(new Joomla\Cms\Dispatcher\Dispatcher())->dispatch();
To be more clear, my only concern is whether we want to support HMVC in our namespace MVC or not. If not, this PR is fine (some minor things can be addressed easily) and I will stop working on what I am working on.
Your PR doesn't prepare for HMVC support
That doesn't belong as part of this PR. This is simply working out details for component class namespacing.
createModel
function in your controller. What can be changed is to use the second parameter as client. This would mean then that in namespaced context it defines if the model from site or admin should be loaded.Also, it will help we develop everything inside component, the module is actually show a view in a component, like this https://github.com/akeeba/akeebasubs/blob/development/modules/site/akmysubs/mod_akmysubs.php#L41
$model = $this->getModel('article', '\Joomla\Component\Admin\Model')
article is name of model, while \Joomla\Component\Admin\Model is considered as prefix in getModel method of the controller
As I said, just a minor thing
I haven't developed anything using symfony, just concern about how people will create template override for components.
$model = $this->getModel('Article', 'Site');
.#1. The approach in #13684 seems doesn't get positive feedback, I can see at least two developers disagree with it. Also, for HMVC support, I think @wilsonge supports it, see his comment #14258 (comment) (item 2 in the comment)
#2. That would work, too.
#3. I know. It is just where to find the original layout to create override. Right now, we support two places:
views/ViewName/tmpl
View/ViewName/tmpl
With your resources folder, we will end of with third location (and it is still correct that you will need to edit Template Manager code to support your new location)
One of the problems in #13684 IMO is that it basically turns a view agnostic JViewLegacy
into an HTML first view class. We actually need to subclass it and have format specific subclasses (similar to https://github.com/joomla-framework/view/tree/2.0-dev/src). It's not so much the approach is bad, but architecturally it's yet another move toward the CMS being so heavily HTML first (only) that it identifies a need to rethink things.
So just talking about right now, this PR as is and what is currently merged into 3.8/4.0, for me we're still missing some autowiring stuff.
Anyone using a component still has to know its internals (namespaces, file paths, etc.) and still manually register stuff into the system for it to be used. Somehow I'd like to see things evolve in a way where a component's internals just automagically get autowired (think a FOF3 component when you fetch its container and how part of that process handles the autoloader configurations).
I know there's going to be at least one response that's going to be "well, that's the job of the dispatcher". I don't see the dispatcher having that much responsibility when it comes to components, that seems like we're cramming too much responsibility into the dispatcher class (think SRP, the name to me implies that the dispatcher's role is to dispatch a component task, it shouldn't get too complex with too many responsibilities; classes are cheap). I'd still like to be able to direct load and use a component's model in a module if desired versus the code being forced to use a dispatcher to perform a task or even instantiate a dummy dispatcher just to do the wiring.
I'm about to go do some other work, but wanted to throw that thought out there. It's probably out of scope for this PR as is but it is definitely an issue that's going to need to be addressed.
component's internals just automagically get autowired
That would be nice, but not by loading from the database or by parsing a manifest file.
What's wrong with either of those? We already load component extension records into memory on every request, so at worst we're adding some additional load onto that query and the resulting cache data.
I'm just not a fan of loading more than what is needed. If a cache gets created somehow which contains all the namespaces, then I'm fine with that. But loading all extensions from the database or parsing all manifest files on every page request is for me too much load and not acceptable.
Well, through a request cycle the parameters for several components end up getting used, so we're already loading all components into memory in JComponentHelper
and caching that query result since the method gets hit on every request (off hand the system includes lookups for the guest user group from com_users
and the default language from com_languages
, I'm not sure if there are other components that have "global" configuration options like that).
Plugins have a similar query loader and the result is cached by a key generated based on the active user's groups (since that would affect what plugins are loaded/triggered during a request cycle).
JModuleHelper
also has a cache for the module list query, though that one has some additional filters for each request (i.e. the active menu item, user groups, publish up/down, etc.).
So, a good chunk of the #__extensions
and #__modules
tables are already getting read into memory during a request cycle, and cached when that is enabled so it's persisting.
Also, we don't HAVE to read all the data into memory immediately. As much of the system that can be lazy loaded should be, including lazy conversion of parameters to Registry
instances as I've done with a couple parts of the API. If the dispatcher were used to do all this automagic stuff, the namespaces should only be added to the autoloader when something explicitly requests it. If that data source were the component manifest, or a separate configuration file similar to FOF, that would be the point the source is processed (granted if the source were the manifest, we're already creating a cache of that in the database, so we would just include that in the query result (and inherently cache) for at least the component and plugin helpers and it would just be another property on the resulting objects).
I don't think we can get to a point where Joomla can create a dynamic configuration source like the compiled appProdProjectContainer.php
in Symfony projects. But that would be another optimal option that has all the mapping info (this would equate to the %kernel.bundles_metadata%
parameter in the container that has the bundle name, namespace, filesystem path, and if it has a parent).
If that's really the case that all extensions do get loaded anyway, then it can probably work out to have the name in the database.
For me it is important to have an agreement on the structure of a namespaced extension. If we can agree that this is the case with this PR. Then I would like to get it merged. From there I can start a PR autoloading the namespaces from the database, otherwise this one will get too big.
If the decision is just for structure of a namespace a component, I agree with most of what you did here. To me, there are few items left and the Joomla 4 team will have to make decision:
Then we can get testers to test it. If it works, it can be merged so that you can namespace frontend part of the component (and other components).
The technical discussion of whole MVC layer, not sure when we have a final decision and it could hold the namespace effort back.
@joomdonation All things that needs to be discussed, but let's do one step after another. We have the akward habit to rush things in without a greater concept, so better to have multiple iterations than one big "final" step.
For the code in controller which create View and Model object, you assume that these classes always exists
Why? I think I haven't done something special in that PR which should force them? If this is the case, then it should be removed.
Whether we need to introduce resources folder or still keep these items inside Model and View folder like before
If you're familiar with Symfony bundles, you know that they use a Resources folder as a location to store all sorts of miscellaneous files (translations, service configurations, validator configurations, Doctrine entity mappings, and views (our layouts)). From that aspect, I think it'd be better to start consolidating "random" things into one spot. It seems like a better convention to keep the PHP class files in one path and not continue to spread miscellaneous files all throughout the system by grouping them into one path.
Labels |
Added:
?
|
@joomdonation added checks if the class do exist. On the second commit I'v changed the code to consider the prefix, which can be either Site or Admin.
@mbabker so you agree with the resources folder approach or not? Sorry but your last sentence was for me as a none native English speaking person just not understandable.
Yes we should do it. Seems better to put all the resources into one resources folder than spread them all over a component.
What about the rest, some feedback about them?
@laoneo Just a very quick look at your new code, I am afraid of it still not correct;
In case model doesn't exists, you should return false instead of return null. That's because the getModel method in controller expect to receive a Model object or Boolean value
The createModel method is now support getting both from frontend and backend model. Unfortunately, with your dispatcher code (have to read the JLoader::registerNamespace method to confirm), you only register the current path (JPATH_COMPONENT), so I guess in frontend, you cannot load a model from backend and vice versa. To be more clear, when you are in frontend, the backend path is not registered with auto-loader, so backend model could class is not auto-loaded
The code for getting frontend and backend namespace looks abit long and difficult to read to me. Would it be better if we calculate base namespace of the component (Joomla\Component\Content in this case), store it as a property of the class. Then getting frontend and backend namespace of model would be easier:
$this->namespace.'\Admin\Model\' or $this->namespace.'\Site\Model\'
That's the approach I use on my PR, see the code https://github.com/joomdonation/joomla-cms/blob/4295a3c310f8b9b41856d2c495621a095a3c4809/libraries/src/Cms/Controller/Controller.php#L1230-L1249
Honestly I don't see a reason to put the namespace as prefix, I mean then you can create the instance directly instead of creating the model trough another function.
Honestly I don't see a reason to put the namespace as prefix, I mean then you can create the instance directly instead of creating the model trough another function.
I was thinking about different thing (wrong BTW). Also, look at the current implementation, I even not sure if we should support Site/Admin as the prefix because as you said, we can create model class directly when needed. We will wait for feedback from others.
More and more I think the same, we should create the model instances directly in the code and not trough the createModel function. Then it is typed and makes the code more readable. When all classes are loaded anyway.
The view_list property in Admin controller is also not being detected properly. After publishing an article, we are being redirected to administrator/index.php?option=com_content&view=\articles (note the backslash before article).
Only found two issues which I just reported while doing quick test today
Fixed the two errors.
@wilsonge should we not merge this one that @joomdonation can work out his pr's on a live example? I guess we all agree on the set up, if this one get merged then we can switch focus to the Dispatcher and MVC issues. Like that it will be easier to understand how the changes by @joomdonation should work.
Will do when it will be merged, otherwise I have to do that multiple times.
@joomdonation is taking over the namespacing part so I'm out.
Status | Pending | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2017-04-07 07:24:17 |
Closed_By | ⇒ | laoneo |
Status | Closed | ⇒ | New |
Closed_Date | 2017-04-07 07:24:17 | ⇒ | |
Closed_By | laoneo | ⇒ |
Status | New | ⇒ | Pending |
Category | Administration com_content | ⇒ | Administration com_content Modules Libraries |
I made some changes that the factory, app and input are passed to the parent controllers.
I installed a copy of https://github.com/digital-Peak/joomla-cms/tree/j4/namespace/component/content , and there are some errors;
Look like there is no changed to extensions to set namespace data for com_content yet
I inserted the data manually to that table. Then for some reasons, cpanel still broken Fatal error: Class 'Joomla\Component\Content\Administrator\Helper\ContentHelper' not found in E:\www\namespacecontent\administrator\components\com_content\helpers\content.php on line 19
I tried to access to http://localhost/namespacecontent/administrator/index.php?option=com_content and saw error 500 - An error has occurred.
Layout default not found.
Return to Control Panel
Look like it doesn't work yet (or there is error from my end). Could you please check?
In frontend, we are having errors, too.
Fatal error: Class 'Joomla\Component\Content\Administrator\Helper\ContentHelper' not found in E:\www\namespacecontent\administrator\components\com_content\helpers\content.php on line 19
1 0.0191 364168 {main}( ) ...\index.php:0
2 0.0292 370120 require_once( 'E:\www\namespacecontent\includes\app.php' ) ...\index.php:30
3 0.3974 3024424 Joomla\CMS\Application\CmsApplication->execute( ) ...\app.php:35
4 0.7428 4753320 Joomla\CMS\Application\SiteApplication->doExecute( ) ...\CmsApplication.php:393
5 0.8803 5621680 Joomla\CMS\Application\SiteApplication->dispatch( ) ...\SiteApplication.php:233
6 0.9671 5857848 Joomla\CMS\Component\ComponentHelper::renderComponent( ) ...\SiteApplication.php:194
7 0.9722 5864112 Joomla\CMS\Component\ComponentHelper::executeComponent( ) ...\ComponentHelper.php:398
8 0.9759 5893640 require_once( 'E:\www\namespacecontent\components\com_content\content.php' ) ...\ComponentHelper.php:424
9 1.0092 6120880 Joomla\CMS\Controller\Controller->execute( ) ...\content.php:39
10 1.0092 6120880 ContentController->display( ) ...\Controller.php:710
11 1.4061 6801232 Joomla\CMS\Controller\Controller->display( ) ...\controller.php:113
12 1.4363 6943704 ContentViewArticle->display( ) ...\Controller.php:672
13 1.6681 7753024 Joomla\CMS\Application\WebApplication->triggerEvent( ) ...\view.html.php:221
14 1.6682 7753104 Joomla\Event\Dispatcher->dispatch( ) ...\EventAware.php:109
15 1.6686 7753576 call_user_func:{E:\www\namespacecontent\libraries\vendor\joomla\event\src\Dispatcher.php:402} ( ) ...\Dispatcher.php:402
16 1.6686 7753576 JPlugin->{closure:E:\www\namespacecontent\libraries\cms\plugin\plugin.php:287-341}( ) ...\Dispatcher.php:402
17 1.6687 7753896 PlgSystemFields->onContentPrepare( ) ...\plugin.php:328
18 1.6724 7854880 FieldsHelper::extract( ) ...\fields.php:363
19 1.6736 7855552 class_exists ( ) ...\fields.php:55
20 1.6736 7855584 spl_autoload_call ( ) ...\fields.php:55
21 1.6739 7855648 JLoader::load( ) ...\fields.php:55
22 1.6749 7857704 include_once( 'E:\www\namespacecontent\administrator\components\com_content\helpers\content.php' )
The helper file is using in frontend, and would require registering auto-loader properly. That is one of the reason I didn't want to namespace the helper class while working on com_banners
Another thing is about location of layout fields and form fields class, form xmls. Since we don't have final decision about using resources folder yet, to avoid having more folders than we actually, I thnk:
Form XMLs and form fields, rules should be inside Model folder
View layout files should be inside View folder
Right now, you have it inside models and views folders and result in two extra folders than we need
Note that I tested this using Windows, case-sensitive folder name, views and Views for example, is different. Look like that's the reason causing layout not found error. I also installed sample data for easier testing
Category | Administration com_content Modules Libraries | ⇒ | Administration com_content Modules SQL Installation Libraries |
Title |
|
Status | Pending | ⇒ | Fixed in Code Base |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2017-04-11 09:06:49 |
Closed_By | ⇒ | wilsonge |
open Article, got:
After deinstalling PR and clear Cache got: