Skip to content

Commit

Permalink
Merge pull request #1 from Maxofil/master
Browse files Browse the repository at this point in the history
added src files
  • Loading branch information
peldax authored Jun 24, 2020
2 parents 0943b33 + d2b53af commit e2a4770
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 0 deletions.
24 changes: 24 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "infinityloop-dev/observer-component",
"description": "Event system for Nette framework's component model.",
"homepage": "https://www.infinityloop.dev/",
"type": "library",
"license": ["MIT"],
"authors": [
{
"name": "Václav Pelíšek",
"homepage": "https://www.peldax.com"
}
],
"require": {
"php": ">=7.4",
"nette/application": "^3.0",
"nette/caching": "^3.0",
"nette/utils": "^3.0"
},
"autoload": {
"psr-4": {
"Infinityloop\\": "src/"
}
}
}
91 changes: 91 additions & 0 deletions src/ObserverComponent/EventMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

declare(strict_types = 1);

namespace Infinityloop\ObserverComponent;

final class EventMapper
{
use Nette\SmartObject;

private \Nette\Application\Application $application;
private \Nette\Caching\IStorage $storage;
private ?\Nette\Caching\Cache $eventMap = null;
private bool $debugMode;

public function __construct(
\Nette\Application\Application $application,
\Nette\Caching\IStorage $storage,
bool $debugMode = true
)
{
$this->application = $application;
$this->storage = $storage;
$this->debugMode = $debugMode;
}

public function registerObserver(IObserverComponent $component) : void
{
$componentPath = $component->lookupPath(\Nette\Application\IPresenter::class);
\assert(\is_string($componentPath));

if (!$this->debugMode && $this->isComponentRegistered($componentPath)) {
return;
}

foreach ($component::getObservedEvents() as $eventName) {
\assert(\is_string($eventName) && \class_exists($eventName));

$observerList = $this->getObserverList($eventName);

if (\in_array($componentPath, $observerList, true)) {
continue;
}

$observerList[] = $componentPath;
$this->getEventMap()->save($eventName, $observerList);

$registeredComponents = $this->getEventMap()->load('components') ?? [];
$registeredComponents[] = $componentPath;
$this->getEventMap()->save('components', $registeredComponents);
}
}

public function dispatchEvent(IEvent $event) : void
{
$presenter = $this->application->getPresenter();
\assert($presenter instanceof \Nette\Application\UI\Control);

foreach ($this->getObserverList(\get_class($event)) as $observerPath) {
\assert(\is_string($observerPath));

$observer = $presenter->getComponent($observerPath);
\assert($observer instanceof IObserverComponent);

$observer->observableUpdated($event);
}
}

private function getObserverList(string $eventName) : array
{
return $this->getEventMap()->load($eventName)
?? [];
}

private function isComponentRegistered(string $componentPath) : bool
{
$registeredComponents = $this->getEventMap()->load('components') ?? [];

return \in_array($componentPath, $registeredComponents, true);
}

private function getEventMap() : \Nette\Caching\Cache
{
if (!$this->eventMap instanceof \Nette\Caching\Cache) {
$applicationPath = \ltrim($this->application->getPresenter()->getAction(true), ':');
$this->eventMap = new \Nette\Caching\Cache($this->storage, 'eventMapper-' . $applicationPath);
}

return $this->eventMap;
}
}
9 changes: 9 additions & 0 deletions src/ObserverComponent/IEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types = 1);

namespace Infinityloop\ObserverComponent;

interface IEvent
{
}
12 changes: 12 additions & 0 deletions src/ObserverComponent/IObservable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types = 1);

namespace Infinityloop\ObserverComponent;

interface IObservable
{
public function injectEventMapperObservable(EventMapper $eventMapper) : void;

public function notifyObservers(IEvent $event) : void;
}
16 changes: 16 additions & 0 deletions src/ObserverComponent/IObserverComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types = 1);

namespace Infinityloop\ObserverComponent;

interface IObserverComponent
{
public static function getObservedEvents() : array;

public function injectEventMapperObserver(EventMapper $eventMapper) : void;

public function observableUpdated(IEvent $event) : void;

public function lookupPath(?string $type = null, bool $throw = true) : ?string;
}
20 changes: 20 additions & 0 deletions src/ObserverComponent/TObservable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types = 1);

namespace Infinityloop\ObserverComponent;

trait TObservable
{
private EventMapper $eventMapper;

final public function injectEventMapperObservable(EventMapper $eventMapper) : void
{
$this->eventMapper = $eventMapper;
}

public function notifyObservers(IEvent $event) : void
{
$this->eventMapper->dispatchEvent($event);
}
}
22 changes: 22 additions & 0 deletions src/ObserverComponent/TObserverComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types = 1);

namespace Infinityloop\ObserverComponent;

trait TObserverComponent
{
private EventMapper $eventMapper;

abstract public static function getObservedEvents() : array;

abstract public function observableUpdated(IEvent $event) : void;

final public function injectEventMapperObserver(EventMapper $eventMapper) : void
{
$this->eventMapper = $eventMapper;
$this->onAnchor[] = function (\Nette\ComponentModel\IComponent $parent) : void {
$this->eventMapper->registerObserver($this);
};
}
}

0 comments on commit e2a4770

Please sign in to comment.