From e6e9e6e102d2d50092885bf2830a77ec152a07a2 Mon Sep 17 00:00:00 2001 From: Vassyli Date: Fri, 7 Apr 2017 10:47:43 +0200 Subject: [PATCH] Added EventContextData containers. --- src/EventHandler.php | 1 + src/EventManager.php | 15 +++++- src/{ => Events}/EventContext.php | 17 +++++- src/Events/EventContextData.php | 14 +++++ .../EventContextDataContainer.php | 7 ++- src/Events/NavigateToScene.php | 53 +++++++++++++++++++ src/Events/NewViewpoint.php | 37 +++++++++++++ src/Game.php | 22 ++++---- src/Module.php | 12 ----- tests/EventManagerTest.php | 14 +++-- tests/FakeModule/Module.php | 6 ++- tests/GameTest.php | 49 ++++++++--------- 12 files changed, 187 insertions(+), 60 deletions(-) rename src/{ => Events}/EventContext.php (79%) create mode 100644 src/Events/EventContextData.php rename src/{ => Events}/EventContextDataContainer.php (95%) create mode 100644 src/Events/NavigateToScene.php create mode 100644 src/Events/NewViewpoint.php diff --git a/src/EventHandler.php b/src/EventHandler.php index ffac91f..1feaf6f 100644 --- a/src/EventHandler.php +++ b/src/EventHandler.php @@ -2,6 +2,7 @@ declare(strict_types=1); namespace LotGD\Core; +use LotGD\Core\Events\EventContext; interface EventHandler { diff --git a/src/EventManager.php b/src/EventManager.php index 3687b19..7bef581 100644 --- a/src/EventManager.php +++ b/src/EventManager.php @@ -5,11 +5,13 @@ namespace LotGD\Core; use Doctrine\ORM\EntityManagerInterface; +use LotGD\Core\Events\EventContext; use LotGD\Core\Models\EventSubscription; use LotGD\Core\EventHandler; use LotGD\Core\Exceptions\ClassNotFoundException; use LotGD\Core\Exceptions\SubscriptionNotFoundException; use LotGD\Core\Exceptions\WrongTypeException; +use LotGD\Core\Events\EventContextDataContainer; /** * Manages a simple publish/subscribe system based on regular expressions @@ -33,8 +35,9 @@ class EventManager * are run. * * @param string $event The name of the event to publish. + * @param EventContextDataContainer $contextData The Data context */ - public function publish(string $event, array &$context) + public function publish(string $event, EventContextDataContainer $contextData): EventContextDataContainer { // For right now, implement the naive approach of iterating every entry // in the subscription database, checking the regular expression. We @@ -49,9 +52,17 @@ class EventManager if (preg_match($s->getPattern(), $event)) { $class = $s->getClass(); $this->g->getLogger()->addDebug(" Handling with {$class}."); - $c = $class::handleEvent($this->g, $event, $context); + + $eventContext = new EventContext($event, $s->getPattern(), $contextData); + + $returnedEventContext = $class::handleEvent($this->g, $eventContext); + if ($returnedEventContext->hasDataChanged($contextData)) { + $contextData = $returnedEventContext->getData(); + } } } + + return $contextData; } /** diff --git a/src/EventContext.php b/src/Events/EventContext.php similarity index 79% rename from src/EventContext.php rename to src/Events/EventContext.php index faa3708..e9924a4 100644 --- a/src/EventContext.php +++ b/src/Events/EventContext.php @@ -1,7 +1,7 @@ matchingPattern; } + public function hasDataType($type): bool + { + return $this->data instanceof $type ? true : false; + } + /** * Returns the immutable data container. * @return EventContextDataContainer @@ -87,4 +92,14 @@ class EventContext { $this->data = $this->data->setFields($data); } + + /** + * Checks if given original data is the same as currently held within this context. + * @param EventContextDataContainer $originalData + * @return bool + */ + public function hasDataChanged(EventContextDataContainer $originalData): bool + { + return $this->data === $originalData ? false : true; + } } \ No newline at end of file diff --git a/src/Events/EventContextData.php b/src/Events/EventContextData.php new file mode 100644 index 0000000..c204668 --- /dev/null +++ b/src/Events/EventContextData.php @@ -0,0 +1,14 @@ +data[$field]); + return array_key_exists($field, $this->data); } /** diff --git a/src/Events/NavigateToScene.php b/src/Events/NavigateToScene.php new file mode 100644 index 0000000..ba8deee --- /dev/null +++ b/src/Events/NavigateToScene.php @@ -0,0 +1,53 @@ + $this->getCharacter(), 'scene' => null - ]; - $this->getEventManager()->publish('h/lotgd/core/default-scene', $context); + ]); - $s = $context['scene']; + $contextData = $this->getEventManager()->publish('h/lotgd/core/default-scene', $contextData); + + $s = $contextData->get("scene"); if ($s === null) { throw new InvalidConfigurationException("No subscriber to h/lotgd/core/default-scene returned a scene."); } @@ -292,17 +295,18 @@ class Game // Let and installed listeners (ie modules) make modifications to the // new viewpoint, including the ability to redirect the user to // a different scene, by setting $context['redirect'] to a new scene. - $context = [ + $contextData = NavigateToScene::create([ 'referrer' => $referrer, 'viewpoint' => $viewpoint, 'scene' => $scene, 'parameters' => $parameters, 'redirect' => null - ]; - $hook = 'h/lotgd/core/navigate-to/' . $scene->getTemplate(); - $this->getEventManager()->publish($hook, $context); + ]); - $scene = $context['redirect']; + $hook = 'h/lotgd/core/navigate-to/' . $scene->getTemplate(); + $contextData = $this->getEventManager()->publish($hook, $contextData); + + $scene = $contextData->get('redirect'); if ($scene !== null) { $id = $scene->getId(); $this->getLogger()->debug("Redirecting to sceneId={$id}"); diff --git a/src/Module.php b/src/Module.php index df27aaf..7ccbfb0 100644 --- a/src/Module.php +++ b/src/Module.php @@ -9,18 +9,6 @@ use LotGD\Core\Models\Module as ModuleModel; */ interface Module extends EventHandler { - /** - * Called when an event is published that is handled by this class. - * - * @param Game $g The game. - * @param string $event Name of this event. - * @param array $context Arbitrary dictionary representing context around this event. - * @return array|null Return an array if you want to make changes to the $context before - * the next handler is called. Otherwise, return null. Any changes made will be propogated - * to the event publisher as well. - */ - public static function handleEvent(Game $g, string $event, array &$context); - /** * Lifecycle method called when this module is initially installed. Use * this method to perform one-time setup operations like adding tables diff --git a/tests/EventManagerTest.php b/tests/EventManagerTest.php index 038784d..30b232d 100644 --- a/tests/EventManagerTest.php +++ b/tests/EventManagerTest.php @@ -3,6 +3,8 @@ declare(strict_types=1); namespace LotGD\Core\Tests; +use LotGD\Core\Events\EventContext; +use LotGD\Core\Events\EventContextData; use LotGD\Core\Game; use LotGD\Core\EventManager; use LotGD\Core\EventHandler; @@ -20,7 +22,9 @@ class EventManagerTestInvalidSubscriber class EventManagerTestSubscriber implements EventHandler { - public static function handleEvent(Game $g, string $event, array &$context) {} + public static function handleEvent(Game $g, EventContext $context): EventContext { + return $context; + } } class EventManagerTest extends CoreModelTestCase @@ -129,9 +133,11 @@ class EventManagerTest extends CoreModelTestCase $em = new EventManager($this->g); $event = 'test.foo.something_here'; - $context = array('foo' => 'bar'); + $contextData = EventContextData::create(["foo" => "bar"]); - $em->publish($event, $context); - $this->assertEquals($context['foo'], 'baz'); + // The event is expected to change foo from bar to baz. + $contextDataModified = $em->publish($event, $contextData); + $this->assertNotSame($contextData, $contextDataModified); + $this->assertEquals("baz", $contextDataModified->get("foo")); } } diff --git a/tests/FakeModule/Module.php b/tests/FakeModule/Module.php index 756e2b5..a7350ad 100644 --- a/tests/FakeModule/Module.php +++ b/tests/FakeModule/Module.php @@ -3,12 +3,14 @@ namespace LotGD\Core\Tests\FakeModule; use LotGD\Core\Game; +use LotGD\Core\Events\EventContext; use LotGD\Core\Module as ModuleInterface; use LotGD\Core\Models\Module as ModuleModel; class Module implements ModuleInterface { - public static function handleEvent(Game $g, string $event, array &$context) { - $context['foo'] = 'baz'; + public static function handleEvent(Game $g, EventContext $context): EventContext + { + $context->setDataField("foo", "baz"); return $context; } public static function onRegister(Game $g, ModuleModel $module) {} diff --git a/tests/GameTest.php b/tests/GameTest.php index 0e444d1..3b01ca5 100644 --- a/tests/GameTest.php +++ b/tests/GameTest.php @@ -8,26 +8,16 @@ use Doctrine\ORM\EntityManager; use Monolog\Logger; use Monolog\Handler\NullHandler; -use LotGD\Core\Action; -use LotGD\Core\ActionGroup; -use LotGD\Core\Bootstrap; -use LotGD\Core\Configuration; -use LotGD\Core\ComposerManager; -use LotGD\Core\DiceBag; -use LotGD\Core\EventHandler; -use LotGD\Core\EventManager; -use LotGD\Core\Game; -use LotGD\Core\TimeKeeper; -use LotGD\Core\ModuleManager; -use LotGD\Core\Models\Character; -use LotGD\Core\Models\Viewpoint; -use LotGD\Core\Models\Scene; -use LotGD\Core\Exceptions\ { - ActionNotFoundException, - CharacterNotFoundException, - InvalidConfigurationException +use LotGD\Core\{ + Action, ActionGroup, Bootstrap, Configuration, ComposerManager, DiceBag, EventHandler, EventManager, Events\NewViewpoint, Game, TimeKeeper, ModuleManager }; -use LotGD\Core\Tests\CoreModelTestCase; +use LotGD\Core\Models\{ + Character, Viewpoint, Scene +}; +use LotGD\Core\Exceptions\ { + ActionNotFoundException, CharacterNotFoundException, InvalidConfigurationException +}; +use LotGD\Core\Events\EventContext; class DefaultSceneProvider implements EventHandler { @@ -35,17 +25,22 @@ class DefaultSceneProvider implements EventHandler public static $attachments = ['actions']; public static $data = ['data']; - public static function handleEvent(Game $g, string $event, array &$context) + public static function handleEvent(Game $g, EventContext $context): EventContext { - switch ($event) { + switch ($context->getEvent()) { case 'h/lotgd/core/default-scene': - if (!isset($context['character'])) { - throw new \Exception("Key 'character' was expected on event h/lotgd/core/default-scene."); + if (!$context->hasDataType(NewViewpoint::class)) { + throw new \Exception(sprintf( + "Context was expected to be %s, %s instead.", + NewViewpoint::class, + get_class($context->getData()) + )); } - $context['scene'] = $g->getEntityManager()->getRepository(Scene::class)->find(1); + + $context->setDataField("scene", $g->getEntityManager()->getRepository(Scene::class)->find(1)); break; case 'h/lotgd/core/navigate-to/lotgd/tests/village': - $v = $context['viewpoint']; + $v = $context->getDataField('viewpoint'); self::$actionGroups = [new ActionGroup('default', 'Title', 0)]; self::$actionGroups[0]->setActions([ @@ -58,6 +53,8 @@ class DefaultSceneProvider implements EventHandler $v->setData(self::$data); break; } + + return $context; } } @@ -124,7 +121,7 @@ class GameTest extends CoreModelTestCase $c = $this->getEntityManager()->getRepository(Character::class)->find(1); $this->g->setCharacter($c); - // There shouldnt be any listeners to provide a default scene. + // There should'nt be any listeners to provide a default scene. $this->expectException(InvalidConfigurationException::class); $this->g->getViewpoint(); }