Plugin type for use before JApplication has been instantiated

54 views
Skip to first unread message

Chris Bradbury

unread,
Nov 20, 2016, 1:04:06 PM11/20/16
to Joomla! CMS Development
I've been wanting the ability to override or extend pretty much any class, particularly `JApplicationCms`, for ages. I've been spending too much time with the session classes lately and the 'onAfterSessionStart' event that's only used to call an application class's `afterSessionStart()` method began to grate.

So I implemented a new plugin type, 'application', for use before an application object instance has been created, with three event triggers:
  • onBeforeApplication - triggered in root index.php before beginning application instantiation.
  • onBeforeSessionStart - triggered during application instantiation before a session is started, taking a session object as an argument.
  • onAfterSessionStart - triggered during application instantiation after a session is started, taking a session object as an argument.

As as result I can now override/extend any class I like with minimal effort.

It was far too easy to do though, so I'm suspicious as to why it's not been implemented yet - there's no way I'm the first to have thought of this. Is there a reason that plugins are unable to be used until an application object has been created, or can it really be as simple as 'because nobody's done it yet'?

Michael Babker

unread,
Nov 20, 2016, 1:22:11 PM11/20/16
to joomla-...@googlegroups.com
There is an inner coupling with JPluginHelper's method to load the plugins to a JUser object fetched from JFactory, which will first look for the user object from the session (inherently starting the session).  So it is not feasible to be able to decouple the system like this, unless you're explicitly registering the event handlers as callbacks to the dispatcher without loading the plugins you're still going to get a session started before you can use any of those events are dispatched (which defeats the purpose of having them available as plugins).

You might be able to create this as an override on a per-instance basis which you have more control over, but there is not a way to cleanly introduce this as a default behavior into the CMS.  Nor do I think we should have an event that makes it possible to overload the application objects (the CMS is already too fragile with having untyped dependencies to JApplicationCms, I don't agree with our API supporting class overloading to begin with but this particular class and its children are really one that shouldn't be touched).

--
You received this message because you are subscribed to the Google Groups "Joomla! CMS Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to joomla-dev-cms+unsubscribe@googlegroups.com.
To post to this group, send email to joomla-dev-cms@googlegroups.com.
Visit this group at https://groups.google.com/group/joomla-dev-cms.
For more options, visit https://groups.google.com/d/optout.

Hannes Papenberg

unread,
Nov 20, 2016, 2:34:15 PM11/20/16
to joomla-...@googlegroups.com
Why aren't you using a self-defined defines.php? Simply drop a
defines.php in the root of your site and in there set all the constants
from /includes/defines.php and do your additional code stuff, like
loading your version of JApplicationCMS. No need for new triggers, no
issues with prematurely started sessions, etc. and works back to at
least Joomla 1.6.

Hannes

Am 20.11.2016 um 19:04 schrieb Chris Bradbury:
> I've been wanting the ability to override or extend pretty much any
> class, particularly `JApplicationCms`, for ages. I've been spending too
> much time with the session classes lately and the 'onAfterSessionStart'
> event that's only used to call an application class's
> `afterSessionStart()` method began to grate.
>
> So I implemented a new plugin type, 'application', for use before an
> application object instance has been created, with three event triggers:
>
> * onBeforeApplication - triggered in root index.php before beginning
> application instantiation.
> * onBeforeSessionStart - triggered during application instantiation
> before a session is started, taking a session object as an argument.
> * onAfterSessionStart - triggered during application instantiation
> after a session is started, taking a session object as an argument.
>
> As as result I can now override/extend any class I like with minimal effort.
>
> It was far too easy to do though, so I'm suspicious as to why it's not
> been implemented yet - there's no way I'm the first to have thought of
> this. Is there a reason that plugins are unable to be used until an
> application object has been created, or can it really be as simple as
> 'because nobody's done it yet'?
>
> --
> You received this message because you are subscribed to the Google
> Groups "Joomla! CMS Development" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to joomla-dev-cm...@googlegroups.com
> <mailto:joomla-dev-cm...@googlegroups.com>.
> To post to this group, send email to joomla-...@googlegroups.com
> <mailto:joomla-...@googlegroups.com>.

Chris Bradbury

unread,
Nov 20, 2016, 3:39:35 PM11/20/16
to Joomla! CMS Development

On Sunday, November 20, 2016 at 6:22:11 PM UTC, Michael Babker wrote:
There is an inner coupling with JPluginHelper's method to load the plugins to a JUser object fetched from JFactory, which will first look for the user object from the session (inherently starting the session).

That's actually incorrect - a session object is created, it isn't doesn't actually try to start a session until halfway through the `loadSession` method during construction of the application object. That call in the plugin helper just gets the view levels from the database, it doesn't result in the 'onAfterSessionStart' event being triggered; the session object can be easily modified before the session is actually started.

Nor do I think we should have an event that makes it possible to overload the application objects (the CMS is already too fragile with having untyped dependencies to JApplicationCms

This is what I was wondering about. My follow up question to it is asked purely for my own education rather than questioning the rational of that decision - why?

I can understand that by overriding it you are seriously, heavily able to mess with the guts of the CMS. Misuse of it will undoubtedly lead to a whole load of problems. Why, though, is that any worse than messing up anything else? I can already write a crap component that exposes any site using it to every two-bit script-kiddie going, so is it really that much more of a problem if I poorly implement an application class? Surely it's a dev's responsibility to ensure their code works properly? Or is it a case that when working within a framework some things should be left inviolable?

Chris Bradbury

unread,
Nov 20, 2016, 3:42:43 PM11/20/16
to Joomla! CMS Development
On Sunday, November 20, 2016 at 7:34:15 PM UTC, Hannes Papenberg wrote:
Why aren't you using a self-defined defines.php?

That's an option, but as much as I'd like to able to break the CMS whenever I want I'd also like to be able to do so from within as much as possible.

Hannes Papenberg

unread,
Nov 20, 2016, 4:09:22 PM11/20/16
to joomla-...@googlegroups.com
I don't see a reason to implement something like what you are proposing
for a maybe low double digit audience, when there is a perfectly good
solution like the one that I described previously is available.

I doubt that there are more than 5 sites out there that would benefit
from something like that. On the other hand, Plugin Events are not for
free. Introducing something like this so that 5 sites can benefit from
this, means several more CPU cycles for everybody. Might not be much for
each page call individually, but accumulated over the millions of
websites and billions of page calls every day, this adds up both in
wasted energy and reduced performance.

Hannes

Michael Babker

unread,
Nov 20, 2016, 4:15:25 PM11/20/16
to joomla-...@googlegroups.com
On Sun, Nov 20, 2016 at 2:39 PM, Chris Bradbury <viff...@gmail.com> wrote:

On Sunday, November 20, 2016 at 6:22:11 PM UTC, Michael Babker wrote:
There is an inner coupling with JPluginHelper's method to load the plugins to a JUser object fetched from JFactory, which will first look for the user object from the session (inherently starting the session).

That's actually incorrect - a session object is created, it isn't doesn't actually try to start a session until halfway through the `loadSession` method during construction of the application object.

Oh, right.  I stand corrected.  What the actual issue is is that the session right now requires an explicit call to JSession::start() to actually start the session (and inherently load the correct data into memory).  So you're right in that a call to JSession::get() can incorrectly result in a bad data return (one of the many things I tried fixing through https://github.com/joomla/joomla-cms/pull/10905 but thanks to our current application constructor behaviors that entire PR had to be reverted and I honestly can't be bothered to try and implement it and the numerous bug fixes again knowing full well the extra additional changes required).

Nor do I think we should have an event that makes it possible to overload the application objects (the CMS is already too fragile with having untyped dependencies to JApplicationCms

This is what I was wondering about. My follow up question to it is asked purely for my own education rather than questioning the rational of that decision - why?

I can understand that by overriding it you are seriously, heavily able to mess with the guts of the CMS. Misuse of it will undoubtedly lead to a whole load of problems. Why, though, is that any worse than messing up anything else? I can already write a crap component that exposes any site using it to every two-bit script-kiddie going, so is it really that much more of a problem if I poorly implement an application class? Surely it's a dev's responsibility to ensure their code works properly? Or is it a case that when working within a framework some things should be left inviolable?

My issue with overloading classes (that is, you using a custom version of JApplicationSite by messing with the autoloader or PHP behaviors to get your custom version loaded before the correct version) is it no longer makes the API consistent.  This is nothing against Peter and his products, but one of the ways Advanced Module Manager works is by overloading the JModuleHelper class.  So now on sites using that extension, if there is a bug with a stack trace leading back to that class, now you have to spend extra time figuring out whether it is a bug in the overloaded class or with Joomla core (since IIRC the majority of that class is based on the core code but a couple of the methods have some extra code for his extension to work).  As an extension developer, I can't rely on the API to be correct when these classes are overloaded.  It's not just the app class or JModuleHelper, but at least with the module helper this was the easiest current example I could reference.

Chris Bradbury

unread,
Nov 20, 2016, 5:12:11 PM11/20/16
to Joomla! CMS Development
I doubt that there are more than 5 sites out there that would benefit
from something like that.

I started down this road mainly because I wanted to override the behaviour of sessions more easily than at present - that's less of a niche demand than overriding the application class (probably will be a bit less demand for the ability now shared sessions are set to be implemented though, but it's still more work to attach a custom storage handler than it should be). Adding a plugin type that doesn't rely on instanced application objects is the easiest way to do that without making some hefty changes to the session classes. So I added one to add session event triggers, and it became a case of 'if the potential's there, why not, it's just one more event'.


My issue with overloading classes (that is, you using a custom version of JApplicationSite by messing with the autoloader or PHP behaviors to get your custom version loaded before the correct version) is it no longer makes the API consistent.  This is nothing against Peter and his products, but one of the ways Advanced Module Manager works is by overloading the JModuleHelper class.  So now on sites using that extension, if there is a bug with a stack trace leading back to that class, now you have to spend extra time figuring out whether it is a bug in the overloaded class or with Joomla core (since IIRC the majority of that class is based on the core code but a couple of the methods have some extra code for his extension to work).  As an extension developer, I can't rely on the API to be correct when these classes are overloaded.  It's not just the app class or JModuleHelper, but at least with the module helper this was the easiest current example I could reference.

Great explanation Michael, thanks.
Reply all
Reply to author
Forward
0 new messages