diff --git a/src/Game.php b/src/Game.php index ad8f8f4..f4964b0 100644 --- a/src/Game.php +++ b/src/Game.php @@ -8,7 +8,6 @@ use Doctrine\ORM\EntityManagerInterface; use LotGD\Core\Events\NavigateToSceneData; use LotGD\Core\Events\NewViewpointData; use LotGD\Core\Exceptions\ActionNotFoundException; - use LotGD\Core\Exceptions\CharacterNotFoundException; use LotGD\Core\Exceptions\InvalidConfigurationException; use LotGD\Core\Exceptions\SceneNotFoundException; @@ -338,6 +337,13 @@ class Game $viewpoint->setActionGroups(\array_values($actionGroups)); + $sceneTemplate = $scene->getTemplate(); + $templateClass = $sceneTemplate ? $sceneTemplate->getClass() : BasicSceneTemplate::class; + + if (!is_a($templateClass, SceneTemplateInterface::class, true)) { + throw new \Exception("Scene template must implement ".SceneTemplateInterface::class); + } + // 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. @@ -349,7 +355,7 @@ class Game 'redirect' => null, ]); - $hook = 'h/lotgd/core/navigate-to/' . $scene->getTemplate(); + $hook = "h/lotgd/core/navigate-to/".$templateClass::getNavigationEvent(); $contextData = $this->getEventManager()->publish($hook, $contextData); $scene = $contextData->get('redirect'); @@ -379,13 +385,15 @@ class Game if ($action === null) { throw new ActionNotFoundException("Invalid actionId={$actionId} for current viewpoint."); } - $actionParameters = $action->getParameters(); + $actionParameters = $action->getParameters(); $sceneId = $action->getDestinationSceneId(); + + /** @var Scene $scene */ $scene = $this->getEntityManager()->getRepository(Scene::class)->find([ 'id' => $sceneId, ]); - if ($scene == null) { + if ($scene === null) { throw new SceneNotFoundException("Cannot find sceneId={$sceneId} specified by actionId={$actionId}."); } diff --git a/src/Models/SceneTemplate.php b/src/Models/SceneTemplate.php index a0527e6..7ebe228 100644 --- a/src/Models/SceneTemplate.php +++ b/src/Models/SceneTemplate.php @@ -23,7 +23,7 @@ class SceneTemplate /** @Id @Column(type="string", length=255, unique=True, name="class") */ protected $class; - /** @Column(type="string", length=255, unique=True, name="id") */ + /** @Column(type="string", length=255, name="module") */ protected $module; /** @Column(type="boolean", options={"default": True}) */ @@ -48,6 +48,14 @@ class SceneTemplate $this->module = $module; } + /** + * @return string The class name of the template. + */ + public function getClass(): string + { + return $this->class; + } + /** * Changes whether the template should be able to get manually assigned to a template or not. * @param bool $flag diff --git a/src/Models/Viewpoint.php b/src/Models/Viewpoint.php index 958acb1..9df7c21 100644 --- a/src/Models/Viewpoint.php +++ b/src/Models/Viewpoint.php @@ -3,6 +3,7 @@ declare(strict_types=1); namespace LotGD\Core\Models; +use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\Id; @@ -140,7 +141,7 @@ class Viewpoint implements CreateableInterface $snapshot = new ViewpointSnapshot( $this->getTitle(), $this->getDescription(), - $this->getTemplate(), + get_class($this->getTemplate()), $this->getActionGroups(), $this->getAttachments(), $this->getData() @@ -153,11 +154,13 @@ class Viewpoint implements CreateableInterface * Changes the current viewpoint to the state saved in the given restoration point. * @param ViewpointSnapshot $snapshot */ - public function changeFromSnapshot(ViewpointSnapshot $snapshot) + public function changeFromSnapshot(EntityManager $entityManager, ViewpointSnapshot $snapshot) { + $templateInstance = $entityManager->getRepository(SceneTemplate::class)->find($snapshot->getTemplate()); + $this->setTitle($snapshot->getTitle()); $this->setDescription($snapshot->getDescription()); - $this->setTemplate($snapshot->getTemplate()); + $this->setTemplate($templateInstance); $this->setActionGroups($snapshot->getActionGroups()); $this->setAttachments($snapshot->getAttachments()); $this->setData($snapshot->getData()); diff --git a/src/SceneTemplates/BasicSceneTemplate.php b/src/SceneTemplates/BasicSceneTemplate.php index 4e27ddc..ba60fd5 100644 --- a/src/SceneTemplates/BasicSceneTemplate.php +++ b/src/SceneTemplates/BasicSceneTemplate.php @@ -5,7 +5,19 @@ declare(strict_types=1); namespace LotGD\Core\SceneTemplates; +/** + * Class BasicSceneTemplate + * + * Offers a basic scene template. All scenes with no template use this class internally. + */ class BasicSceneTemplate implements SceneTemplateInterface { - + /** + * {@inheritDoc} + * @return string + */ + public static function getNavigationEvent(): string + { + return "no-template"; + } } \ No newline at end of file diff --git a/src/SceneTemplates/SceneTemplateInterface.php b/src/SceneTemplates/SceneTemplateInterface.php index 79fa644..4c9ee1a 100644 --- a/src/SceneTemplates/SceneTemplateInterface.php +++ b/src/SceneTemplates/SceneTemplateInterface.php @@ -7,5 +7,9 @@ namespace LotGD\Core\SceneTemplates; interface SceneTemplateInterface { - + /** + * Returns the event string that's attached to the navigation-to hook. + * @return string + */ + public static function getNavigationEvent(): string; } \ No newline at end of file diff --git a/tests/GameTest.php b/tests/GameTest.php index 25a2aff..e571ed7 100644 --- a/tests/GameTest.php +++ b/tests/GameTest.php @@ -8,9 +8,21 @@ use Doctrine\ORM\EntityManager; use Monolog\Logger; use Monolog\Handler\NullHandler; -use LotGD\Core\{ - Action, ActionGroup, Bootstrap, Configuration, ComposerManager, DiceBag, EventHandler, EventManager, Events\NewViewpointData, Game, GameBuilder, TimeKeeper, ModuleManager -}; +use LotGD\Core\{Action, + ActionGroup, + Bootstrap, + Configuration, + ComposerManager, + DiceBag, + EventHandler, + EventManager, + Events\NewViewpointData, + Game, + GameBuilder, + Tests\SceneTemplates\ParameterTestSceneTemplate, + Tests\SceneTemplates\VillageSceneTemplate, + TimeKeeper, + ModuleManager}; use LotGD\Core\Models\{ Character, Viewpoint, Scene }; @@ -40,7 +52,7 @@ class DefaultSceneProvider implements EventHandler $context->setDataField("scene", $g->getEntityManager()->getRepository(Scene::class) ->find("30000000-0000-0000-0000-000000000001")); break; - case 'h/lotgd/core/navigate-to/lotgd/tests/village': + case "h/lotgd/core/navigate-to/".VillageSceneTemplate::getNavigationEvent(); $v = $context->getDataField('viewpoint'); self::$actionGroups = [new ActionGroup('default', 'Title', 0)]; @@ -54,7 +66,7 @@ class DefaultSceneProvider implements EventHandler $v->setData(self::$data); break; - case 'h/lotgd/core/navigate-to/lotgd/tests/paramaters': + case "h/lotgd/core/navigate-to/".ParameterTestSceneTemplate::getNavigationEvent(): /* @var Viewpoint $v //*/ $v = $context->getDataField('viewpoint'); /* @var array //*/ @@ -164,8 +176,9 @@ class GameTest extends CoreModelTestCase $v = $this->g->getViewpoint(); // Run it twice to make sure no additional DB operations happen. + /** @var Viewpoint $v */ $v = $this->g->getViewpoint(); - $this->assertEquals('lotgd/tests/village', $v->getTemplate()); + $this->assertSame(VillageSceneTemplate::class, $v->getTemplate()->getClass()); // Validate the changes made by the hook. $this->assertSame(DefaultSceneProvider::$actionGroups, $v->getActionGroups()); @@ -215,7 +228,7 @@ class GameTest extends CoreModelTestCase $this->g->setCharacter($c); // subscribe event - $this->g->getEventManager()->subscribe('#h/lotgd/core/navigate-to/lotgd/tests/paramaters#', DefaultSceneProvider::class, 'lotgd/core/tests'); + $this->g->getEventManager()->subscribe('#'.ParameterTestSceneTemplate::getNavigationEvent().'#', DefaultSceneProvider::class, 'lotgd/core/tests'); $this->getEntityManager()->flush(); $action = new Action("30000000-0000-0000-0000-000000000007", null, ["foo" => "baz"]); @@ -235,7 +248,7 @@ class GameTest extends CoreModelTestCase $this->assertSame("Parameter is baz.", $v->getDescription()); // unsubscribe event - $this->g->getEventManager()->unsubscribe('#h/lotgd/core/navigate-to/lotgd/tests/paramaters#', DefaultSceneProvider::class, 'lotgd/core/tests'); + $this->g->getEventManager()->unsubscribe('#'.ParameterTestSceneTemplate::getNavigationEvent().'#', DefaultSceneProvider::class, 'lotgd/core/tests'); } public function testIfActionParametersTakePriorityToOtherParameters() @@ -245,7 +258,7 @@ class GameTest extends CoreModelTestCase $this->g->setCharacter($c); // subscribe event - $this->g->getEventManager()->subscribe('#h/lotgd/core/navigate-to/lotgd/tests/paramaters#', DefaultSceneProvider::class, 'lotgd/core/tests'); + $this->g->getEventManager()->subscribe('#'.ParameterTestSceneTemplate::getNavigationEvent().'#', DefaultSceneProvider::class, 'lotgd/core/tests'); $this->getEntityManager()->flush(); $action = new Action("30000000-0000-0000-0000-000000000007", null, ["foo" => "baz"]); @@ -265,7 +278,7 @@ class GameTest extends CoreModelTestCase $this->assertSame("Parameter is baz.", $v->getDescription()); // unsubscribe event - $this->g->getEventManager()->unsubscribe('#h/lotgd/core/navigate-to/lotgd/tests/paramaters#', DefaultSceneProvider::class, 'lotgd/core/tests'); + $this->g->getEventManager()->unsubscribe('#'.ParameterTestSceneTemplate::getNavigationEvent().'#', DefaultSceneProvider::class, 'lotgd/core/tests'); } public function testIfActionsAreAddedAsExpected() diff --git a/tests/Models/SceneModelTest.php b/tests/Models/SceneModelTest.php index e1d1468..a63fe4e 100644 --- a/tests/Models/SceneModelTest.php +++ b/tests/Models/SceneModelTest.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace LotGD\Core\Tests\Models; use LotGD\Core\Exceptions\ArgumentException; -use LotGD\Core\Models\{Scene, SceneConnection, SceneConnectionGroup}; +use LotGD\Core\Models\{Scene, SceneConnection, SceneConnectionGroup, SceneTemplate}; use LotGD\Core\Tests\CoreModelTestCase; +use LotGD\Core\Tests\SceneTemplates\NewSceneSceneTemplate; /** * Tests for creating scenes and moving them around. @@ -38,7 +39,7 @@ class SceneModelTest extends CoreModelTestCase return [ "title" => "A new scene", "description" => "This is a new scene", - "template" => "lotgd/test/new-scene" + "template" => $this->getEntityManager()->getRepository(SceneTemplate::class)->find(NewSceneSceneTemplate::class), ]; } diff --git a/tests/Models/ViewpointRestorationTest.php b/tests/Models/ViewpointRestorationTest.php index af57616..2714273 100644 --- a/tests/Models/ViewpointRestorationTest.php +++ b/tests/Models/ViewpointRestorationTest.php @@ -3,9 +3,13 @@ declare(strict_types=1); namespace LotGD\Core\Tests\Models; +use Composer\Repository\RepositoryInterface; +use Doctrine\Common\Persistence\ObjectRepository; +use Doctrine\ORM\EntityManager; use LotGD\Core\Action; use LotGD\Core\ActionGroup; use LotGD\Core\Models\Scene; +use LotGD\Core\Models\SceneTemplate; use LotGD\Core\Models\Viewpoint; use LotGD\Core\Tests\CoreModelTestCase; @@ -29,10 +33,18 @@ class ViewpointRestorationTest extends CoreModelTestCase protected function getViewpoint() { + $sceneTemplateMock = $this->createMock(SceneTemplate::class); + $sceneMock = $this->createMock(Scene::class); $sceneMock->method("getTitle")->willReturn("Scene Mock Title"); $sceneMock->method("getDescription")->willReturn("Scene Mock Description"); - $sceneMock->method("getTemplate")->willReturn("lotgd/scene-mock-template"); + $sceneMock->method("getTemplate")->willReturn($sceneTemplateMock); + + $repository = $this->createMock(ObjectRepository::class); + $repository->method("find")->willReturn($sceneTemplateMock); + + $entityManager = $this->createMock(EntityManager::class); + $entityManager->method("getRepository")->willReturn($repository); $actionGroup = $this->getActionGroup(); @@ -40,31 +52,39 @@ class ViewpointRestorationTest extends CoreModelTestCase $viewpoint->changeFromScene($sceneMock); $viewpoint->setActionGroups([$actionGroup]); - return $viewpoint; + return [$entityManager, $viewpoint]; } protected function getAlternativeViewpoint() { + $sceneTemplateMock = $this->createMock(SceneTemplate::class); + $sceneMock = $this->createMock(Scene::class); $sceneMock->method("getTitle")->willReturn("Another Scene Mock Title"); $sceneMock->method("getDescription")->willReturn("Another Scene Mock Description"); - $sceneMock->method("getTemplate")->willReturn("lotgd/scene-mock-template/another"); + $sceneMock->method("getTemplate")->willReturn($sceneTemplateMock); + + $repository = $this->createMock(ObjectRepository::class); + $repository->method("find")->willReturn($sceneTemplateMock); + + $entityManager = $this->createMock(EntityManager::class); + $entityManager->method("getRepository")->willReturn($repository); $viewpoint = new Viewpoint(); $viewpoint->changeFromScene($sceneMock); - return $viewpoint; + return [$entityManager, $viewpoint]; } public function testIfViewpointAfterUnserializationIsEqualToBeforeItsSerialization() { - $viewpoint = $this->getViewpoint(); - $viewpointRestoration = $this->getViewpoint()->getSnapshot(); + [$entityManager, $viewpoint] = $this->getViewpoint(); + $viewpointRestoration = $viewpoint->getSnapshot(); $serialized = serialize($viewpointRestoration); $viewpointRestored = unserialize($serialized); - $newViewpoint = $this->getAlternativeViewpoint(); - $newViewpoint->changeFromSnapshot($viewpointRestored); + [$entityManager2, $newViewpoint] = $this->getAlternativeViewpoint(); + $newViewpoint->changeFromSnapshot($entityManager, $viewpointRestored); $this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle()); $this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription()); diff --git a/tests/SceneTemplates/NewSceneSceneTemplate.php b/tests/SceneTemplates/NewSceneSceneTemplate.php new file mode 100644 index 0000000..6d9f619 --- /dev/null +++ b/tests/SceneTemplates/NewSceneSceneTemplate.php @@ -0,0 +1,16 @@ +