Update to Drupal 8.1.0. For more information, see https://www.drupal.org/drupal-8.1.0-release-notes

This commit is contained in:
Pantheon Automation 2016-04-20 09:56:34 -07:00 committed by Greg Anderson
parent b11a755ba8
commit c0a0d5a94c
6920 changed files with 64395 additions and 57312 deletions

View file

@ -131,6 +131,16 @@ class ContainerAwareEventDispatcher extends EventDispatcher
return parent::getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
{
$this->lazyLoad($eventName);
return parent::getListenerPriority($eventName, $listener);
}
/**
* Adds a service as event subscriber.
*

View file

@ -99,6 +99,14 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return $this->dispatcher->getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
/**
* {@inheritdoc}
*/
@ -186,6 +194,8 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
}
uasort($notCalled, array($this, 'sortListenersByPriority'));
return $notCalled;
}
@ -225,12 +235,12 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
private function preProcess($eventName)
{
foreach ($this->dispatcher->getListeners($eventName) as $listener) {
$this->dispatcher->removeListener($eventName, $listener);
$info = $this->getListenerInfo($listener, $eventName);
$name = isset($info['class']) ? $info['class'] : $info['type'];
$wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this);
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->addListener($eventName, $wrappedListener);
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $wrappedListener, $info['priority']);
}
}
@ -243,8 +253,9 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
continue;
}
// Unwrap listener
$priority = $this->getListenerPriority($eventName, $listener);
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $listener->getWrappedListener());
$this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);
$info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
if ($listener->wasCalled()) {
@ -285,6 +296,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
{
$info = array(
'event' => $eventName,
'priority' => $this->getListenerPriority($eventName, $listener),
);
if ($listener instanceof \Closure) {
$info += array(
@ -332,4 +344,25 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return $info;
}
private function sortListenersByPriority($a, $b)
{
if (is_int($a['priority']) && !is_int($b['priority'])) {
return 1;
}
if (!is_int($a['priority']) && is_int($b['priority'])) {
return -1;
}
if ($a['priority'] === $b['priority']) {
return 0;
}
if ($a['priority'] > $b['priority']) {
return -1;
}
return 1;
}
}

View file

@ -98,9 +98,8 @@ class RegisterListenersPass implements CompilerPassInterface
// We must assume that the class value has been correctly filled, even if the service is created by a factory
$class = $container->getParameterBag()->resolveValue($def->getClass());
$refClass = new \ReflectionClass($class);
$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
if (!$refClass->implementsInterface($interface)) {
if (!is_subclass_of($class, $interface)) {
throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
}

View file

@ -75,6 +75,29 @@ class EventDispatcher implements EventDispatcherInterface
return array_filter($this->sorted);
}
/**
* Gets the listener priority for a specific event.
*
* Returns null if the event or the listener does not exist.
*
* @param string $eventName The name of the event
* @param callable $listener The listener
*
* @return int|null The event listener priority
*/
public function getListenerPriority($eventName, $listener)
{
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== ($key = array_search($listener, $listeners, true))) {
return $priority;
}
}
}
/**
* {@inheritdoc}
*/
@ -169,8 +192,6 @@ class EventDispatcher implements EventDispatcherInterface
*/
private function sortListeners($eventName)
{
$this->sorted[$eventName] = array();
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
}

View file

@ -38,7 +38,7 @@ interface EventSubscriberInterface
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2')))
*
* @return array The event names to listen to
*/

View file

@ -83,6 +83,14 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
return $this->dispatcher->getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
/**
* {@inheritdoc}
*/

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,27 +1,15 @@
EventDispatcher Component
=========================
The Symfony EventDispatcher component implements the Mediator pattern in a
simple and effective way to make your projects truly extensible.
```php
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\Event;
$dispatcher = new EventDispatcher();
$dispatcher->addListener('event_name', function (Event $event) {
// ...
});
$dispatcher->dispatch('event_name');
```
The EventDispatcher component provides tools that allow your application
components to communicate with each other by dispatching events and listening to
them.
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/EventDispatcher/
$ composer install
$ phpunit
* [Documentation](https://symfony.com/doc/current/components/event_dispatcher/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View file

@ -108,6 +108,20 @@ abstract class AbstractEventDispatcherTest extends \PHPUnit_Framework_TestCase
$this->assertSame($expected, $this->dispatcher->getListeners());
}
public function testGetListenerPriority()
{
$listener1 = new TestEventListener();
$listener2 = new TestEventListener();
$this->dispatcher->addListener('pre.foo', $listener1, -10);
$this->dispatcher->addListener('pre.foo', $listener2);
$this->assertSame(-10, $this->dispatcher->getListenerPriority('pre.foo', $listener1));
$this->assertSame(0, $this->dispatcher->getListenerPriority('pre.foo', $listener2));
$this->assertNull($this->dispatcher->getListenerPriority('pre.bar', $listener2));
$this->assertNull($this->dispatcher->getListenerPriority('pre.foo', function () {}));
}
public function testDispatch()
{
$this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));

View file

@ -59,6 +59,18 @@ class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
->with($event)
;
$service
->expects($this->once())
->method('onEventWithPriority')
->with($event)
;
$service
->expects($this->once())
->method('onEventNested')
->with($event)
;
$container = new Container();
$container->set('service.subscriber', $service);
@ -66,6 +78,8 @@ class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
$dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService');
$dispatcher->dispatch('onEvent', $event);
$dispatcher->dispatch('onEventWithPriority', $event);
$dispatcher->dispatch('onEventNested', $event);
}
public function testPreventDuplicateListenerService()
@ -92,6 +106,7 @@ class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
/**
* @expectedException \InvalidArgumentException
* @group legacy
*/
public function testTriggerAListenerServiceOutOfScope()
{
@ -111,6 +126,9 @@ class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
$dispatcher->dispatch('onEvent');
}
/**
* @group legacy
*/
public function testReEnteringAScope()
{
$event = new Event();
@ -239,11 +257,21 @@ class SubscriberService implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
'onEvent' => array('onEvent'),
'onEvent' => 'onEvent',
'onEventWithPriority' => array('onEventWithPriority', 10),
'onEventNested' => array(array('onEventNested')),
);
}
public function onEvent(Event $e)
{
}
public function onEventWithPriority(Event $e)
{
}
public function onEventNested(Event $e)
{
}
}

View file

@ -25,7 +25,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
$tdispatcher->addListener('foo', $listener = function () {; });
$tdispatcher->addListener('foo', $listener = function () {});
$listeners = $dispatcher->getListeners('foo');
$this->assertCount(1, $listeners);
$this->assertSame($listener, $listeners[0]);
@ -39,7 +39,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
$tdispatcher->addListener('foo', $listener = function () {; });
$tdispatcher->addListener('foo', $listener = function () {});
$this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo'));
}
@ -51,11 +51,28 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($dispatcher->hasListeners('foo'));
$this->assertFalse($tdispatcher->hasListeners('foo'));
$tdispatcher->addListener('foo', $listener = function () {; });
$tdispatcher->addListener('foo', $listener = function () {});
$this->assertTrue($dispatcher->hasListeners('foo'));
$this->assertTrue($tdispatcher->hasListeners('foo'));
}
public function testGetListenerPriority()
{
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
$tdispatcher->addListener('foo', function () {}, 123);
$listeners = $dispatcher->getListeners('foo');
$this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
// Verify that priority is preserved when listener is removed and re-added
// in preProcess() and postProcess().
$tdispatcher->dispatch('foo', new Event());
$listeners = $dispatcher->getListeners('foo');
$this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
}
public function testAddRemoveSubscriber()
{
$dispatcher = new EventDispatcher();
@ -76,14 +93,14 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
{
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
$tdispatcher->addListener('foo', $listener = function () {; });
$tdispatcher->addListener('foo', $listener = function () {});
$this->assertEquals(array(), $tdispatcher->getCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => 0)), $tdispatcher->getNotCalledListeners());
$tdispatcher->dispatch('foo');
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => null)), $tdispatcher->getCalledListeners());
$this->assertEquals(array(), $tdispatcher->getNotCalledListeners());
}
@ -107,8 +124,8 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
$tdispatcher->addListener('foo', $listener1 = function () {; });
$tdispatcher->addListener('foo', $listener2 = function () {; });
$tdispatcher->addListener('foo', $listener1 = function () {});
$tdispatcher->addListener('foo', $listener2 = function () {});
$logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".');
$logger->expects($this->at(1))->method('debug')->with('Notified event "foo" to listener "closure".');
@ -123,7 +140,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
$tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); });
$tdispatcher->addListener('foo', $listener2 = function () {; });
$tdispatcher->addListener('foo', $listener2 = function () {});
$logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".');
$logger->expects($this->at(1))->method('debug')->with('Listener "closure" stopped propagation of the event "foo".');
@ -138,12 +155,12 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$dispatcher = new EventDispatcher();
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
$tdispatcher->addListener('foo', $listener1 = function () use (&$called) { $called[] = 'foo1'; });
$tdispatcher->addListener('foo', $listener2 = function () use (&$called) { $called[] = 'foo2'; });
$tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10);
$tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20);
$tdispatcher->dispatch('foo');
$this->assertEquals(array('foo1', 'foo2'), $called);
$this->assertSame(array('foo2', 'foo1'), $called);
}
public function testDispatchNested()

View file

@ -19,10 +19,10 @@
"php": ">=5.3.9"
},
"require-dev": {
"symfony/dependency-injection": "~2.6",
"symfony/expression-language": "~2.6",
"symfony/config": "~2.0,>=2.0.5",
"symfony/stopwatch": "~2.3",
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/config": "~2.0,>=2.0.5|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0",
"psr/log": "~1.0"
},
"suggest": {
@ -30,12 +30,15 @@
"symfony/http-kernel": ""
},
"autoload": {
"psr-4": { "Symfony\\Component\\EventDispatcher\\": "" }
"psr-4": { "Symfony\\Component\\EventDispatcher\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.8-dev"
}
}
}