From 1ec03c30869de17e822a893c134e3307b8f9704d Mon Sep 17 00:00:00 2001 From: Aydin Hassan Date: Tue, 1 Nov 2016 23:02:49 +0000 Subject: [PATCH 1/3] Dispatch event when an exercise is selected --- src/Exercise/AbstractExercise.php | 6 +++--- src/Factory/MenuFactory.php | 26 +++++++++++++++++++++++++- test/Factory/MenuFactoryTest.php | 4 +++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Exercise/AbstractExercise.php b/src/Exercise/AbstractExercise.php index 16cd0e6f..79dc468b 100644 --- a/src/Exercise/AbstractExercise.php +++ b/src/Exercise/AbstractExercise.php @@ -41,7 +41,7 @@ public function getSolution() sprintf( '%s/../../exercises/%s/solution/solution.php', dirname((new ReflectionClass(static::class))->getFileName()), - $this->normaliseName($this->getName()) + self::normaliseName($this->getName()) ) ) ); @@ -55,7 +55,7 @@ public function getSolution() */ public function getProblem() { - $name = $this->normaliseName($this->getName()); + $name = self::normaliseName($this->getName()); $dir = dirname((new ReflectionClass(static::class))->getFileName()); return sprintf('%s/../../exercises/%s/problem/problem.md', $dir, $name); } @@ -74,7 +74,7 @@ public function tearDown() * @param string $name * @return string */ - private function normaliseName($name) + public static function normaliseName($name) { return preg_replace('/[^A-Za-z\-]+/', '', str_replace(' ', '-', strtolower($name))); } diff --git a/src/Factory/MenuFactory.php b/src/Factory/MenuFactory.php index 33830bf1..0f3b2b7a 100644 --- a/src/Factory/MenuFactory.php +++ b/src/Factory/MenuFactory.php @@ -9,6 +9,9 @@ use PhpSchool\PhpWorkshop\Command\CreditsCommand; use PhpSchool\PhpWorkshop\Command\HelpCommand; use PhpSchool\PhpWorkshop\Command\MenuCommandInvoker; +use PhpSchool\PhpWorkshop\Event\Event; +use PhpSchool\PhpWorkshop\Event\EventDispatcher; +use PhpSchool\PhpWorkshop\Exercise\AbstractExercise; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\ExerciseRenderer; use PhpSchool\PhpWorkshop\ExerciseRepository; @@ -34,6 +37,7 @@ public function __invoke(ContainerInterface $c) $userState = $userStateSerializer->deSerialize(); $exerciseRenderer = $c->get(ExerciseRenderer::class); $workshopType = $c->get(WorkshopType::class); + $eventDispatcher = $c->get(EventDispatcher::class); $builder = (new CliMenuBuilder) ->addLineBreak(); @@ -48,9 +52,13 @@ public function __invoke(ContainerInterface $c) ->addStaticItem('Exercises') ->addStaticItem('---------') ->addItems( - array_map(function (ExerciseInterface $exercise) use ($exerciseRenderer, $userState, $workshopType) { + array_map(function (ExerciseInterface $exercise) use ($exerciseRenderer, $userState, $workshopType, $eventDispatcher) { return [ $exercise->getName(), + function (CliMenu $menu) use ($exerciseRenderer, $eventDispatcher, $exercise) { + $this->dispatchExerciseSelectedEvent($eventDispatcher, $exercise); + $exerciseRenderer->__invoke($menu); + }, $exerciseRenderer, $userState->completedExercise($exercise->getName()), $this->isExerciseDisabled($exercise, $userState, $workshopType) @@ -121,4 +129,20 @@ private function isExerciseDisabled(ExerciseInterface $exercise, UserState $user $previous = $exercise; return true; } + + /** + * @param EventDispatcher $eventDispatcher + * @param ExerciseInterface $exercise + */ + private function dispatchExerciseSelectedEvent(EventDispatcher $eventDispatcher, ExerciseInterface $exercise) + { + $eventDispatcher->dispatch( + new Event( + sprintf( + 'exercise.selected.%s', + AbstractExercise::normaliseName($exercise->getName()) + ) + ) + ); + } } diff --git a/test/Factory/MenuFactoryTest.php b/test/Factory/MenuFactoryTest.php index 292e32fd..37d53f17 100644 --- a/test/Factory/MenuFactoryTest.php +++ b/test/Factory/MenuFactoryTest.php @@ -6,6 +6,7 @@ use PhpSchool\CliMenu\CliMenu; use PhpSchool\PhpWorkshop\Command\CreditsCommand; use PhpSchool\PhpWorkshop\Command\HelpCommand; +use PhpSchool\PhpWorkshop\Event\EventDispatcher; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\ExerciseRenderer; use PhpSchool\PhpWorkshop\ExerciseRepository; @@ -53,7 +54,8 @@ public function testFactoryReturnsInstance() 'bgColour' => 'black', 'fgColour' => 'green', 'workshopTitle' => 'TITLE', - WorkshopType::class => WorkshopType::STANDARD() + WorkshopType::class => WorkshopType::STANDARD(), + EventDispatcher::class => $this->createMock(EventDispatcher::class), ]; $container From c7b1a1592d7039ce4a5c6be291adaf74bfaaa425 Mon Sep 17 00:00:00 2001 From: Aydin Hassan Date: Tue, 1 Nov 2016 23:14:25 +0000 Subject: [PATCH 2/3] remove old arg --- src/Factory/MenuFactory.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Factory/MenuFactory.php b/src/Factory/MenuFactory.php index 0f3b2b7a..32c41780 100644 --- a/src/Factory/MenuFactory.php +++ b/src/Factory/MenuFactory.php @@ -59,7 +59,6 @@ function (CliMenu $menu) use ($exerciseRenderer, $eventDispatcher, $exercise) { $this->dispatchExerciseSelectedEvent($eventDispatcher, $exercise); $exerciseRenderer->__invoke($menu); }, - $exerciseRenderer, $userState->completedExercise($exercise->getName()), $this->isExerciseDisabled($exercise, $userState, $workshopType) ]; From ca502721c62209a62211dc6806d9b1cbc47b13d1 Mon Sep 17 00:00:00 2001 From: Aydin Hassan Date: Tue, 1 Nov 2016 23:36:06 +0000 Subject: [PATCH 3/3] fix when eventListeners not set --- src/Factory/EventDispatcherFactory.php | 2 +- src/Factory/MenuFactory.php | 29 +++++++------ test/Factory/EventDispatcherFactoryTest.php | 48 +++++++++++++++++---- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/Factory/EventDispatcherFactory.php b/src/Factory/EventDispatcherFactory.php index 64603109..b325c75a 100644 --- a/src/Factory/EventDispatcherFactory.php +++ b/src/Factory/EventDispatcherFactory.php @@ -40,7 +40,7 @@ public function __invoke(ContainerInterface $container) $dispatcher->listen('verify.post.check', $container->get(SelfCheckListener::class)); //add listeners from config - $eventListeners = $container->get('eventListeners') ?: []; + $eventListeners = $container->has('eventListeners') ? $container->get('eventListeners') : []; if (!is_array($eventListeners)) { throw InvalidArgumentException::typeMisMatch('array', $eventListeners); diff --git a/src/Factory/MenuFactory.php b/src/Factory/MenuFactory.php index 32c41780..64abda76 100644 --- a/src/Factory/MenuFactory.php +++ b/src/Factory/MenuFactory.php @@ -50,20 +50,21 @@ public function __invoke(ContainerInterface $c) ->addLineBreak('_') ->addLineBreak() ->addStaticItem('Exercises') - ->addStaticItem('---------') - ->addItems( - array_map(function (ExerciseInterface $exercise) use ($exerciseRenderer, $userState, $workshopType, $eventDispatcher) { - return [ - $exercise->getName(), - function (CliMenu $menu) use ($exerciseRenderer, $eventDispatcher, $exercise) { - $this->dispatchExerciseSelectedEvent($eventDispatcher, $exercise); - $exerciseRenderer->__invoke($menu); - }, - $userState->completedExercise($exercise->getName()), - $this->isExerciseDisabled($exercise, $userState, $workshopType) - ]; - }, $exerciseRepository->findAll()) - ) + ->addStaticItem('---------'); + + foreach ($exerciseRepository->findAll() as $exercise) { + $builder->addItem( + $exercise->getName(), + function (CliMenu $menu) use ($exerciseRenderer, $eventDispatcher, $exercise) { + $this->dispatchExerciseSelectedEvent($eventDispatcher, $exercise); + $exerciseRenderer->__invoke($menu); + }, + $userState->completedExercise($exercise->getName()), + $this->isExerciseDisabled($exercise, $userState, $workshopType) + ); + } + + $builder ->addLineBreak() ->addLineBreak('-') ->addLineBreak() diff --git a/test/Factory/EventDispatcherFactoryTest.php b/test/Factory/EventDispatcherFactoryTest.php index 72ee9b64..ff92f6ba 100644 --- a/test/Factory/EventDispatcherFactoryTest.php +++ b/test/Factory/EventDispatcherFactoryTest.php @@ -109,6 +109,11 @@ public function testConfigEventListenersThrowsExceptionIfEventsNotArray() ->will($this->returnValue($selfCheckListener)); $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue(new \stdClass)); @@ -150,6 +155,11 @@ public function testConfigEventListenersThrowsExceptionIfEventsListenersNotArray ->will($this->returnValue($selfCheckListener)); $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue([ 'someEvent' => new \stdClass])); @@ -191,6 +201,11 @@ public function testConfigEventListenersThrowsExceptionIfEventsListenerNotCallab ->will($this->returnValue($selfCheckListener)); $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue([ 'someEvent' => [new \stdClass]])); @@ -232,11 +247,16 @@ public function testConfigEventListenersThrowsExceptionIfEventsListenerContainer ->will($this->returnValue($selfCheckListener)); $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue([ 'someEvent' => ['nonExistingContainerEntry']])); - $c->expects($this->once()) + $c->expects($this->at(6)) ->method('has') ->with('nonExistingContainerEntry') ->will($this->returnValue(false)); @@ -278,16 +298,21 @@ public function testConfigEventListenersThrowsExceptionIfEventsListenerContainer ->will($this->returnValue($selfCheckListener)); $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue([ 'someEvent' => ['notCallableEntry']])); - $c->expects($this->once()) + $c->expects($this->at(6)) ->method('has') ->with('notCallableEntry') ->will($this->returnValue(true)); - $c->expects($this->at(6)) + $c->expects($this->at(7)) ->method('get') ->with('notCallableEntry') ->will($this->returnValue(null)); @@ -332,11 +357,15 @@ public function testConfigEventListenersWithAnonymousFunction() }; $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue([ 'someEvent' => [$callback]])); - $dispatcher = (new EventDispatcherFactory)->__invoke($c); $this->assertInstanceOf(EventDispatcher::class, $dispatcher); $this->assertSame( @@ -398,14 +427,17 @@ public function testConfigEventListenersWithContainerEntry() ->with(SelfCheckListener::class) ->will($this->returnValue($selfCheckListener)); - - $c->expects($this->at(4)) + ->method('has') + ->with('eventListeners') + ->willReturn(true); + + $c->expects($this->at(5)) ->method('get') ->with('eventListeners') ->will($this->returnValue([ 'someEvent' => ['containerEntry']])); - $c->expects($this->once()) + $c->expects($this->at(6)) ->method('has') ->with('containerEntry') ->will($this->returnValue(true)); @@ -413,7 +445,7 @@ public function testConfigEventListenersWithContainerEntry() $callback = function () { }; - $c->expects($this->at(6)) + $c->expects($this->at(7)) ->method('get') ->with('containerEntry') ->will($this->returnValue($callback));