New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introducing HookDispatcherInterface #9437
Introducing HookDispatcherInterface #9437
Conversation
@mickaelandrieu wdyt about this? |
src/Core/Hook/HookDispatcher.php
Outdated
/** | ||
* @param HookDispatcherService $deprecatedHookDispatcherService | ||
*/ | ||
public function __construct(HookDispatcherService $deprecatedHookDispatcherService) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internally it still depends on deprecated service to keep same functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the old service should implement the interface too
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function dispatchRendering(HookInterface $hook) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be called ->dispatch
too. But check for class interface or capability to use render or not.
If we change the hook capability, we will need to change the method name everywhere, when the first aim is to dispatch a hook. No?
Plus, if you stay with dispatchRendering
method, the parameter isn't the right one, must be RenderedHookInterface
, same for parent interface and doc block :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PierreRambaud thanks for your comment! :)
However, Im not sure if I get it correctly. Why do you think parameter is wrong for dispatchRendering
? I think that both types of hooks have same structure (name and parameters) despite whether it's a display or an action hook.
The main difference between dispatch()
and dispatchRendering()
is that you dont expect anything to be returned from dispatch()
(right?) but you always know that dispatchRendering
will return RenderedHookInterface
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just think like for Symfony and Response
for example.
If you dispatch
a Response
, you don't care if it's a JsonResponse
, a BinaryFileResponse
or a RedirectResponse
. These three classes haven't the same capabilities but are called with the same method =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a note, we can't use dispatch() as it will conflict with EventDispatcherInterface.
For now, we want to keep the compatibility with the Event Dispatcher component, so we MUST NOT override this function signature.
@@ -35,6 +35,8 @@ | |||
* | |||
* If the event is a RenderingHookEvent, then the final result is | |||
* an array of contents accessed from $event->getContent(). | |||
* | |||
* @deprecated since 1.7.5, to be removed in 1.8. Use PrestaShop\PrestaShop\Core\Hook\HookDispatcher instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I read this correctly, you didn't deprecate it but only add an extra layer to the old implementation.
Deprecation means: "we don't use it anymore, but if external people use it, it will works as expected". This is not what is done here, because you re-use it.
Let's imagine we remove it: the new implementation will be broken because we depend on implementation and not to the contract.
What I suggest:
- Create
PrestaShop\PrestaShop\Adapter\Hook\HookDispatcher
withPrestaShop\PrestaShopBundle\Service\Hook\HookDispatcher
content, this new class implementsHookDispatcherInterface
; - Make
PrestaShop\PrestaShopBundle\Service\Hook\HookDispatcher
extendsPrestaShop\PrestaShop\Adapter\Hook\HookDispatcher
, empty it and add a constructor with the following content:
public function __construct() {
trigger_error('Deprecated since 1.7.5, to be removed in 1.8. Use PrestaShop\PrestaShop\Core\Hook\HookDispatcher instead.', E_USER_DEPRECATED);
parent::__construct();
}
- Now
PrestaShop\PrestaShop\Core\Hook\HookDispatcherInterface
can depend on his adapter (which is our strategy to deprecate legacy stuff) and in 1.8 we will be able to removePrestaShopBundle\Service\HookDispatcher
(not used anymore) for sure and maybe the adapter. - You need to replace all calls of
PrestaShopBundle\Service\HookDispatcher
by the core class.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some extra work to do but I'm ok with it: good job @sarjon
src/Core/Hook/HookDispatcher.php
Outdated
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function dispatch(HookInterface $hook) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this one conflicts with EventDispatcherInterface::dispatch(), reverted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but is hook dispatcher == event dispatcher?
0c2ca3a
to
f16a106
Compare
Some work to do here: remove every direct call to |
I'll finish this one ;) |
*/ | ||
public function dispatchHook(HookInterface $hook) | ||
{ | ||
$this->hookDispatcherAdapter->dispatchForParameters( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, now that i think about it, maybe we actually have to return results even though this is not Rendering hook?
For example, we have a hook paymentOptions
, it does not render anything, but rather returns PaymentOption[]
. There are more hooks like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so this should be
return $this->hookDispatcherAdapter->dispatchForParameters()...
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, as we now have RenderedHookInterface
we could return ExecutedHookInterface
with getData()
which returns executed hook's data if any?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not, let me think about it: I'm in favor of typed hook return, but I may not want to introduce it "now".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, I was thinking about further refactoring:
ModuleManagementEvent should be splitted into:
- AbstractModuleEvent
- InstallModuleEvent
- UninstallModuleEvent
- ... Event
And they have to extend HookEvent instead of Event so we could call dispatchHook(AbstractModuleEvent ...) in ModuleManager: wdyt?
Same for ModuleZipManagementEvent (nice name that means nothing :p )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, i guess it makes sense to have different events for actually different events (install, uninstall & etc).
thanks! :) |
f01a71f
to
8164557
Compare
443963b
to
b725452
Compare
30c9407
to
5dd01f4
Compare
ping @PierreRambaud / @Quetzacoalt91 wdyt: go, no go? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 5 of 8 files at r1, 29 of 29 files at r9.
Reviewable status: all files reviewed, 9 unresolved discussions (waiting on @sarjon, @PierreRambaud, and @mickaelandrieu)
src/Adapter/Hook/HookDispatcher.php, line 55 at r9 (raw file):
* @throws \Exception If the Event is not HookEvent or a subclass. */ public function dispatch($eventName, Event $event = null)
Should be HookEvent
instead Event
. And you will be able to remove the test with instanceof
src/Adapter/Hook/HookDispatcher.php, line 86 at r9 (raw file):
* @throws \Exception If the Event is not HookEvent or a subclass. */ public function dispatchMultiple(array $eventNames, array $eventParameters)
you can make $eventParameters optional
src/Adapter/Hook/HookDispatcher.php, line 131 at r9 (raw file):
* @param array $parameters Hook parameters * @return Event The event that has been passed to each listener. * @throws \Exception
use namespace
src/Core/Hook/HookDispatcher.php
Outdated
/** | ||
* Class HookDispatcher is responsible for dispatching hooks | ||
*/ | ||
final class HookDispatcher implements HookDispatcherInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between this file and src/Adapter/Hook/HookDispatcher.php
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't depend directly on Symfony EventDispatcher 👍
this is a BC, we can't do that.
this is a BC, we can't do that.
hey, I can actually do that 👍 ... but Event class namespace is already included in the file header: what do you mean? I can't alter any behavior of the Adapter as it's a copy of the Service, for instance if you wanted to replace HookEvent by Event I can do it as the "contract" become more open (can't break existing). Making $eventParameters optional is ok from a "contract" point of view, but what will happens if at some point the contract is not respected and someone assume the $eventParameters exists? It's risky. |
Don't understand why it's a BC when there is an exception throw if it's not a HookEvent. Otherwise it's already a BC to add this condition.
Can't be a BC. adding |
yes, and it's part of the behavior: you can caught the exception while it's really hard to catch the error induced by the signature changes.
If it changes nothing at all, why introduce a change? Above all, I want to clarify what is done here: move what was previously in Services/HookDispatcher into Adapter namespace: there is no intent to refactor nor improve the current behavior here, as it's not tested at all. It was done only to comply with rules on |
My bad, forget the interface 🙄
It add a little value to call a function without adding and empty array if we don't have a parameters, don't forget we are not alone to use this project =) |
ok, let's go for it |
6b6ed41
to
2c0a526
Compare
@PierreRambaud I've added the optional array 👍 and rebased and fixed coding styles |
This doesn't QA approval, in case of error it's on me :) Thanks for review @PierreRambaud |
PrestaShopBundle\Service\Hook\HookDispatcher
.What have been done here?
HookDispatcherInterface
everywhere we usedHookDispatcher
.PrestaShopBundle\Service\Hook\HookDispatcher
in favor ofPrestaShop\PrestaShop\Adapter\Hook\HookDispatcher
=> more compliant withPrestaShopBundle
responsibilities;PrestaShop\PrestaShop\Core\Hook\HookDispatcher
and use it everywhere in Core, we keep the Adapter available until 1.8 => compliant with our migration strategy;NullDispatcher
and made him implementsHookDispatcherInterface
=> some technical debt we will address in another contribution;HookDispatcherInterface
extendsEventDispatcherInterface
from Symfony and we rely onEventDispatcher
class (even though we don't use the registered one).Why do we do that?
This is a first step to migrate Hook management to Symfony Event Dispatcher component: for now Hook system is richer on dispatch features, but weaker in "listeners" control. At some point, we will need to decide what to do with Hooks and how to make them more powerful and performant 👍
Rely on interfaces give us time to work on multiples implementations without introduces any breaks.
Next step(s) ?
What we'd like to to is to make the HookDispatcher used as a replacement of the Event Dispatcher so we could dispatch events, regardless these are hooks (PrestaShop events) or Symfony events with the same class. For now the Event Dispatcher is used for Symfony events, and the HookDispacher for Hooks: but now they share a common interface 👍 .
This is something (Make hooks dispatched as Symfony events or Symfony events dispatched as "Hooks") we could do in 1.7 to replace the old Hook system in the next major. For that we also need to use the even dispatcher in Front office.
This change is