joomla-cms icon indicating copy to clipboard operation
joomla-cms copied to clipboard

[6.0] Remove class-level event dispatcher dependency in plugins

Open SharkyKZ opened this issue 3 years ago • 15 comments

Summary of Changes

Currently, the use of event dispatcher in plugins has some issues. Joomla\CMS\Plugin\CMSPlugin requires the dispatcher to be passed to the constructor but under normal circumstances it is not used because the dispatcher is always overwritten when importing the plugins using Joomla\CMS\Plugin\PluginHelper::importPlugin(). This is allowed by the fact that Joomla\CMS\Extension\PluginInterface implements Joomla\Event\DispatcherAwareInterface which has a setter method for injecting the dispatcher. This, however, means that for plugins that do not require it in the constructor, the dispatcher is optional and may not be set. This does not make any sense for plugins. The dispatcher must be mandatory and made available explicitly when registering listeners with it.

This PR proposes:

  1. Deprecate the dispatcher as an argument for Joomla\CMS\Plugin\CMSPlugin::__construct().
  2. Deprecate Joomla\CMS\Extension\PluginInterface extending Joomla\Event\DispatcherAwareInterface.
  3. Deprecate not passing the dispatcher to Joomla\CMS\Plugin\PluginHelper::importPlugin().
  4. Add dispatcher argument to Joomla\CMS\Extension\PluginInterface::registerListeners(). Currently nullable to allow J4/J5 compatibility.

B/C break for developers

Plugin developers need to update the registerListeners() method signature to support both J4 and J5.

Testing Instructions

Test that plugins continue working. Login, edit content, run smart search indexer, etc.

Link to documentations

Please select:

  • [ ] Documentation link for docs.joomla.org: TBD

  • [ ] No documentation changes for docs.joomla.org needed

  • [x] Pull Request link for manual.joomla.org: https://github.com/joomla/Manual/pull/70

  • [ ] No documentation changes for manual.joomla.org needed

SharkyKZ avatar Dec 09 '22 08:12 SharkyKZ

This PR is not possible, this would break all plugins overriding the registerListeners method, which means you can't have a plugin which supports 4 and 5.

We need this in a way which is b/c.

HLeithner avatar Mar 08 '23 17:03 HLeithner

It's true that existing plugins with overridden method would need to be updated to account for the new method signature. But such plugins will work with both 4.0 and 5.0. This is mentioned in the manual. And when interface method signature is changed again in 6.0 to require a dispatcher instance, no changes will be necessary. So a plugin that's updated with 5.0 signature today will end up working with 4.0, 5.0 and 6.0.

We need this in a way which is b/c.

Interesting. Can you post a link to the new versioning policy of Joomla? I've seen claims that it supposedly follows SemVer but that seems to have changed.

SharkyKZ avatar Mar 09 '23 06:03 SharkyKZ

This changes can be done in b/c way, without changing method signatures:

  • keep DispatcherAwareInterface interface
  • call $plugin->setDispatcher($dispatcher) in PluginHelper::import(), as it already is
  • modify registerListeners() to throw an exception when $this->getDispatcher() return trash.

Fedik avatar Apr 03 '23 14:04 Fedik

@laoneo what would you say?

HLeithner avatar Apr 03 '23 17:04 HLeithner

This changes can be done in b/c way, without changing method signatures:

* keep `DispatcherAwareInterface` interface

* call `$plugin->setDispatcher($dispatcher)` in `PluginHelper::import()`, as it already is

* modify `registerListeners()` to throw an exception when `$this->getDispatcher()` return trash.

🤦‍♂️ The point here is to get rid of the totally misused DispatcherAwareInterface. But, apparently, the project is going backwards, introducing -aware interfaces in places where they absolutely don't belong.

SharkyKZ avatar Apr 03 '23 18:04 SharkyKZ

Why it is not belong, what is belong then? Sorry, I do not understand, maybe my knowledge just not enogh. In current case for me no big diference here if it DispatcherAwareInterface or PotatoInterface ;)

I can also sugest other way around, without DispatcherAwareInterface:

  • add new method to PluginInterface, kind of registerListenersInDispatcher(?DispatcherInterface $dispatcher = null);
  • deprecate registerListeners()
  • add use of new method, and proxy it to registerListeners(), untill 6.x

And add description why and when registerListeners() should be removed, and replaced with new method. Because after 1 year no one will remember what the heck is going on.

Fedik avatar Apr 03 '23 18:04 Fedik

Hmhm, or you mean that DispatcherAwareInterface should be used only when Class triggers some event? Well, then it may have a sense, even though it not an obvious thing. Then a new method should be a less risky change, than changing existing, in current case.

Fedik avatar Apr 03 '23 18:04 Fedik

So I think that removing the Dispatcher as a constructor argument is a good thing.

My only question would be do we want to go down this approach OR to have the dispatcher get the events out (which is how I think this was intended to work originally using the subscriber interface - i.e. https://github.com/joomla/joomla-cms/pull/39387/files#diff-76977b095cc108785d3c5026e26a2df447db05cd1ad28a0a22820cf72573965bR230-R234 ). I always assumed once we removed support for Joomla 3.x style plugins and moved people over to SubscriberInterface that we'd remove the entire registerListeners method.

introducing -aware interfaces in places where they absolutely don't belong

I totally agree with this.

wilsonge avatar Jun 29 '23 11:06 wilsonge

This pull request has been automatically rebased to 5.1-dev.

HLeithner avatar Sep 30 '23 22:09 HLeithner

This pull request has been automatically rebased to 5.2-dev.

HLeithner avatar Apr 24 '24 09:04 HLeithner

I'm sorry, but looking at the registerListener, this wont be able to be merged into 5.x and would have to wait for 6.0 at least.

Hackwar avatar Jul 24 '24 19:07 Hackwar

This pull request has been automatically rebased to 5.3-dev.

HLeithner avatar Sep 02 '24 08:09 HLeithner

@SharkyKZ I think we going to use Lazy Objects for plugins, this is where static getSubscribedEvents() come in handy. The plugin will be initialized only at time when actual event is triggered.

We should say farewell to registerListeners() because it will always trigger Lazy Objects instantiation.

Please update your PR:

  • revert changes for registerListeners(), it going to be deprecated with https://github.com/joomla/joomla-cms/pull/43395
  • resolve conflicts, note that use of DispatcherAwareInterface is deprecated already in https://github.com/joomla/joomla-cms/pull/43430

Only issue is need to be resolved, is conditional registration (eg: if admin, if site etc). It seems main reason why some developers override registerListeners() in their plugins. One of ideas is:

  • https://github.com/joomla/joomla-cms/pull/43657 (drawback: it still will instantiate plugin, but only when it is explicitly implemented by plugin)
  • use static calls of Factory::getApplication() inside getSubscribedEvents(), which is not very nice

If you or someone else have a better ideas, please write in that PR.

Thanks!

Fedik avatar Mar 02 '25 14:03 Fedik

This pull request has been automatically rebased to 6.0-dev.

HLeithner avatar Mar 04 '25 17:03 HLeithner

@SharkyKZ If you really want this feature (a possibility to do listeners registration inside the plugin), then it is need a new interface with different method names. Otherwise there is no way it going to be merged, because of hard b/c break, which prevent of using the same plugin across multiple Joomla version.

You could do something like I tried in:

  • #43431

But with 2 methods:

  • registerEventListeners(DispatcherInterface $dispatcher)
  • unregisterEventListeners(DispatcherInterface $dispatcher)

Or something like that. Then it probably can be even merged in to 5.4. If other developers don't mind.

Fedik avatar Jun 01 '25 09:06 Fedik

This pull request has been automatically rebased to 6.1-dev.

HLeithner avatar Aug 31 '25 12:08 HLeithner