Skip to content

Commit 4a53d80

Browse files
author
Maxofil
committed
added src files
1 parent 0943b33 commit 4a53d80

File tree

7 files changed

+189
-0
lines changed

7 files changed

+189
-0
lines changed

composer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "infinityloop-dev/observer-component",
3+
"description": "Event system for Nette framework's component model.",
4+
"homepage": "https://www.infinityloop.dev/",
5+
"type": "library",
6+
"license": ["MIT"],
7+
"authors": [
8+
{
9+
"name": "Václav Pelíšek",
10+
"homepage": "https://www.peldax.com"
11+
}
12+
],
13+
"require": {
14+
"php": ">=7.4",
15+
"nette/application": "^3.0",
16+
"nette/caching": "^3.0"
17+
},
18+
"autoload": {
19+
"psr-4": {
20+
"Infinityloop\\": "src/"
21+
}
22+
}
23+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Infinityloop\ObserverComponent;
6+
7+
class EventMapper
8+
{
9+
private \Nette\Application\Application $application;
10+
private \Nette\Caching\IStorage $storage;
11+
private ?\Nette\Caching\Cache $eventMap = null;
12+
private bool $debugMode;
13+
14+
public function __construct(
15+
\Nette\Application\Application $application,
16+
\Nette\Caching\IStorage $storage
17+
)
18+
{
19+
$this->application = $application;
20+
$this->storage = $storage;
21+
$this->debugMode = \App\Bootstrap::isDebugMode();
22+
}
23+
24+
public function registerObserver(IObserverComponent $component) : void
25+
{
26+
$componentPath = $component->lookupPath(\Nette\Application\IPresenter::class);
27+
\assert(\is_string($componentPath));
28+
29+
if (!$this->debugMode && $this->isComponentRegistered($componentPath)) {
30+
return;
31+
}
32+
33+
foreach ($component::getObservedEvents() as $eventName) {
34+
\assert(\is_string($eventName) && \class_exists($eventName));
35+
36+
$observerList = $this->getObserverList($eventName);
37+
38+
if (\in_array($componentPath, $observerList, true)) {
39+
continue;
40+
}
41+
42+
$observerList[] = $componentPath;
43+
$this->getEventMap()->save($eventName, $observerList);
44+
45+
$registeredComponents = $this->getEventMap()->load('components') ?? [];
46+
$registeredComponents[] = $componentPath;
47+
$this->getEventMap()->save('components', $registeredComponents);
48+
}
49+
}
50+
51+
public function dispatchEvent(IEvent $event) : void
52+
{
53+
$presenter = $this->application->getPresenter();
54+
\assert($presenter instanceof \Nette\Application\UI\Control);
55+
56+
foreach ($this->getObserverList(\get_class($event)) as $observerPath) {
57+
\assert(\is_string($observerPath));
58+
59+
$observer = $presenter->getComponent($observerPath);
60+
\assert($observer instanceof IObserverComponent);
61+
62+
$observer->observableUpdated($event);
63+
}
64+
}
65+
66+
private function getObserverList(string $eventName) : array
67+
{
68+
return $this->getEventMap()->load($eventName) ?? [];
69+
}
70+
71+
private function isComponentRegistered(string $componentPath) : bool
72+
{
73+
$registeredComponents = $this->getEventMap()->load('components') ?? [];
74+
75+
return \in_array($componentPath, $registeredComponents, true);
76+
}
77+
78+
private function getEventMap() : \Nette\Caching\Cache
79+
{
80+
if (!$this->eventMap instanceof \Nette\Caching\Cache) {
81+
$applicationPath = \ltrim($this->application->getPresenter()->getAction(true), ':');
82+
$this->eventMap = new \Nette\Caching\Cache($this->storage, 'eventMapper-' . $applicationPath);
83+
}
84+
85+
return $this->eventMap;
86+
}
87+
}

src/ObserverComponent/IEvent.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Infinityloop\ObserverComponent;
6+
7+
interface IEvent
8+
{
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Infinityloop\ObserverComponent;
6+
7+
interface IObservable
8+
{
9+
public function injectEventMapperObservable(EventMapper $eventMapper) : void;
10+
11+
public function notifyObservers(IEvent $event) : void;
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Infinityloop\ObserverComponent;
6+
7+
interface IObserverComponent
8+
{
9+
public static function getObservedEvents() : array;
10+
11+
public function injectEventMapperObserver(EventMapper $eventMapper) : void;
12+
13+
public function observableUpdated(IEvent $event) : void;
14+
15+
public function lookupPath(?string $type = null, bool $throw = true) : ?string;
16+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Infinityloop\ObserverComponent;
6+
7+
trait TObservable
8+
{
9+
private EventMapper $eventMapper;
10+
11+
final public function injectEventMapperObservable(EventMapper $eventMapper) : void
12+
{
13+
$this->eventMapper = $eventMapper;
14+
}
15+
16+
public function notifyObservers(IEvent $event) : void
17+
{
18+
$this->eventMapper->dispatchEvent($event);
19+
}
20+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Infinityloop\ObserverComponent;
6+
7+
trait TObserverComponent
8+
{
9+
private EventMapper $eventMapper;
10+
11+
abstract public static function getObservedEvents() : array;
12+
13+
abstract public function observableUpdated(IEvent $event) : void;
14+
15+
final public function injectEventMapperObserver(EventMapper $eventMapper) : void
16+
{
17+
$this->eventMapper = $eventMapper;
18+
$this->onAnchor[] = function (\Nette\ComponentModel\IComponent $parent) : void {
19+
$this->eventMapper->registerObserver($this);
20+
};
21+
}
22+
}

0 commit comments

Comments
 (0)