JRenderer - phproberto/joomla-cms GitHub Wiki
This is a proof of concept of the changes to be done (or not) in the joomla rendering system.
This branch includes the JLayout
improvements/fixes that I had already proposed for Joomla for v3.5 but also starts a new discussion about which is the best way to go for the joomla rendering.
If you want to see all the changes you can check the jlayout-3.5 branch
New features
Here I will describe the new features that I have included in the rendering system. Most of them are inside the new JRendererAdapterLayout but I have also backported them to JLayout just in case we decide to keep the original plan.
Renamed includePaths to searchPaths
I think this describes better what information the property stores.
Add data as you build it
Sometimes it's better to add data for the layout as you receive it. I don't recommend it for most cases but I can see the benefits. Sample use:
$renderer->set('myvar', $myValue);
Then if after that call you use something like:
$renderer->render('joomla.layout', $additionalData);
Any previously assigned data is still there in the layout.
Suffixes support
Now you can use prefixes for your file searches. With something like:
$renderer->setSuffixes(array('bs2', 'bs3'))
->render('joomla.layout', $data);
It will search for layouts in this order:
joomla.layout.bs2.php
joomla.layout.bs3.php
joomla.layout.php
I have also replaced the way to remove suffixes from my first proposal from:
$renderer->setSuffixes('none');
with:
$renderer->clearSuffixes();
I have added the automatic suffixes for versions and languages but changed the way they have to be used from:
$renderer->setSuffixes('autoversion');
$renderer->setSuffixes('autolanguage');
To:
$renderer->loadVersionSuffixes();
$renderer->loadLanguageSuffixes();
Prefixes support
As in my original proposal I have added prefixes support. Using something like:
$prefixes->setPrefixes(array('bootstrap3'))
->render('joomla.layout', $data);
will search for:
bootstrap3/joomla/layout.php
joomla/layouts.php
Chainable methods
In both JLayout
and JRenderAdapterLayout
methods that can be chainable are so. So you can do something like:
echo $renderer->set('myVar', $myValue)
->setSearchPaths($mySearchPaths)
->loadVersionSuffixes()
->render('joomla.layout', $data);
Suffixes support
- In JRenderer the debug mode is not a parameter anymore. If you want to debug a layout you use:
$renderer->debug('joomla.layout', $data)
instead of the old:
$renderer->render('joomla.layout', $data, array('debug' => true))
JRenderer to replace JLayout
I have committed all the changes/fixes/improvements that I had pending for JLayout
so we can use that directly but I thought that plugin something new would help us to avoid inheriting some wrong behaviors from it.
So I have created a new JRenderer
class that uses adapters for each renderer type.
Benefits:
- It's a B/C change because anybody using
JLayout
will be able to use it normally. - In most cases
JRendererAdapterLayout
can replaceJLayout directly. I have created a helper for it so a sample
JLayoutHelper::render()call can be replaced with:
JRendererHelper::render()`. - With a new renderer we can be sure that only arrays are received by the renderer. We can also use
SplPriorityQueue
for search paths and anything we want it to have without having to think in B/C. - New adapters can be created for new renderers we want to integrate.
- Developers can call the renderer to get the base renderer and then tweak it in their own rendering class
- We could create a container of renderers in the application using DI for example? so anybody could plug there more renderers with something like
$app->registerRenderer('myname', $renderer)
? See section Things to discuss.
There is still a lot of work to do on the renderer but this is a starting point to further discussions.
To show how different classes can use the new renderer I have connected the plugin system.
JPlugin
receives the main renderer instance from the application- Then it setups the paths that apply to plugins
I have also replaced JLayout
calls in the default article view to see how it would be used instead of JLayout
.
* This is an example of how a renderer could be called if we want to go the single renderer instance way
Get base renderer from the active application
In this concept the renderer is provided by the application which is the class that initialises it with the right layout paths, prefixes or whatever we want to set as defaults.
This is how it works:
* JApplicationCms
provides the main renderer instance. So it's easy to replace the main renderer in one single file.
* Each application customises the renderer for its own needs. See JApplicationSite example
Renderer stats changes
I have also provided the debug plugin integration with JRenderer but instead of putting stats inside the renderer I have created a different class JRendererStats
so any renderer can send its own data instead of having to use JLayoutFile
to save stats. That means that any layout rendered by any class can be shown as a global stat in the debug plugin (while we migrate to a dynamic system for the debug system).
JRendererStats
now is almost empty and will need a lot of work to add methods like increaseCounter($name)
and anything that helps devs to use it. I have just moved things from my proposal.
To be discussed
- Now the renderer just generates a new instance of the renderer for each call. I have tried to create a single cached instance of the renderer but that will force us to reset the renderer before/after each use to avoid to inherit previous renderer settings & data
- What is the best way to allow devs to connect their own renderers? Can we use DI for that for example?
- JRenderer main class can be directly removed if we go the containers way in the application.
- Would be better to connect the current framework renderer and work on improving it?
- Can the framework package break B/C ?
- Can we use namespaces for this?
- Is adapters the best way to integrate renderers?
- Is JProfile something to use in the
JRendererStats
class?
Additional note
I'm really open to comments now as if we go the new renderer way I'm sure there are a lot of things we can do now before connecting the new renderer to the system and start dealing with B/C issues.
This is not a finished proposal. Just a collection of things connected here and there to show a global concept and to start discussing about it with a testing working system that can be improved with the feedback.