Skip to content

Commit 046fc81

Browse files
authored
Merge pull request #287 from php-school/05-05-reorganise_event_hiearchy
Reorganise event hiearchy
2 parents 4488e46 + 4b35965 commit 046fc81

13 files changed

+248
-102
lines changed

Diff for: src/Event/CgiExecuteEvent.php

+12-8
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,32 @@
44

55
namespace PhpSchool\PhpWorkshop\Event;
66

7+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
8+
use PhpSchool\PhpWorkshop\Input\Input;
79
use Psr\Http\Message\RequestInterface;
810

911
/**
1012
* An event to represent events which occur throughout the verification and running process in
1113
* `\PhpSchool\PhpWorkshop\ExerciseRunner\CgiRunner`.
1214
*/
13-
class CgiExecuteEvent extends Event
15+
class CgiExecuteEvent extends CgiExerciseRunnerEvent
1416
{
15-
/**
16-
* @var RequestInterface
17-
*/
18-
private $request;
17+
private RequestInterface $request;
1918

2019
/**
2120
* @param string $name The event name.
2221
* @param RequestInterface $request The request that will be performed.
2322
* @param array<mixed> $parameters The event parameters.
2423
*/
25-
public function __construct(string $name, RequestInterface $request, array $parameters = [])
26-
{
24+
public function __construct(
25+
string $name,
26+
ExerciseInterface $exercise,
27+
Input $input,
28+
RequestInterface $request,
29+
array $parameters = []
30+
) {
2731
$parameters['request'] = $request;
28-
parent::__construct($name, $parameters);
32+
parent::__construct($name, $exercise, $input, $parameters);
2933
$this->request = $request;
3034
}
3135

Diff for: src/Event/CgiExerciseRunnerEvent.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\Event;
4+
5+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
6+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
7+
use PhpSchool\PhpWorkshop\Input\Input;
8+
9+
class CgiExerciseRunnerEvent extends ExerciseRunnerEvent
10+
{
11+
}

Diff for: src/Event/CliExecuteEvent.php

+12-5
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,35 @@
44

55
namespace PhpSchool\PhpWorkshop\Event;
66

7+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
8+
use PhpSchool\PhpWorkshop\Input\Input;
79
use PhpSchool\PhpWorkshop\Utils\ArrayObject;
810

911
/**
1012
* An event to represent events which occur throughout the verification and running process in
1113
* `\PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner`.
1214
*/
13-
class CliExecuteEvent extends Event
15+
class CliExecuteEvent extends CliExerciseRunnerEvent
1416
{
1517
/**
1618
* @var ArrayObject<int, string>
1719
*/
18-
private $args;
20+
private ArrayObject $args;
1921

2022
/**
2123
* @param string $name The event name.
2224
* @param ArrayObject<int, string> $args The arguments that should be/have been passed to the program.
2325
* @param array<mixed> $parameters The event parameters.
2426
*/
25-
public function __construct(string $name, ArrayObject $args, array $parameters = [])
26-
{
27+
public function __construct(
28+
string $name,
29+
ExerciseInterface $exercise,
30+
Input $input,
31+
ArrayObject $args,
32+
array $parameters = []
33+
) {
2734
$parameters['args'] = $args;
28-
parent::__construct($name, $parameters);
35+
parent::__construct($name, $exercise, $input, $parameters);
2936
$this->args = $args;
3037
}
3138

Diff for: src/Event/CliExerciseRunnerEvent.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\Event;
4+
5+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
6+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
7+
use PhpSchool\PhpWorkshop\Input\Input;
8+
9+
class CliExerciseRunnerEvent extends ExerciseRunnerEvent
10+
{
11+
}

Diff for: src/Event/Event.php

+4-7
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@
1111
*/
1212
class Event implements EventInterface
1313
{
14-
/**
15-
* @var string
16-
*/
17-
private $name;
14+
private string $name;
1815

1916
/**
2017
* @var array<mixed>
2118
*/
22-
protected $parameters;
19+
protected array $parameters;
2320

2421
/**
2522
* @param string $name The event name.
@@ -52,13 +49,13 @@ public function getParameters(): array
5249
}
5350

5451
/**
55-
* Get a parameter by it's name.
52+
* Get a parameter by its name.
5653
*
5754
* @param string $name The name of the parameter.
5855
* @return mixed The value.
5956
* @throws InvalidArgumentException If the parameter by name does not exist.
6057
*/
61-
public function getParameter(string $name)
58+
public function getParameter(string $name): mixed
6259
{
6360
if (!array_key_exists($name, $this->parameters)) {
6461
throw new InvalidArgumentException(sprintf('Parameter: "%s" does not exist', $name));

Diff for: src/Event/EventDispatcher.php

+2-11
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,20 @@ class EventDispatcher
1616
/**
1717
* @var array<string, array<callable>>
1818
*/
19-
private $listeners = [];
19+
private array $listeners = [];
2020

2121
/**
2222
* @var ResultAggregator
2323
*/
24-
private $resultAggregator;
24+
private ResultAggregator $resultAggregator;
2525

26-
/**
27-
* @param ResultAggregator $resultAggregator
28-
*/
2926
public function __construct(ResultAggregator $resultAggregator)
3027
{
3128
$this->resultAggregator = $resultAggregator;
3229
}
3330

3431
/**
3532
* Dispatch an event. Can be any event object which implements `PhpSchool\PhpWorkshop\Event\EventInterface`.
36-
*
37-
* @param EventInterface $event
38-
* @return EventInterface
3933
*/
4034
public function dispatch(EventInterface $event): EventInterface
4135
{
@@ -103,9 +97,6 @@ public function removeListener(string $eventName, callable $callback): void
10397
* Insert a verifier callback which will execute at the given event name much like normal listeners.
10498
* A verifier should return an object which implements `PhpSchool\PhpWorkshop\Result\FailureInterface`
10599
* or `PhpSchool\PhpWorkshop\Result\SuccessInterface`. This result object will be added to the result aggregator.
106-
*
107-
* @param string $eventName
108-
* @param callable $verifier
109100
*/
110101
public function insertVerifier(string $eventName, callable $verifier): void
111102
{

Diff for: src/Event/EventInterface.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ public function getName(): string;
2626
public function getParameters(): array;
2727

2828
/**
29-
* Get a parameter by it's name.
29+
* Get a parameter by its name.
3030
*
3131
* @param string $name The name of the parameter.
3232
* @return mixed The value.
3333
* @throws InvalidArgumentException If the parameter by name does not exist.
3434
*/
35-
public function getParameter(string $name);
35+
public function getParameter(string $name): mixed;
3636
}

Diff for: src/ExerciseRunner/CgiRunner.php

+81-49
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpSchool\PhpWorkshop\Check\FileExistsCheck;
1111
use PhpSchool\PhpWorkshop\Check\PhpLintCheck;
1212
use PhpSchool\PhpWorkshop\Event\CgiExecuteEvent;
13+
use PhpSchool\PhpWorkshop\Event\CgiExerciseRunnerEvent;
1314
use PhpSchool\PhpWorkshop\Event\Event;
1415
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
1516
use PhpSchool\PhpWorkshop\Event\ExerciseRunnerEvent;
@@ -85,33 +86,84 @@ public function getRequiredChecks(): array
8586
}
8687

8788
/**
88-
* @param RequestInterface $request
89-
* @param string $fileName
90-
* @return CgiResultInterface
89+
* Verifies a solution by invoking PHP via the `php-cgi` binary, populating all the super globals with
90+
* the information from the request objects returned from the exercise. The exercise can return multiple
91+
* requests so the solution will be invoked for however many requests there are.
92+
*
93+
* Events dispatched (for each request):
94+
*
95+
* * cgi.verify.reference-execute.pre
96+
* * cgi.verify.reference.executing
97+
* * cgi.verify.reference-execute.fail (if the reference solution fails to execute)
98+
* * cgi.verify.student-execute.pre
99+
* * cgi.verify.student.executing
100+
* * cgi.verify.student-execute.fail (if the student's solution fails to execute)
101+
*
102+
* @param Input $input The command line arguments passed to the command.
103+
* @return CgiResult The result of the check.
91104
*/
92-
private function checkRequest(RequestInterface $request, string $fileName): CgiResultInterface
105+
public function verify(Input $input): ResultInterface
106+
{
107+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.start', $this->exercise, $input));
108+
$result = new CgiResult(
109+
array_map(
110+
function (RequestInterface $request) use ($input) {
111+
return $this->doVerify($request, $input);
112+
},
113+
$this->exercise->getRequests()
114+
)
115+
);
116+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $input));
117+
return $result;
118+
}
119+
120+
private function doVerify(RequestInterface $request, Input $input): CgiResultInterface
93121
{
94122
try {
95123
/** @var CgiExecuteEvent $event */
96124
$event = $this->eventDispatcher->dispatch(
97-
new CgiExecuteEvent('cgi.verify.reference-execute.pre', $request)
125+
new CgiExecuteEvent('cgi.verify.reference-execute.pre', $this->exercise, $input, $request)
98126
);
99127
$solutionResponse = $this->executePhpFile(
128+
$input,
100129
$this->exercise->getSolution()->getEntryPoint()->getAbsolutePath(),
101130
$event->getRequest(),
102131
'reference'
103132
);
104133
} catch (CodeExecutionException $e) {
105-
$this->eventDispatcher->dispatch(new Event('cgi.verify.reference-execute.fail', ['exception' => $e]));
134+
$this->eventDispatcher->dispatch(
135+
new CgiExecuteEvent(
136+
'cgi.verify.reference-execute.fail',
137+
$this->exercise,
138+
$input,
139+
$request,
140+
['exception' => $e]
141+
)
142+
);
106143
throw new SolutionExecutionException($e->getMessage());
107144
}
108145

109146
try {
110147
/** @var CgiExecuteEvent $event */
111-
$event = $this->eventDispatcher->dispatch(new CgiExecuteEvent('cgi.verify.student-execute.pre', $request));
112-
$userResponse = $this->executePhpFile($fileName, $event->getRequest(), 'student');
148+
$event = $this->eventDispatcher->dispatch(
149+
new CgiExecuteEvent('cgi.verify.student-execute.pre', $this->exercise, $input, $request)
150+
);
151+
$userResponse = $this->executePhpFile(
152+
$input,
153+
$input->getRequiredArgument('program'),
154+
$event->getRequest(),
155+
'student'
156+
);
113157
} catch (CodeExecutionException $e) {
114-
$this->eventDispatcher->dispatch(new Event('cgi.verify.student-execute.fail', ['exception' => $e]));
158+
$this->eventDispatcher->dispatch(
159+
new CgiExecuteEvent(
160+
'cgi.verify.student-execute.fail',
161+
$this->exercise,
162+
$input,
163+
$request,
164+
['exception' => $e]
165+
)
166+
);
115167
return GenericFailure::fromRequestAndCodeExecutionFailure($request, $e);
116168
}
117169

@@ -146,12 +198,18 @@ private function getHeaders(ResponseInterface $response): array
146198
* @param string $type
147199
* @return ResponseInterface
148200
*/
149-
private function executePhpFile(string $fileName, RequestInterface $request, string $type): ResponseInterface
150-
{
201+
private function executePhpFile(
202+
Input $input,
203+
string $fileName,
204+
RequestInterface $request,
205+
string $type
206+
): ResponseInterface {
151207
$process = $this->getPhpProcess(dirname($fileName), basename($fileName), $request);
152208

153209
$process->start();
154-
$this->eventDispatcher->dispatch(new CgiExecuteEvent(sprintf('cgi.verify.%s.executing', $type), $request));
210+
$this->eventDispatcher->dispatch(
211+
new CgiExecuteEvent(sprintf('cgi.verify.%s.executing', $type), $this->exercise, $input, $request)
212+
);
155213
$process->wait();
156214

157215
if (!$process->isSuccessful()) {
@@ -206,38 +264,6 @@ private function getPhpProcess(string $workingDirectory, string $fileName, Reque
206264
return $this->processFactory->create($processInput);
207265
}
208266

209-
/**
210-
* Verifies a solution by invoking PHP via the `php-cgi` binary, populating all the super globals with
211-
* the information from the request objects returned from the exercise. The exercise can return multiple
212-
* requests so the solution will be invoked for however many requests there are.
213-
*
214-
* Events dispatched (for each request):
215-
*
216-
* * cgi.verify.reference-execute.pre
217-
* * cgi.verify.reference.executing
218-
* * cgi.verify.reference-execute.fail (if the reference solution fails to execute)
219-
* * cgi.verify.student-execute.pre
220-
* * cgi.verify.student.executing
221-
* * cgi.verify.student-execute.fail (if the student's solution fails to execute)
222-
*
223-
* @param Input $input The command line arguments passed to the command.
224-
* @return CgiResult The result of the check.
225-
*/
226-
public function verify(Input $input): ResultInterface
227-
{
228-
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('cgi.verify.start', $this->exercise, $input));
229-
$result = new CgiResult(
230-
array_map(
231-
function (RequestInterface $request) use ($input) {
232-
return $this->checkRequest($request, $input->getRequiredArgument('program'));
233-
},
234-
$this->exercise->getRequests()
235-
)
236-
);
237-
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $input));
238-
return $result;
239-
}
240-
241267
/**
242268
* Runs a student's solution by invoking PHP via the `php-cgi` binary, populating all the super globals with
243269
* the information from the request objects returned from the exercise. The exercise can return multiple
@@ -257,12 +283,12 @@ function (RequestInterface $request) use ($input) {
257283
*/
258284
public function run(Input $input, OutputInterface $output): bool
259285
{
260-
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('cgi.run.start', $this->exercise, $input));
286+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.start', $this->exercise, $input));
261287
$success = true;
262288
foreach ($this->exercise->getRequests() as $i => $request) {
263289
/** @var CgiExecuteEvent $event */
264290
$event = $this->eventDispatcher->dispatch(
265-
new CgiExecuteEvent('cgi.run.student-execute.pre', $request)
291+
new CgiExecuteEvent('cgi.run.student-execute.pre', $this->exercise, $input, $request)
266292
);
267293
$process = $this->getPhpProcess(
268294
dirname($input->getRequiredArgument('program')),
@@ -272,7 +298,13 @@ public function run(Input $input, OutputInterface $output): bool
272298

273299
$process->start();
274300
$this->eventDispatcher->dispatch(
275-
new CgiExecuteEvent('cgi.run.student.executing', $request, ['output' => $output])
301+
new CgiExecuteEvent(
302+
'cgi.run.student.executing',
303+
$this->exercise,
304+
$input,
305+
$request,
306+
['output' => $output]
307+
)
276308
);
277309
$process->wait(function ($outputType, $outputBuffer) use ($output) {
278310
$output->write($outputBuffer);
@@ -286,10 +318,10 @@ public function run(Input $input, OutputInterface $output): bool
286318
$output->lineBreak();
287319

288320
$this->eventDispatcher->dispatch(
289-
new CgiExecuteEvent('cgi.run.student-execute.post', $request)
321+
new CgiExecuteEvent('cgi.run.student-execute.post', $this->exercise, $input, $request)
290322
);
291323
}
292-
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('cgi.run.finish', $this->exercise, $input));
324+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.finish', $this->exercise, $input));
293325
return $success;
294326
}
295327
}

0 commit comments

Comments
 (0)