20 Commits
Author SHA1 Message Date
Jeremy Mikola 19dc115e94 Alias dev-master as 1.1.x-dev 2016-09-14 15:37:00 -04:00
Jeremy Mikola 8d53f365b2 Merge pull request #7 2016-09-14 15:36:37 -04:00
Jeremy Mikola f8099a63f8 Add more platforms to Travis build matrix
This ensures we test against old and current Symfony versions
2016-09-09 15:42:24 -04:00
Jeremy Mikola fd3a84d57d Remove minimum-stability from composer.json
This only applies to root projects, and isn't necessary for testing.
2016-09-09 15:36:56 -04:00
Jeremy Mikola 8fcbe9f726 Remove extra whitespace in doc block 2016-09-09 15:31:27 -04:00
Jeremy Mikola 5472039e48 Throw exceptions for getListenerPriority() incompatibilities
For the time being, do not support wildcard patterns with getListenerPriority().

An exception will be thrown if getListenerPriority() is not implemented on the inner dispatcher. The method was added in https://github.com/symfony/symfony/pull/16198 for Symfony 2.8. It was added to the interface in Symfony 3.0, which is relevant for our test cases.
2016-09-09 15:27:43 -04:00
SpacePossum 2d68309b14 Use assertCount() and getMockBuilder() in tests
getMock() was deprecated in PHPUnit 5.4.0.
2016-09-09 15:09:13 -04:00
SpacePossum 83a285207b Use FQCN for InvalidArgumentException in doc block 2016-09-09 15:08:35 -04:00
SpacePossum 0300cbb1a5 Compatibility with Symfony 3.0 2016-09-09 14:49:16 -04:00
Jeremy Mikola 392eb3b559 Add installation notes to readme 2016-09-09 14:37:29 -04:00
Jeremy Mikola a688303be2 Simplify header syntax in readme 2016-09-09 14:36:46 -04:00
Jeremy Mikola 6af1e73df4 Remove "Symfony2" references in readme 2016-09-09 14:36:20 -04:00
Lars Strojny 62eb20340a Allow subscribing to multiple events like Symfony EventDispatcher does 2013-07-30 11:02:43 -04:00
Jeremy Mikola e6b272951d Allow compatibility with Symfony 2.x 2013-06-06 14:47:59 -04:00
Jeremy Mikola d96fe85d12 Allow for greater Symfony2 compatibility (2.0 through 2.2) 2013-02-26 14:21:37 -05:00
Jeremy Mikola 36fbd1c880 Add Travis CI testing 2013-02-26 13:56:14 -05:00
Jeremy Mikola 1996172dbe Update ignored files 2013-02-26 13:54:46 -05:00
Jeremy Mikola b7860e16b4 Merge pull request #3 from eriksencosta/composer-autoload-path-fix
Updated path to the Composer generated autoload file
2013-02-26 10:48:55 -08:00
Eriksen Costa ef8369f930 updated path to the Composer generated autoload file 2013-01-04 18:37:06 -02:00
Jeremy Mikola 282231d728 Add bundle link 2012-02-17 14:11:36 -05:00
10 changed files with 161 additions and 41 deletions
+1 -3
View File
@@ -1,5 +1,3 @@
composer.lock
phpunit.xml
vendor
composer.lock
composer.phar
+27
View File
@@ -0,0 +1,27 @@
language: php
sudo: false
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
matrix:
fast_finish: true
allow_failures:
- php: hhvm
- env: SYMFONY_VERSION=3.0.*
include:
- php: 5.3
env: COMPOSER_FLAGS="--prefer-lowest"
before_install:
- travis_retry composer self-update
install:
- composer update ${COMPOSER_FLAGS} --no-interaction
+29 -8
View File
@@ -1,16 +1,37 @@
# WildcardEventDispatcher
This library implements an event dispatcher, based on [Symfony2's interface][],
[![Build Status](https://travis-ci.org/jmikola/WildcardEventDispatcher.png?branch=master)](https://travis-ci.org/jmikola/WildcardEventDispatcher)
This library implements an event dispatcher, based on [Symfony's interface][],
with wildcard syntax inspired by AMQP topic exchanges. Listeners may be bound to
a wildcard pattern and be notified if a dispatched event's name matches that
pattern. Literal event name matching is still supported.
[Symfony2's interface]: https://github.com/symfony/EventDispatcher
If you are interested in using this library in a Symfony project, you may also
want to take a look at the corresponding [bundle][].
## Usage ##
[Symfony's interface]: https://github.com/symfony/EventDispatcher
[bundle]: https://github.com/jmikola/JmikolaWildcardEventDispatcherBundle
## Installation
The library is published as a [package][] and is installable via [Composer][]:
```
$ composer require jmikola/wildcard-event-dispatcher=~1.0
```
[package]: https://packagist.org/packages/jmikola/wildcard-event-dispatcher
[Composer]: http://getcomposer.org/
### Compatibility
This library requires Symfony 2.3 or above.
## Usage
WildcardEventDispatcher implements EventDispatcherInterface and may be used as
you would Symfony2's standard EventDispatcher:
you would Symfony's standard EventDispatcher:
```php
<?php
@@ -44,9 +65,9 @@ $dispatcher = new WildcardEventDispatcher(new EventDispatcher());
[composes]: http://en.wikipedia.org/wiki/Object_composition
## Wildcard Syntax ##
## Wildcard Syntax
### Single-word Wildcard ###
### Single-word Wildcard
Consider the scenario where the same listener is defined for multiple events,
all of which share a common prefix:
@@ -84,7 +105,7 @@ and followed by another word. The matching of `core` alone may not make sense,
but this is implemented in order to be consistent with AMQP. A trailing `*`
after a non-empty sequence may match the preceding sequence sans `.*`.
### Multi-word Wildcard ###
### Multi-word Wildcard
Suppose there was a `core` event in your application named `core.foo.bar`. The
aforementioned `core.*` pattern would not catch this event. You could use:
@@ -124,7 +145,7 @@ $dispatcher = new WildcardEventDispatcher();
$dispatcher->addListener('#', $allListener);
```
### Additional Wildcard Documentation ###
### Additional Wildcard Documentation
When in doubt, the unit tests for `ListenerPattern` are a good resource for
inferring how wildcards will be interpreted. This library aims to mimic the
+6 -1
View File
@@ -10,9 +10,14 @@
],
"require": {
"php": ">=5.3.2",
"symfony/event-dispatcher": ">=2.0-dev,<2.2-dev"
"symfony/event-dispatcher": "^2.3 || ^3.0"
},
"autoload": {
"psr-0": { "Jmikola": "src/" }
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
}
}
@@ -15,7 +15,7 @@ class LazyListenerPattern extends ListenerPattern
* @param string $eventPattern
* @param callback $listenerProvider
* @param integer $priority
* @throws InvalidArgumentException if the listener provider is not a callback
* @throws \InvalidArgumentException if the listener provider is not a callback
*/
public function __construct($eventPattern, $listenerProvider, $priority = 0)
{
@@ -16,7 +16,7 @@ class WildcardEventDispatcher implements EventDispatcherInterface
/**
* Constructor.
*
* If an EventDispatcherInterface is not provided , a new EventDispatcher
* If an EventDispatcherInterface is not provided, a new EventDispatcher
* will be composed.
*
* @param EventDispatcherInterface $dispatcher
@@ -92,10 +92,14 @@ class WildcardEventDispatcher implements EventDispatcherInterface
public function addSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
if (is_array($params)) {
$this->addListener($eventName, array($subscriber, $params[0]), $params[1]);
} else {
if (is_string($params)) {
$this->addListener($eventName, array($subscriber, $params));
} elseif (is_string($params[0])) {
$this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
} else {
foreach ($params as $listener) {
$this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
}
}
}
}
@@ -106,7 +110,13 @@ class WildcardEventDispatcher implements EventDispatcherInterface
public function removeSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
$this->removeListener($eventName, array($subscriber, is_array($params) ? $params[0] : $params));
if (is_array($params) && is_array($params[0])) {
foreach ($params as $listener) {
$this->removeListener($eventName, array($subscriber, $listener[0]));
}
} else {
$this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
}
}
}
@@ -185,4 +195,22 @@ class WildcardEventDispatcher implements EventDispatcherInterface
}
}
}
/**
* @see EventDispatcherInterface::getListenerPriority()
* @throws \InvalidArgumentException if $eventName contains a wildcard pattern
* @throws \BadMethodCallException if this method is not implemented on the composed EventDispatcher
*/
public function getListenerPriority($eventName, $listener)
{
if ($this->hasWildcards($eventName)) {
throw new \InvalidArgumentException('Wildcard patterns are not supported');
}
if ( ! method_exists($this->dispatcher, 'getListenerPriority')) {
throw new \BadMethodCallException('getListenerPriority() is not implemented');
}
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
}
@@ -86,6 +86,6 @@ class ListenerPatternTest extends \PHPUnit_Framework_TestCase
private function getMockEventDispatcher()
{
return $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
return $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
}
}
@@ -127,7 +127,7 @@ class WildcardEventDispatcherFunctionalTest extends \PHPUnit_Framework_TestCase
private function assertNumberListenersAdded($expected, $eventName = null)
{
return isset($eventName)
? $this->assertEquals($expected, count($this->dispatcher->getListeners($eventName)))
? $this->assertCount($expected, $this->dispatcher->getListeners($eventName))
: $this->assertEquals($expected, array_sum(array_map('count', $this->dispatcher->getListeners())));
}
}
@@ -115,32 +115,74 @@ class EventDispatcherTest extends \PHPUnit_Framework_TestCase
*/
$subscriber = new TestEventSubscriber();
$i = 0;
$defaultPriority = 0;
$numSubscribedEvents = count($subscriber->getSubscribedEvents());
$this->innerDispatcher->expects($this->at(0))
->method('addListener')
->with('core.request', array($subscriber, 'onRequest'), 0);
$this->innerDispatcher->expects($this->at(1))
->method('addListener')
->with('core.exception', array($subscriber, 'onException'), 10);
$this->innerDispatcher->expects($this->at(2))
->method('addListener')
->with('core.multi', array($subscriber, 'onMulti1'), 10);
$this->innerDispatcher->expects($this->at(3))
->method('addListener')
->with('core.multi', array($subscriber, 'onMulti2'), 20);
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
$method = is_array($params) ? $params[0] : $params;
$priority = is_array($params) ? $params[1] : $defaultPriority;
$this->innerDispatcher->expects($this->at(4))
->method('removeListener')
->with('core.request', array($subscriber, 'onRequest'));
$this->innerDispatcher->expects($this->at(5))
->method('removeListener')
->with('core.exception', array($subscriber, 'onException'));
$this->innerDispatcher->expects($this->at(6))
->method('removeListener')
->with('core.multi', array($subscriber, 'onMulti1'));
$this->innerDispatcher->expects($this->at(7))
->method('removeListener')
->with('core.multi', array($subscriber, 'onMulti2'));
$this->innerDispatcher->expects($this->at($i))
->method('addListener')
->with($eventName, array($subscriber, $method), $priority);
$this->innerDispatcher->expects($this->at($numSubscribedEvents + $i))
->method('removeListener')
->with($eventName, array($subscriber, $method));
$this->dispatcher->addSubscriber($subscriber);
$this->dispatcher->removeSubscriber($subscriber);
}
++$i;
public function testGetListenerPriorityInvokesMethodOnInnerDispather()
{
if ( ! method_exists('Symfony\Component\EventDispatcher\EventDispatcherInterface', 'getListenerPriority')) {
$this->markTestSkipped('getListenerPriority() does not exist on EventDispatcherInterface');
}
$this->dispatcher->addSubscriber($subscriber, $priority);
$this->dispatcher->removeSubscriber($subscriber, $priority);
$this->innerDispatcher->expects($this->once())
->method('getListenerPriority')
->with('core.request', 'callback')
->will($this->returnValue(1));
$this->assertSame(1, $this->dispatcher->getListenerPriority('core.request', 'callback'));
}
/**
* @expectedException InvalidArgumentException
*/
public function testGetListenerPriorityRequiresEventNameWithoutWildcards()
{
$this->dispatcher->getListenerPriority('core.*', 'callback');
}
/**
* @expectedException BadMethodCallException
*/
public function testGetListenerPriorityRequiresMethodOnInnerDispather()
{
if (method_exists('Symfony\Component\EventDispatcher\EventDispatcherInterface', 'getListenerPriority')) {
$this->markTestSkipped('getListenerPriority() exists on EventDispatcherInterface');
}
$this->dispatcher->getListenerPriority('core.request', 'callback');
}
private function getMockEventDispatcher()
{
return $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
return $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
}
}
@@ -151,6 +193,7 @@ class TestEventSubscriber implements EventSubscriberInterface
return array(
'core.request' => 'onRequest',
'core.exception' => array('onException', 10),
'core.multi' => array(array('onMulti1', 10), array('onMulti2', 20)),
);
}
}
+3 -5
View File
@@ -1,9 +1,7 @@
<?php
<?php
if (file_exists($file = __DIR__.'/../vendor/.composer/autoload.php')) {
$loader = require_once $file;
} else {
if (!is_file($autoloadFile = __DIR__.'/../vendor/autoload.php')) {
throw new RuntimeException('Install dependencies to run test suite.');
}
$loader->add('Jmikola\\WildcardEventDispatcher', __DIR__.'/../src');
require $autoloadFile;