Skip to content

Commit

Permalink
Добавлены AttachDispatcherInterface, SubcriberInterface
Browse files Browse the repository at this point in the history
  • Loading branch information
remils committed Oct 29, 2023
1 parent d0d1eac commit b463e05
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 25 deletions.
89 changes: 79 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,119 @@
```php
<?php

use Remils\EventListener\AttachDispatcherInterface;
use Remils\EventListener\Dispatcher;
use Remils\EventListener\EventInterface;
use Remils\EventListener\ListenerInterface;
use Remils\EventListener\SubscriberInterface;

require './vendor/autoload.php';

class Entity
{
public string $name;
public int $age;
}

class CreateEntityEvent implements EventInterface
class SetAgeEntityEvent implements EventInterface
{
public int $age;
}

class SetNameEntityEvent implements EventInterface
{
public string $name;
}

class CreateEntityListener implements ListenerInterface
class SendEntityEvent implements EventInterface
{
}

class ResponseEntityEvent implements EventInterface
{
public Entity $entity;
}

class EntitySubscriber implements SubscriberInterface, AttachDispatcherInterface
{
protected Dispatcher $dispatcher;

protected Entity $entity;

public function __construct()
{
$this->entity = new Entity();
}

public function setDispatcher(Dispatcher $dispatcher): void
{
$this->dispatcher = $dispatcher;
}

public function getSubscribedEvents(): array
{
return [
SetAgeEntityEvent::class => 'setAge',
SetNameEntityEvent::class => 'setName',
SendEntityEvent::class => 'sendEntity',
];
}

public function setAge(SetAgeEntityEvent $event): void
{
$this->entity->age = $event->age;
}

public function setName(SetNameEntityEvent $event): void
{
$this->entity->name = $event->name;
}

public function sendEntity(SendEntityEvent $event): void
{
$event = new ResponseEntityEvent();
$event->entity = $this->entity;

$this->dispatcher->dispatch($event);
}
}

class ResponseEntityListener implements ListenerInterface
{
public function getEventNamespace(): string
{
return CreateEntityEvent::class;
return ResponseEntityEvent::class;
}

/**
* @param CreateEntityEvent $event
* @param ResponseEntityEvent $event
* @return void
*/
public function handle(EventInterface $event): void
{
$entity = new Entity();
$entity->name = $event->name;

var_dump($entity);
var_dump($event->entity);
}
}

$listeners = [
new CreateEntityListener(),
new EntitySubscriber(),
new ResponseEntityListener(),
];

$dispatcher = new Dispatcher($listeners);

$event = new CreateEntityEvent();
$event = new SetAgeEntityEvent();
$event->age = 64;

$dispatcher->dispatch($event);

$event = new SetNameEntityEvent();
$event->name = 'Анатолий';

$dispatcher->dispatch($event);

$event = new SendEntityEvent();

$dispatcher->dispatch($event);

```
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "remils/event-listener",
"type": "library",
"version": "1.0.0",
"version": "1.1.0",
"description": "Слушатель событий",
"keywords": [
"event",
Expand Down
12 changes: 6 additions & 6 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions src/AttachDispatcherInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Remils\EventListener;

interface AttachDispatcherInterface
{
/**
* Добавляет диспетчер в класс слушателя/подписчика
*
* @param Dispatcher $dispatcher
* @return void
*/
public function setDispatcher(Dispatcher $dispatcher): void;
}
46 changes: 38 additions & 8 deletions src/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
final class Dispatcher
{
/**
* @param ListenerInterface[] $listeners
* @param array<ListenerInterface|SubscriberInterface> $handlers
*/
public function __construct(
protected array $listeners = [],
protected array $handlers = [],
) {
}

Expand All @@ -20,19 +20,49 @@ public function __construct(
*/
public function dispatch(EventInterface $event): void
{
foreach ($this->listeners as $listener) {
if (!$listener instanceof ListenerInterface) {
foreach ($this->handlers as $handler) {
$isListener = is_a($handler, ListenerInterface::class);
$isSubscriber = is_a($handler, SubscriberInterface::class);

if (
$isListener === false
&& $isSubscriber === false
) {
throw new ListenerException(
message: sprintf(
'Слушатель %s не реализует интерфейс %s.',
$listener::class,
'Класс %s должен реализовать интерфейс %s, либо %s.',
$handler::class,
ListenerInterface::class,
SubscriberInterface::class,
),
);
}

if ($listener->getEventNamespace() === $event::class) {
$listener->handle($event);
if (is_a($handler, AttachDispatcherInterface::class)) {
/**
* @var AttachDispatcherInterface $handler
*/
$handler->setDispatcher($this);
}

if ($isListener && is_a($event, $handler->getEventNamespace())) {
/**
* @var ListenerInterface $handler
*/
$handler->handle($event);
}

if ($isSubscriber) {
/**
* @var SubscriberInterface $handler
*/
$eventNamespaces = $handler->getSubscribedEvents();

foreach ($eventNamespaces as $eventNamespace => $method) {
if (is_a($event, $eventNamespace)) {
call_user_func([$handler, $method], $event);
}
}
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions src/SubscriberInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Remils\EventListener;

interface SubscriberInterface
{
/**
* Должен возвращать список событий привязанных к методу.
*
* Пример:
*
* @code
* return [
* Event1::class => 'nameMethod1',
* Event2::class => 'nameMethod2',
* EventN::class => 'nameMethodN'
* ];
* @endcode
*
* @return array<string,string>
*/
public function getSubscribedEvents(): array;
}

0 comments on commit b463e05

Please sign in to comment.