From c4429c342401703188f0d949b5302e8011691b38 Mon Sep 17 00:00:00 2001
From: Stanislau Komar <stanislau_komar@epam.com>
Date: Fri, 25 Nov 2022 20:55:46 +0400
Subject: [PATCH] v1.1 release

---
 composer.json                                 |  6 +-
 src/Business/Factory/EventEmitterFactory.php  | 33 ++++++++++
 .../Locator/EventListenerClassLocator.php     | 32 ++++++++++
 .../EventListenerClassLocatorFactory.php      | 27 ++++++++
 ...ntListenerClassLocatorFactoryInterface.php | 11 ++++
 .../EventListenerClassLocatorInterface.php    | 13 ++++
 .../Provider/ApplicationListenerProvider.php  | 61 +++++++++++++++++++
 src/Business/Provider/ProviderFactory.php     | 48 +++++++++++++++
 .../Provider/ProviderFactoryInterface.php     | 13 ++++
 src/EventEmitterPlugin.php                    | 57 +++++++++++++++--
 10 files changed, 294 insertions(+), 7 deletions(-)
 create mode 100644 src/Business/Factory/EventEmitterFactory.php
 create mode 100644 src/Business/Locator/EventListenerClassLocator.php
 create mode 100644 src/Business/Locator/EventListenerClassLocatorFactory.php
 create mode 100644 src/Business/Locator/EventListenerClassLocatorFactoryInterface.php
 create mode 100644 src/Business/Locator/EventListenerClassLocatorInterface.php
 create mode 100644 src/Business/Provider/ApplicationListenerProvider.php
 create mode 100644 src/Business/Provider/ProviderFactory.php
 create mode 100644 src/Business/Provider/ProviderFactoryInterface.php

diff --git a/composer.json b/composer.json
index b876be0..ee3e380 100755
--- a/composer.json
+++ b/composer.json
@@ -3,7 +3,7 @@
     "description": "Micro Framework: Application plugin to provide an event emitter",
     "type": "library",
     "license": "MIT",
-    "version": "1.0",
+    "version": "1.1",
     "autoload": {
         "psr-4": {
             "Micro\\Plugin\\EventEmitter\\": "src/"
@@ -17,6 +17,8 @@
     ],
     "require": {
         "micro/event-emitter": "^1",
-        "micro/kernel": "^1"
+        "micro/plugin-locator": "^1",
+        "micro/kernel": "^1",
+        "micro/autowire": "^1"
     }
 }
diff --git a/src/Business/Factory/EventEmitterFactory.php b/src/Business/Factory/EventEmitterFactory.php
new file mode 100644
index 0000000..2d310e2
--- /dev/null
+++ b/src/Business/Factory/EventEmitterFactory.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Factory;
+
+use Micro\Component\EventEmitter\EventEmitterInterface;
+use Micro\Component\EventEmitter\EventEmitterFactory as BaseEventEmitterFactory;
+use Micro\Plugin\EventEmitter\Business\Provider\ProviderFactoryInterface;
+
+class EventEmitterFactory extends BaseEventEmitterFactory
+{
+    /**
+     * @param ProviderFactoryInterface $providerFactoryInterface
+     */
+    public function __construct(
+        private readonly ProviderFactoryInterface $providerFactoryInterface
+    )
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function create(): EventEmitterInterface
+    {
+        $emitter = parent::create();
+
+        $emitter->addListenerProvider(
+            $this->providerFactoryInterface->create()
+        );
+
+        return $emitter;
+    }
+}
\ No newline at end of file
diff --git a/src/Business/Locator/EventListenerClassLocator.php b/src/Business/Locator/EventListenerClassLocator.php
new file mode 100644
index 0000000..8569e5d
--- /dev/null
+++ b/src/Business/Locator/EventListenerClassLocator.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Locator;
+
+use Micro\Component\EventEmitter\EventListenerInterface;
+use Micro\Plugin\Locator\Facade\LocatorFacadeInterface;
+
+class EventListenerClassLocator implements EventListenerClassLocatorInterface
+{
+    /**
+     * @param LocatorFacadeInterface $locatorFacade
+     */
+    public function __construct(
+        private readonly LocatorFacadeInterface $locatorFacade
+    )
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function lookupListenerClasses(): iterable
+    {
+        $listenerClassCollection = [];
+
+        foreach ($this->locatorFacade->lookup(EventListenerInterface::class) as $listenerClass) {
+            $listenerClassCollection[] = $listenerClass;
+        }
+
+        return $listenerClassCollection;
+    }
+}
\ No newline at end of file
diff --git a/src/Business/Locator/EventListenerClassLocatorFactory.php b/src/Business/Locator/EventListenerClassLocatorFactory.php
new file mode 100644
index 0000000..b1a5db3
--- /dev/null
+++ b/src/Business/Locator/EventListenerClassLocatorFactory.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Locator;
+
+use Micro\Plugin\Locator\Facade\LocatorFacadeInterface;
+
+class EventListenerClassLocatorFactory implements EventListenerClassLocatorFactoryInterface
+{
+    /**
+     * @param LocatorFacadeInterface $locatorFacade
+     */
+    public function __construct(
+        private readonly LocatorFacadeInterface $locatorFacade
+    )
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function create(): EventListenerClassLocatorInterface
+    {
+        return new EventListenerClassLocator(
+            $this->locatorFacade,
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/Business/Locator/EventListenerClassLocatorFactoryInterface.php b/src/Business/Locator/EventListenerClassLocatorFactoryInterface.php
new file mode 100644
index 0000000..bd3346a
--- /dev/null
+++ b/src/Business/Locator/EventListenerClassLocatorFactoryInterface.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Locator;
+
+interface EventListenerClassLocatorFactoryInterface
+{
+    /**
+     * @return EventListenerClassLocatorInterface
+     */
+    public function create(): EventListenerClassLocatorInterface;
+}
\ No newline at end of file
diff --git a/src/Business/Locator/EventListenerClassLocatorInterface.php b/src/Business/Locator/EventListenerClassLocatorInterface.php
new file mode 100644
index 0000000..50983c5
--- /dev/null
+++ b/src/Business/Locator/EventListenerClassLocatorInterface.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Locator;
+
+use Micro\Component\EventEmitter\EventListenerInterface;
+
+interface EventListenerClassLocatorInterface
+{
+    /**
+     * @return iterable<class-string<EventListenerInterface>>
+     */
+    public function lookupListenerClasses(): iterable;
+}
\ No newline at end of file
diff --git a/src/Business/Provider/ApplicationListenerProvider.php b/src/Business/Provider/ApplicationListenerProvider.php
new file mode 100644
index 0000000..af31d18
--- /dev/null
+++ b/src/Business/Provider/ApplicationListenerProvider.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Provider;
+
+use Micro\Component\DependencyInjection\Autowire\AutowireHelperInterface;
+use Micro\Component\EventEmitter\EventInterface;
+use Micro\Component\EventEmitter\ListenerProviderInterface;
+
+class ApplicationListenerProvider implements ListenerProviderInterface
+{
+    /**
+     * @param AutowireHelperInterface $autowireHelper
+     * @param iterable $eventListenersClasses
+     */
+    public function __construct(
+        private readonly AutowireHelperInterface $autowireHelper,
+        private readonly iterable $eventListenersClasses,
+    )
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getListenersForEvent(EventInterface $event): iterable
+    {
+        foreach ($this->getEventListeners() as $listenerClass) {
+            if(!$listenerClass::supports($event)) {
+                continue;
+            }
+
+            $callback = $this->autowireHelper->autowire($listenerClass);
+
+            yield $callback();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __toString(): string
+    {
+        return $this->getName() ?? get_class($this);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getName(): string
+    {
+        return 'events.listener_provider.default';
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getEventListeners(): iterable
+    {
+        return $this->eventListenersClasses;
+    }
+}
\ No newline at end of file
diff --git a/src/Business/Provider/ProviderFactory.php b/src/Business/Provider/ProviderFactory.php
new file mode 100644
index 0000000..d4de22b
--- /dev/null
+++ b/src/Business/Provider/ProviderFactory.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Provider;
+
+use Micro\Component\DependencyInjection\Autowire\AutowireHelperFactoryInterface;
+use Micro\Component\DependencyInjection\Autowire\AutowireHelperInterface;
+use Micro\Component\EventEmitter\EventListenerInterface;
+use Micro\Component\EventEmitter\ListenerProviderInterface;
+use Micro\Plugin\EventEmitter\Business\Locator\EventListenerClassLocatorFactoryInterface;
+
+class ProviderFactory implements ProviderFactoryInterface
+{
+    /**
+     * @param AutowireHelperInterface $autowireHelper
+     * @param EventListenerClassLocatorFactoryInterface $eventListenerClassLocatorFactory
+     */
+    public function __construct(
+        private readonly AutowireHelperInterface $autowireHelper,
+        private readonly EventListenerClassLocatorFactoryInterface $eventListenerClassLocatorFactory
+    )
+    {
+    }
+
+    /**
+     *{@inheritDoc}
+     */
+    public function create(): ListenerProviderInterface
+    {
+        $listeners = $this->eventListenerClassLocatorFactory
+            ->create()
+            ->lookupListenerClasses();
+
+        return $this->createProvider($listeners);
+    }
+
+    /**
+     * @param iterable<class-string<EventListenerInterface>> $listeners
+     *
+     * @return ListenerProviderInterface
+     */
+    protected function createProvider(iterable $listeners): ListenerProviderInterface
+    {
+        return new ApplicationListenerProvider(
+            $this->autowireHelper,
+            $listeners
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/Business/Provider/ProviderFactoryInterface.php b/src/Business/Provider/ProviderFactoryInterface.php
new file mode 100644
index 0000000..aad8b51
--- /dev/null
+++ b/src/Business/Provider/ProviderFactoryInterface.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Micro\Plugin\EventEmitter\Business\Provider;
+
+use Micro\Component\EventEmitter\ListenerProviderInterface;
+
+interface ProviderFactoryInterface
+{
+    /**
+     * @return ListenerProviderInterface
+     */
+    public function create(): ListenerProviderInterface;
+}
\ No newline at end of file
diff --git a/src/EventEmitterPlugin.php b/src/EventEmitterPlugin.php
index 43099d5..f0105ee 100755
--- a/src/EventEmitterPlugin.php
+++ b/src/EventEmitterPlugin.php
@@ -2,20 +2,44 @@
 
 namespace Micro\Plugin\EventEmitter;
 
+use Micro\Component\DependencyInjection\Autowire\AutowireHelperFactory;
+use Micro\Component\DependencyInjection\Autowire\AutowireHelperFactoryInterface;
+use Micro\Component\DependencyInjection\Autowire\AutowireHelperInterface;
 use Micro\Component\DependencyInjection\Container;
-use Micro\Component\EventEmitter\EventEmitterFactory;
 use Micro\Component\EventEmitter\EventEmitterFactoryInterface;
-use Micro\Framework\Kernel\Plugin\AbstractPlugin;
+use Micro\Framework\Kernel\Plugin\DependencyProviderInterface;
 use Micro\Plugin\EventEmitter\Business\Facade\EventsFacade;
+use Micro\Plugin\EventEmitter\Business\Factory\EventEmitterFactory;
+use Micro\Plugin\EventEmitter\Business\Locator\EventListenerClassLocatorFactory;
+use Micro\Plugin\EventEmitter\Business\Locator\EventListenerClassLocatorFactoryInterface;
+use Micro\Plugin\EventEmitter\Business\Provider\ProviderFactory;
+use Micro\Plugin\EventEmitter\Business\Provider\ProviderFactoryInterface;
+use Micro\Plugin\Locator\Facade\LocatorFacadeInterface;
 
-class EventEmitterPlugin extends AbstractPlugin
+class EventEmitterPlugin implements DependencyProviderInterface
 {
+    /**
+     * @var LocatorFacadeInterface
+     */
+    private readonly LocatorFacadeInterface $locatorFacade;
+
+    /**
+     * @var AutowireHelperInterface $autowireHelper
+     */
+    private readonly AutowireHelperInterface $autowireHelper;
+
     /**
      * {@inheritDoc}
      */
     public function provideDependencies(Container $container): void
     {
-        $container->register(EventsFacadeInterface::class, function (Container $container) {
+        $container->register(EventsFacadeInterface::class, function (
+            AutowireHelperInterface $autowireHelper,
+            LocatorFacadeInterface $locatorFacade,
+        ) {
+            $this->locatorFacade = $locatorFacade;
+            $this->autowireHelper = $autowireHelper;
+
             return $this->createFacade();
         });
     }
@@ -33,6 +57,29 @@ protected function createFacade(): EventsFacadeInterface
      */
     protected function createEventEmitterFactory(): EventEmitterFactoryInterface
     {
-        return new EventEmitterFactory();
+        return new EventEmitterFactory(
+            $this->createProviderFactory()
+        );
+    }
+
+    /**
+     * @return ProviderFactoryInterface
+     */
+    protected function createProviderFactory(): ProviderFactoryInterface
+    {
+        return new ProviderFactory(
+            $this->autowireHelper,
+            $this->createEventListenerClassLocatorFactory(),
+        );
+    }
+
+    /**
+     * @return EventListenerClassLocatorFactoryInterface
+     */
+    protected function createEventListenerClassLocatorFactory(): EventListenerClassLocatorFactoryInterface
+    {
+        return new EventListenerClassLocatorFactory(
+            $this->locatorFacade
+        );
     }
 }