Skip to content

Commit 79aef98

Browse files
authored
Merge pull request #133 from php-school/register-event-listeners-via-config
Register event listeners via config
2 parents 602dc82 + 71bc53a commit 79aef98

File tree

5 files changed

+525
-19
lines changed

5 files changed

+525
-19
lines changed

src/Application.php

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ final class Application
5959
*/
6060
private $bgColour = 'black';
6161

62+
/**
63+
* @var string
64+
*/
65+
private $frameworkConfigLocation = __DIR__ . '/../app/config.php';
66+
6267
/**
6368
* It should be instantiated with the title of
6469
* the workshop and the path to the DI configuration file.
@@ -156,24 +161,7 @@ public function setBgColour($colour)
156161
*/
157162
public function run()
158163
{
159-
$containerBuilder = new ContainerBuilder;
160-
$containerBuilder->addDefinitions(__DIR__ . '/../app/config.php');
161-
$containerBuilder->addDefinitions($this->diConfigFile);
162-
163-
$containerBuilder->addDefinitions(array_merge(
164-
[
165-
'workshopTitle' => $this->workshopTitle,
166-
'exercises' => $this->exercises,
167-
'workshopLogo' => $this->logo,
168-
'bgColour' => $this->bgColour,
169-
'fgColour' => $this->fgColour,
170-
]
171-
));
172-
173-
$containerBuilder->useAutowiring(false);
174-
$containerBuilder->useAnnotations(false);
175-
176-
$container = $containerBuilder->build();
164+
$container = $this->getContainer();
177165

178166
foreach ($this->exercises as $exercise) {
179167
if (false === $container->has($exercise)) {
@@ -229,4 +217,33 @@ public function run()
229217
}
230218
return $exitCode;
231219
}
220+
221+
/**
222+
* @return \DI\Container
223+
*/
224+
private function getContainer()
225+
{
226+
$containerBuilder = new ContainerBuilder;
227+
$containerBuilder->addDefinitions(
228+
array_merge_recursive(
229+
require $this->frameworkConfigLocation,
230+
require $this->diConfigFile
231+
)
232+
);
233+
234+
$containerBuilder->addDefinitions(
235+
[
236+
'workshopTitle' => $this->workshopTitle,
237+
'exercises' => $this->exercises,
238+
'workshopLogo' => $this->logo,
239+
'bgColour' => $this->bgColour,
240+
'fgColour' => $this->fgColour,
241+
]
242+
);
243+
244+
$containerBuilder->useAutowiring(false);
245+
$containerBuilder->useAnnotations(false);
246+
247+
return $containerBuilder->build();
248+
}
232249
}

src/CommandRouter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private function addCommand(CommandDefinition $c)
8484
*
8585
* @param array $args
8686
* @return int
87-
* @throws CliRouteNotExists
87+
* @throws CliRouteNotExistsException
8888
*/
8989
public function route(array $args = null)
9090
{

src/Factory/EventDispatcherFactory.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Interop\Container\ContainerInterface;
66
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
7+
use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException;
78
use PhpSchool\PhpWorkshop\Listener\CodePatchListener;
89
use PhpSchool\PhpWorkshop\Listener\PrepareSolutionListener;
910
use PhpSchool\PhpWorkshop\Listener\SelfCheckListener;
@@ -20,6 +21,7 @@ class EventDispatcherFactory
2021
/**
2122
* @param ContainerInterface $container
2223
* @return EventDispatcher
24+
* @throws InvalidArgumentException
2325
*/
2426
public function __invoke(ContainerInterface $container)
2527
{
@@ -37,6 +39,59 @@ public function __invoke(ContainerInterface $container)
3739

3840
$dispatcher->listen('verify.post.check', $container->get(SelfCheckListener::class));
3941

42+
//add listeners from config
43+
$eventListeners = $container->get('eventListeners') ?: [];
44+
45+
if (!is_array($eventListeners)) {
46+
throw InvalidArgumentException::typeMisMatch('array', $eventListeners);
47+
}
48+
49+
array_walk($eventListeners, function ($listeners, $eventName) use ($dispatcher, $container) {
50+
if (!is_array($listeners)) {
51+
throw InvalidArgumentException::typeMisMatch('array', $listeners);
52+
}
53+
54+
$this->attachListeners($eventName, $listeners, $container, $dispatcher);
55+
});
56+
4057
return $dispatcher;
4158
}
59+
60+
/**
61+
* @param string $eventName
62+
* @param array $listeners
63+
* @param ContainerInterface $container
64+
* @param EventDispatcher $dispatcher
65+
* @throws \PhpSchool\PhpWorkshop\Exception\InvalidArgumentException
66+
*/
67+
private function attachListeners(
68+
$eventName,
69+
array $listeners,
70+
ContainerInterface $container,
71+
EventDispatcher $dispatcher
72+
) {
73+
array_walk($listeners, function ($listener) use ($eventName, $dispatcher, $container) {
74+
if (is_callable($listener)) {
75+
return $dispatcher->listen($eventName, $listener);
76+
}
77+
78+
if (!is_string($listener)) {
79+
throw new InvalidArgumentException(
80+
sprintf('Listener must be a callable or a container entry for a callable service.')
81+
);
82+
}
83+
84+
if (!$container->has($listener)) {
85+
throw new InvalidArgumentException(sprintf('Container has no entry named: "%s"', $listener));
86+
}
87+
88+
$listener = $container->get($listener);
89+
90+
if (!is_callable($listener)) {
91+
throw InvalidArgumentException::typeMisMatch('callable', $listener);
92+
}
93+
94+
return $dispatcher->listen($eventName, $listener);
95+
});
96+
}
4297
}

test/ApplicationTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshopTest;
4+
5+
use PhpSchool\PhpWorkshop\Application;
6+
use PHPUnit_Framework_TestCase;
7+
8+
/**
9+
* @author Aydin Hassan <[email protected]>
10+
*/
11+
class ApplicationTest extends PHPUnit_Framework_TestCase
12+
{
13+
public function testEventListenersFromLocalAndWorkshopConfigAreMerged()
14+
{
15+
16+
$frameworkFileContent = '<?php return [';
17+
$frameworkFileContent .= " 'eventListeners' => [";
18+
$frameworkFileContent .= " 'event1' => [";
19+
$frameworkFileContent .= " 'entry1',";
20+
$frameworkFileContent .= " 'entry2',";
21+
$frameworkFileContent .= ' ]';
22+
$frameworkFileContent .= ' ]';
23+
$frameworkFileContent .= '];';
24+
25+
$localFileContent = '<?php return [';
26+
$localFileContent .= " 'eventListeners' => [";
27+
$localFileContent .= " 'event1' => [";
28+
$localFileContent .= " 'entry3',";
29+
$localFileContent .= ' ]';
30+
$localFileContent .= ' ]';
31+
$localFileContent .= '];';
32+
33+
$localFile = sprintf('%s/%s', sys_get_temp_dir(), uniqid($this->getName(), true));
34+
$frameworkFile = sprintf('%s/%s', sys_get_temp_dir(), uniqid($this->getName(), true));
35+
file_put_contents($frameworkFile, $frameworkFileContent);
36+
file_put_contents($localFile, $localFileContent);
37+
38+
$app = new Application('Test App', $localFile);
39+
40+
$rm = new \ReflectionMethod($app, 'getContainer');
41+
$rm->setAccessible(true);
42+
43+
$rp = new \ReflectionProperty(Application::class, 'frameworkConfigLocation');
44+
$rp->setAccessible(true);
45+
$rp->setValue($app, $frameworkFile);
46+
47+
$container = $rm->invoke($app);
48+
49+
$eventListeners = $container->get('eventListeners');
50+
51+
$this->assertEquals(
52+
[
53+
'event1' => [
54+
'entry1',
55+
'entry2',
56+
'entry3',
57+
]
58+
],
59+
$eventListeners
60+
);
61+
}
62+
}

0 commit comments

Comments
 (0)