Skip to content
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

[EventDispatcher] Add Drupal EventDispatcher #12521

Closed
wants to merge 18 commits into from

Conversation

znerol
Copy link
Contributor

@znerol znerol commented Nov 19, 2014

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? ?
Fixed tickets #12007
License MIT (relicensing to be approved by three contributors)
Doc PR -

Drupal forked the EventDispatcher for performance reasons a while ago because the construction of the event dispatcher service turned out to be an order of magnitude faster when listeners are injected into the constructor instead of adding them one-by-one with method calls (see Drupal issue 1972300).

This PR contains that version with Symfony coding-standards applied and short-array syntax removed. Obviously the class name hardly should be DrupalEventDispatcher but I cannot figure out a good name atm. Let's first see whether Symfony is willing to adopt it.

@znerol
Copy link
Contributor Author

znerol commented Nov 19, 2014

Note that #12131 would also help a lot here, regardless of whether this PR will be accepted or not.

@unkind
Copy link
Contributor

unkind commented Nov 19, 2014

Why you don't patch existing RegisterListenersPass and ContainerAwareEventDispatcher instead?

@znerol
Copy link
Contributor Author

znerol commented Nov 20, 2014

Because that breaks BC and thus cannot be accepted in Symfony, see #12019

* file that was distributed with this source code.
*/

namespace Drupal\Core\DependencyInjection\Compiler;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this namespace be changed to namespace Symfony\Component\EventDispatcher\DependencyInjection;?

@henrikbjorn
Copy link
Contributor

Seems like it should be possible to add an optional constructor argument to the current EventDispatcher instead of doing a new class.

* </dd>
* </dl>
*/
class ContainerAwareEventDispatcher implements EventDispatcherInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class name does not correspond with the filename

@henrikbjorn
Copy link
Contributor

The idea is great, but this lacks tests and have clearly not been run after the move here, as classname and filenames does not correspond.

$definition['callable'] = array($this->container->get($definition['service'][0]), $definition['service'][1]);
}

$definition['callable']($event, $event_name, $this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm right, this dereferencing syntax is only available in PHP 5.4+, so we couldn't use it for Symfony.

@znerol
Copy link
Contributor Author

znerol commented Nov 20, 2014

Indeed this was just a copy paste with some cleanup which I did mainly for testing the waters. Regarding tests, see #12131.

/**
* {@inheritdoc}
*/
public function dispatch($event_name, Event $event = NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's a minor thing, but in Symfony we usually put null in lowercase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the PHP-CS-Fixer tool will fix this automatically

@javiereguiluz
Copy link
Member

@znerol thanks for your PR. As you may now, in Symfony we have a bot that checks if the submitted code complies with the code syntax standards used in the project.

Apparently, your PR needs some minor tweaks to comply with those standards. You can find a patch to fix them all at http://fabbot.io/report/symfony/symfony/12521/61864b082c705f55501bd7ef33e457d2df80656e

Please tell me if you need any help with that.

@znerol
Copy link
Contributor Author

znerol commented Nov 20, 2014

If I'm right, this dereferencing syntax is only available in PHP 5.4+, so we couldn't use it for Symfony.

We actually wondered about that also, but it seems that this has been introduced in 5.3. The following test passes on 3v4l with the relevant versions:

<?php
$f = function ($x) {echo $x;};
$a = array('f' => $f);
$a['f']('hi!');

@javiereguiluz
Copy link
Member

@znerol you are right! I'm sorry about my comment because the syntax is indeed valid for PHP 5.3.

@fabpot
Copy link
Member

fabpot commented Nov 20, 2014

@znerol #12131 has just been merged in 2.6.

@fabpot
Copy link
Member

fabpot commented Nov 20, 2014

So, the question now is: can this class replace the existing one in Symfony 3.0? If yes, we then need to deprecate the current one in favor of this one.

@znerol
Copy link
Contributor Author

znerol commented Nov 20, 2014

There is a subtle change in behavior when using this class. This has been pointed out by @stof in #12069:

adding all listener classes as container resources is likely to have an impact in dev, as it means that the container will need to be rebuilt each time you change the source code of your listener.

With the ContainerAwareEventDispatcher it is possible to set the priority of a listener dynamically (i.e. on every request), this is not possible with CompiledEventDispatcher. I have no idea whether or not this was intentionally designed like that.

@fabpot
Copy link
Member

fabpot commented Nov 20, 2014

@znerol I don't think there is a practical use case of this drawback. So, even if I can see the BC break here, I don't think it makes sense to support it. IMO, if the "limitation" is well documented, that's more than enough.

@znerol
Copy link
Contributor Author

znerol commented Nov 20, 2014

Ok, then the following things need to be done:

Regarding the compiler pass, is it okay to simply add the array of listeners to the list of constructor arguments?

/**
* Whether listeners need to be sorted prior to dispatch, keyed by event name.
*
* @var TRUE[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type doc should be @var array

@stof
Copy link
Member

stof commented Nov 21, 2014

The compiler pass to initialize the dispatcher should be provided as well (otherwise we won't be able to use it by default).

And I don't see how you will handle the lazy loading of event subscriber in your listener. There is no logic to handle this in your code.
And note that resolving events in the compiler pass is precisely was caused previous attempts to be rejected, because it breaks the debug mode (by forcing to clear the cache manually even in debug mode when changing the list of events, which is bad for the DX as Symfony developers are used of having automatic cache reloading in dev)

@stof
Copy link
Member

stof commented Nov 21, 2014

and registering subscribers in a non-lazy way is not an option either given that all Symfony listeners are defined as subcribers to be easier to reuse them in other frameworks like Silex

@znerol
Copy link
Contributor Author

znerol commented Nov 21, 2014

The compiler pass to initialize the dispatcher should be provided as well

It is there

And I don't see how you will handle the lazy loading of event subscriber in your listener.

If you mean $container->get('some-service'); it is there, if you are referring to something different, please explain.

And note that resolving events in the compiler pass is precisely was caused previous attempts to be rejected.

The intention of this PR is to provide an alternative implementation, not to replace the existing ContainerAwareEventDispatcher.

@znerol
Copy link
Contributor Author

znerol commented Nov 22, 2014

Travis failures for PHP 5.3 are the same as for the current 2.7 branch, no test failures in the event dispatcher component.

@chx
Copy link
Contributor

chx commented Nov 23, 2014

You have my permission for this. I am definitely not happy with MIT licensing my code but let's do it.

@znerol
Copy link
Contributor Author

znerol commented Feb 18, 2015

@stof / @fabpot ping

@znerol
Copy link
Contributor Author

znerol commented Mar 3, 2015

Symfony 2.7 is about to enter feature-freeze. We should decide soon on whether or not this gets in.

@nicolas-grekas
Copy link
Member

I'd be in favor of closing this one and work on #20875 instead.

@nicolas-grekas
Copy link
Member

More generic solution posted in #20953, based on closure injection + compile time resolution of subscribers.
Could you please Drupal guys have a look at it and see if it looks good for Drupal also?

@nicolas-grekas
Copy link
Member

Closed in favor of #20953

fabpot added a commit that referenced this pull request Jan 7, 2017
…t type (nicolas-grekas)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DI][EventDispatcher] Add & wire closure-proxy argument type

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #12521, #12007, #20039
| License       | MIT
| Doc PR        | -

By resolving event subscribers at compile time, then wrapping listeners in a closure, we get laziness almost for free. This should solve/replaced all the above linked issues.

(WIP because tests are missing)

Commits
-------

ecdf857 [DI][EventDispatcher] Add & wire closure-proxy argument type
@nicolas-grekas nicolas-grekas modified the milestones: 3.x, 3.3 Mar 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet