mirror of
https://github.com/marcostoll/FF.git
synced 2025-03-21 15:40:00 +01:00
[FEATURE] add events and the event broker
This commit is contained in:
parent
3b0ad843ff
commit
588a41abfe
70
src/Events/AbstractEvent.php
Normal file
70
src/Events/AbstractEvent.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of AbstractEvent
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Events;
|
||||
|
||||
use FF\Factories\ClassLocators\ClassIdentifierAwareInterface;
|
||||
|
||||
/**
|
||||
* Class AbstractEvent
|
||||
*
|
||||
* @package FF\Events
|
||||
*/
|
||||
abstract class AbstractEvent implements ClassIdentifierAwareInterface
|
||||
{
|
||||
/**
|
||||
* For use with the BaseNamespaceClassLocator of the EventsFactory
|
||||
*/
|
||||
const COMMON_NS_SUFFIX = 'Events';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isCanceled = false;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCanceled(): bool
|
||||
{
|
||||
return $this->isCanceled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isCanceled
|
||||
* @return $this
|
||||
*/
|
||||
public function setIsCanceled(bool $isCanceled)
|
||||
{
|
||||
$this->isCanceled = $isCanceled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
return $this->setIsCanceled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getClassIdentifier(): string
|
||||
{
|
||||
$className = get_called_class();
|
||||
$needle = '\\' . self::COMMON_NS_SUFFIX . '\\';
|
||||
$pos = strpos($className, $needle);
|
||||
if ($pos === false) return $className;
|
||||
|
||||
return substr($className, $pos + strlen($needle));
|
||||
}
|
||||
}
|
244
src/Services/EventBroker.php
Normal file
244
src/Services/EventBroker.php
Normal file
@ -0,0 +1,244 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of EventBroker
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services;
|
||||
|
||||
use FF\DataStructures\IndexedCollection;
|
||||
use FF\DataStructures\OrderedCollection;
|
||||
use FF\Events\AbstractEvent;
|
||||
use FF\Factories\Exceptions\ClassNotFoundException;
|
||||
use FF\Services\Factories\EventsFactory;
|
||||
|
||||
/**
|
||||
* Class EventBroker
|
||||
*
|
||||
* @package FF\Services
|
||||
*/
|
||||
class EventBroker extends AbstractService
|
||||
{
|
||||
/**
|
||||
* @var IndexedCollection
|
||||
*/
|
||||
protected $subscriptions;
|
||||
|
||||
/**
|
||||
* @var EventsFactory
|
||||
*/
|
||||
protected $eventsFactory;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function initialize(array $options)
|
||||
{
|
||||
parent::initialize($options);
|
||||
|
||||
$this->subscriptions = new IndexedCollection();
|
||||
$this->eventsFactory = EventsFactory::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EventsFactory
|
||||
*/
|
||||
public function getEventsFactory(): EventsFactory
|
||||
{
|
||||
return $this->eventsFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IndexedCollection
|
||||
*/
|
||||
public function getSubscriptions(): IndexedCollection
|
||||
{
|
||||
return $this->subscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $classIdentifier
|
||||
* @return OrderedCollection
|
||||
*/
|
||||
public function getSubscribers(string $classIdentifier): OrderedCollection
|
||||
{
|
||||
$this->initializeSubscribersCollection($classIdentifier);
|
||||
return $this->subscriptions->get($classIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a listener to the subscribers list of an event
|
||||
*
|
||||
* Removes any previous subscriptions of the listener first to the named event.
|
||||
*
|
||||
* @param callable $listener
|
||||
* @param string $classIdentifier
|
||||
* @return $this
|
||||
*/
|
||||
public function subscribe(callable $listener, string $classIdentifier)
|
||||
{
|
||||
$this->unsubscribe($listener, $classIdentifier);
|
||||
$this->initializeSubscribersCollection($classIdentifier);
|
||||
|
||||
$this->subscriptions->get($classIdentifier)->push($listener);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a listener to the subscriber list of an event
|
||||
*
|
||||
* Removes any previous subscriptions of the listener first to the named event.
|
||||
*
|
||||
* @param callable $listener
|
||||
* @param string $classIdentifier
|
||||
* @return $this
|
||||
*/
|
||||
public function subscribeFirst(callable $listener, string $classIdentifier)
|
||||
{
|
||||
$this->unsubscribe($listener, $classIdentifier);
|
||||
$this->initializeSubscribersCollection($classIdentifier);
|
||||
|
||||
$this->subscriptions->get($classIdentifier)->unshift($listener);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes a listener
|
||||
*
|
||||
* If $name is omitted, the listener will be unsubscribed from each event it was subscribed to.
|
||||
*
|
||||
* @param callable $listener
|
||||
* @param string $classIdentifier
|
||||
* @return $this
|
||||
*/
|
||||
public function unsubscribe(callable $listener, string $classIdentifier = null)
|
||||
{
|
||||
/** @var OrderedCollection $listenerCollection */
|
||||
foreach ($this->subscriptions as $name => $listenerCollection) {
|
||||
if (!is_null($classIdentifier) && $classIdentifier != $name) continue;
|
||||
|
||||
$index = $listenerCollection->search($listener, true);
|
||||
if (is_null($index)) continue;
|
||||
|
||||
// remove listener from event
|
||||
unset($listenerCollection[$index]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all subscriptions for this event
|
||||
*
|
||||
* @param string $classIdentifier
|
||||
* @return $this
|
||||
*/
|
||||
public function unsubscribeAll(string $classIdentifier)
|
||||
{
|
||||
unset($this->subscriptions[$classIdentifier]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any listeners where subscribed to the named event
|
||||
*
|
||||
* @param string $classIdentifier
|
||||
* @return bool
|
||||
*/
|
||||
public function hasSubscribers(string $classIdentifier): bool
|
||||
{
|
||||
return $this->subscriptions->has($classIdentifier) && !$this->subscriptions->get($classIdentifier)->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks of the listener has been subscribed to the given event
|
||||
*
|
||||
* @param callable $listener
|
||||
* @param string $classIdentifier
|
||||
* @return bool
|
||||
*/
|
||||
public function isSubscribed(callable $listener, string $classIdentifier): bool
|
||||
{
|
||||
if (!$this->hasSubscribers($classIdentifier)) return false;
|
||||
|
||||
return !is_null($this->subscriptions->get($classIdentifier)->search($listener));
|
||||
}
|
||||
|
||||
/**Notifies all listeners of events of the given type
|
||||
*
|
||||
* Listeners will be notified in the order of their subscriptions.
|
||||
* Does nothing if no listeners subscribed to the type of the event.
|
||||
*
|
||||
* Creates an event instance and fires it.
|
||||
* Does nothing if no suitable event model could be created.
|
||||
*
|
||||
* Any given $args will be passed to the constructor of the suitable event
|
||||
* model class in the given order.
|
||||
*
|
||||
* @param string $classIdentifier
|
||||
* @param mixed ...$args
|
||||
* @return $this
|
||||
*/
|
||||
public function fire(string $classIdentifier, ...$args)
|
||||
{
|
||||
$event = $this->createEvent($classIdentifier, ...$args);
|
||||
if (is_null($event)) return $this;
|
||||
|
||||
foreach ($this->getSubscribers($classIdentifier) as $listener) {
|
||||
$this->notify($listener, $event);
|
||||
|
||||
if ($event->isCanceled()) {
|
||||
// stop notifying further listeners if event has been canceled
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize listener collection if necessary
|
||||
*
|
||||
* @param string $classIdentifier
|
||||
*/
|
||||
protected function initializeSubscribersCollection(string $classIdentifier)
|
||||
{
|
||||
if ($this->subscriptions->has($classIdentifier)) return;
|
||||
|
||||
$this->subscriptions->set($classIdentifier, new OrderedCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fresh event instance
|
||||
*
|
||||
* @param string $classIdentifier
|
||||
* @param mixed ...$args
|
||||
* @return AbstractEvent|null
|
||||
*/
|
||||
protected function createEvent(string $classIdentifier, ...$args): ?AbstractEvent
|
||||
{
|
||||
try {
|
||||
return $this->eventsFactory->create($classIdentifier, ...$args);
|
||||
} catch (ClassNotFoundException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes the event to the listener
|
||||
*
|
||||
* The listener will be invoked with the event as the first and only argument.
|
||||
* Any return values of the listener will be discarded.
|
||||
*
|
||||
* @param callable $listener
|
||||
* @param AbstractEvent $event
|
||||
*/
|
||||
protected function notify(callable $listener, AbstractEvent $event)
|
||||
{
|
||||
call_user_func($listener, $event);
|
||||
}
|
||||
}
|
82
src/Services/Factories/EventsFactory.php
Normal file
82
src/Services/Factories/EventsFactory.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of EventsFactory
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services\Factories;
|
||||
|
||||
use FF\Events\AbstractEvent;
|
||||
use FF\Factories\AbstractFactory;
|
||||
use FF\Factories\ClassLocators\BaseNamespaceClassLocator;
|
||||
use FF\Factories\ClassLocators\ClassLocatorInterface;
|
||||
|
||||
/**
|
||||
* Class EventsFactory
|
||||
*
|
||||
* @package FF\Services\Factories
|
||||
*/
|
||||
class EventsFactory extends AbstractFactory
|
||||
{
|
||||
/**
|
||||
* @var EventsFactory
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* Declared protected to prevent external usage.
|
||||
* Uses a BaseNamespaceClassLocator pre-configured with the 'Events' as common suffix and the FF namespace.
|
||||
*
|
||||
* @see \FF\Factories\ClassLocators\BaseNamespaceClassLocator
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
parent::__construct(new BaseNamespaceClassLocator(AbstractEvent::COMMON_NS_SUFFIX, 'FF'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Declared protected to prevent external usage
|
||||
*/
|
||||
protected function __clone()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @return BaseNamespaceClassLocator
|
||||
*/
|
||||
public function getClassLocator(): ClassLocatorInterface
|
||||
{
|
||||
return parent::getClassLocator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the singleton instance of this class
|
||||
*
|
||||
* @return EventsFactory
|
||||
*/
|
||||
public static function getInstance(): EventsFactory
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new EventsFactory();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return AbstractEvent
|
||||
*/
|
||||
public function create(string $classIdentifier, ...$args)
|
||||
{
|
||||
/** @var AbstractEvent $event */
|
||||
$event = parent::create($classIdentifier, ...$args);
|
||||
return $event;
|
||||
}
|
||||
}
|
45
src/Services/Traits/EventEmitterTrait.php
Normal file
45
src/Services/Traits/EventEmitterTrait.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of EventEmitterTrait
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services\Traits;
|
||||
|
||||
use FF\Services\EventBroker;
|
||||
use FF\Services\Factories\SF;
|
||||
|
||||
/**
|
||||
* Trait EventEmitterTrait
|
||||
*
|
||||
* @package FF\Services\Traits
|
||||
*/
|
||||
trait EventEmitterTrait
|
||||
{
|
||||
/**
|
||||
* Creates an event instance and fires it
|
||||
*
|
||||
* Delegates the execution to the EventBroker provided by the ServiceFactory.
|
||||
*
|
||||
* @param string $classIdentifier
|
||||
* @param mixed ...$args
|
||||
* @return $this
|
||||
*/
|
||||
protected function fire(string $classIdentifier, ...$args)
|
||||
{
|
||||
/** @var EventBroker $eventBroker */
|
||||
static $eventBroker = null;
|
||||
|
||||
if (is_null($eventBroker)) {
|
||||
$eventBroker = SF::i()->get('EventBroker');
|
||||
}
|
||||
|
||||
$eventBroker->fire($classIdentifier, ...$args);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
68
tests/Events/AbstractEventTest.php
Normal file
68
tests/Events/AbstractEventTest.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of AbstractEventTest
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Tests\Events;
|
||||
|
||||
use FF\Events\AbstractEvent;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test AbstractEventTest
|
||||
*
|
||||
* @package FF\Tests
|
||||
*/
|
||||
class AbstractEventTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MyEvent
|
||||
*/
|
||||
protected $uut;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->uut = new MyEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSetGetIsCanceled()
|
||||
{
|
||||
$same = $this->uut->setIsCanceled(true);
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertTrue($this->uut->isCanceled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testCancel()
|
||||
{
|
||||
$same = $this->uut->cancel();
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertTrue($this->uut->isCanceled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testGetClassIdentifier()
|
||||
{
|
||||
$this->assertEquals('MyEvent', MyEvent::getClassIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
class MyEvent extends AbstractEvent
|
||||
{
|
||||
|
||||
}
|
287
tests/Services/EventBrokerTest.php
Normal file
287
tests/Services/EventBrokerTest.php
Normal file
@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of EventBrokerTest
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Tests\Services {
|
||||
|
||||
use FF\DataStructures\IndexedCollection;
|
||||
use FF\DataStructures\OrderedCollection;
|
||||
use FF\Services\EventBroker;
|
||||
use FF\Services\Factories\EventsFactory;
|
||||
use FF\Tests\Services\Events\EventA;
|
||||
use FF\Tests\Services\Events\EventB;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test EventBrokerTest
|
||||
*
|
||||
* @package FF\Tests
|
||||
*/
|
||||
class EventBrokerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var EventBroker
|
||||
*/
|
||||
protected $uut;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->uut = new EventBroker();
|
||||
$this->uut->getEventsFactory()
|
||||
->getClassLocator()
|
||||
->prependNamespaces(__NAMESPACE__);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->uut->unsubscribeAll('EventA');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testGetEventsFactory()
|
||||
{
|
||||
$this->assertInstanceOf(EventsFactory::class, $this->uut->getEventsFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testGetSubscriptions()
|
||||
{
|
||||
$this->assertInstanceOf(IndexedCollection::class, $this->uut->getSubscriptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testGetSubscribers()
|
||||
{
|
||||
$this->assertInstanceOf(OrderedCollection::class, $this->uut->getSubscribers('EventA'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSubscribe()
|
||||
{
|
||||
$callback = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$same = $this->uut->subscribe($callback, 'EventA');
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertEquals(1, count($this->uut->getSubscribers('EventA')));
|
||||
$this->assertSame($callback, $this->uut->getSubscribers('EventA')->getFirst());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSubscribeRepeated()
|
||||
{
|
||||
$callback = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$this->uut->subscribe($callback, 'EventA')->subscribe($callback, 'EventA');
|
||||
$this->assertEquals(1, count($this->uut->getSubscribers('EventA')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSubscribeAppend()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
$callback2 = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$this->uut->subscribe($callback1, 'EventA')
|
||||
->subscribe($callback2, 'EventA');
|
||||
$this->assertSame($callback1, $this->uut->getSubscribers('EventA')->get(0));
|
||||
$this->assertSame($callback2, $this->uut->getSubscribers('EventA')->get(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSubscribeFirst()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
$callback2 = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$same = $this->uut->subscribe($callback1, 'EventA')
|
||||
->subscribeFirst($callback2, 'EventA');
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertSame($callback1, $this->uut->getSubscribers('EventA')->get(1));
|
||||
$this->assertSame($callback2, $this->uut->getSubscribers('EventA')->get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testUnsubscribe()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$this->uut->subscribe($callback1, 'EventA')
|
||||
->subscribe($callback1, 'EventB')
|
||||
->unsubscribe($callback1);
|
||||
$this->assertTrue($this->uut->getSubscribers('EventA')->isEmpty());
|
||||
$this->assertTrue($this->uut->getSubscribers('EventB')->isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testUnsubscribeNamed()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
$callback2 = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$same = $this->uut->subscribe($callback1, 'EventA')
|
||||
->subscribe($callback2, 'EventA')
|
||||
->unsubscribe($callback1, 'EventA');
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertEquals(1, count($this->uut->getSubscribers('EventA')));
|
||||
$this->assertSame($callback2, $this->uut->getSubscribers('EventA')->get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testUnsubscribeAll()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
$callback2 = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$same = $this->uut->subscribe($callback1, 'EventA')
|
||||
->subscribe($callback2, 'EventA')
|
||||
->unsubscribeAll('EventA');
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertTrue($this->uut->getSubscribers('EventA')->isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testHasSubscribers()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
|
||||
$this->uut->subscribe($callback1, 'EventA');
|
||||
|
||||
$this->assertTrue($this->uut->hasSubscribers('EventA'));
|
||||
$this->assertFalse($this->uut->hasSubscribers('EventB'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testIsSubscribed()
|
||||
{
|
||||
$callback1 = [new ListenerA(), 'shoutA'];
|
||||
$callback2 = [new ListenerA(), 'shoutB'];
|
||||
|
||||
$this->uut->subscribe($callback1, 'EventA');
|
||||
|
||||
$this->assertTrue($this->uut->isSubscribed($callback1, 'EventA'));
|
||||
$this->assertFalse($this->uut->isSubscribed($callback1, 'EventB'));
|
||||
$this->assertFalse($this->uut->isSubscribed($callback2, 'EventA'));
|
||||
$this->assertFalse($this->uut->isSubscribed($callback2, 'EventB'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testFire()
|
||||
{
|
||||
$same = $this->uut->fire('EventA', 'foo');
|
||||
$this->assertSame($this->uut, $same);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testFireWithListener()
|
||||
{
|
||||
$this->expectOutputString('foo');
|
||||
|
||||
$this->uut->subscribe([new ListenerA(), 'shoutA'], 'EventA')
|
||||
->fire('EventA', 'foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testFireCancel()
|
||||
{
|
||||
$this->expectOutputString('foo'); // output would be 'foofoo' if event canceling does not work
|
||||
|
||||
$this->uut->subscribe([new ListenerA(), 'cancelA'], 'EventA')
|
||||
->subscribe([new ListenerB(), 'neverToReach'], 'EventA')
|
||||
->fire('EventA', 'foo');
|
||||
}
|
||||
}
|
||||
|
||||
class ListenerA
|
||||
{
|
||||
public function shoutA(EventA $event)
|
||||
{
|
||||
print $event->content;
|
||||
}
|
||||
|
||||
public function shoutB(EventB $event)
|
||||
{
|
||||
print $event->content;
|
||||
}
|
||||
|
||||
public function cancelA(EventA $event)
|
||||
{
|
||||
print $event->content;
|
||||
$event->cancel();
|
||||
}
|
||||
}
|
||||
|
||||
class ListenerB extends ListenerA
|
||||
{
|
||||
public function shoutB(EventB $event)
|
||||
{
|
||||
print $event->content;
|
||||
}
|
||||
|
||||
public function neverToReach(EventA $event)
|
||||
{
|
||||
print $event->content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FF\Tests\Services\Events {
|
||||
|
||||
use FF\Events\AbstractEvent;
|
||||
|
||||
class EventA extends AbstractEvent
|
||||
{
|
||||
public $content;
|
||||
|
||||
public function __construct(string $content)
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
}
|
||||
|
||||
class EventB extends EventA
|
||||
{
|
||||
|
||||
}
|
||||
}
|
41
tests/Services/Factories/EventsFactoryTest.php
Normal file
41
tests/Services/Factories/EventsFactoryTest.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of EventsFactoryTest
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Tests\Services\Factories;
|
||||
|
||||
use FF\Factories\ClassLocators\BaseNamespaceClassLocator;
|
||||
use FF\Services\Factories\EventsFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test EventsFactoryTest
|
||||
*
|
||||
* @package FF\Tests
|
||||
*/
|
||||
class EventsFactoryTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testGetInstance()
|
||||
{
|
||||
$instance = EventsFactory::getInstance();
|
||||
$this->assertInstanceOf(EventsFactory::class, $instance);
|
||||
$this->assertSame($instance, EventsFactory::getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testGetClassLocator()
|
||||
{
|
||||
$this->assertInstanceOf(BaseNamespaceClassLocator::class, EventsFactory::getInstance()->getClassLocator());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user