Skip to content

Commit ecc7d97

Browse files
committed
Use context objects in dispatcher and runners
1 parent 0964eb3 commit ecc7d97

13 files changed

+278
-258
lines changed

Diff for: app/config.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
3939
use PhpSchool\PhpWorkshop\ExerciseRenderer;
4040
use PhpSchool\PhpWorkshop\ExerciseRepository;
41+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContextFactory;
4142
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CgiRunnerFactory;
4243
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory;
4344
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CustomVerifyingRunnerFactory;
@@ -134,7 +135,8 @@
134135
$c->get(RunnerManager::class),
135136
$c->get(ResultAggregator::class),
136137
$c->get(EventDispatcher::class),
137-
$c->get(CheckRepository::class)
138+
$c->get(CheckRepository::class),
139+
new ExecutionContextFactory()
138140
);
139141
},
140142
ResultAggregator::class => create(ResultAggregator::class),

Diff for: src/ExerciseDispatcher.php

+17-35
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PhpSchool\PhpWorkshop\Exception\ExerciseNotConfiguredException;
1515
use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException;
1616
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
17+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
1718
use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager;
1819
use PhpSchool\PhpWorkshop\Input\Input;
1920
use PhpSchool\PhpWorkshop\Output\OutputInterface;
@@ -29,49 +30,26 @@ class ExerciseDispatcher
2930
/**
3031
* @var array<SimpleCheckInterface>
3132
*/
32-
private $checksToRunBefore = [];
33+
private array $checksToRunBefore = [];
3334

3435
/**
3536
* @var array<SimpleCheckInterface>
3637
*/
37-
private $checksToRunAfter = [];
38+
private array $checksToRunAfter = [];
3839

39-
/**
40-
* @var RunnerManager
41-
*/
42-
private $runnerManager;
43-
44-
/**
45-
* @var ResultAggregator
46-
*/
47-
private $results;
48-
49-
/**
50-
* @var EventDispatcher
51-
*/
52-
private $eventDispatcher;
53-
54-
/**
55-
* @var CheckRepository
56-
*/
57-
private $checkRepository;
5840

5941
/**
6042
* @param RunnerManager $runnerManager Factory capable of building an exercise runner based on the exercise type.
61-
* @param ResultAggregator $resultAggregator
43+
* @param ResultAggregator $results
6244
* @param EventDispatcher $eventDispatcher
6345
* @param CheckRepository $checkRepository
6446
*/
6547
public function __construct(
66-
RunnerManager $runnerManager,
67-
ResultAggregator $resultAggregator,
68-
EventDispatcher $eventDispatcher,
69-
CheckRepository $checkRepository
48+
private RunnerManager $runnerManager,
49+
private ResultAggregator $results,
50+
private EventDispatcher $eventDispatcher,
51+
private CheckRepository $checkRepository,
7052
) {
71-
$this->runnerManager = $runnerManager;
72-
$this->results = $resultAggregator;
73-
$this->eventDispatcher = $eventDispatcher;
74-
$this->checkRepository = $checkRepository;
7553
}
7654

7755
/**
@@ -129,6 +107,8 @@ public function requireCheck(string $requiredCheck): void
129107
*/
130108
public function verify(ExerciseInterface $exercise, Input $input): ResultAggregator
131109
{
110+
$context = ExecutionContext::fromInputAndExercise($input, $exercise);
111+
132112
$runner = $this->runnerManager->getRunner($exercise);
133113

134114
$exercise->defineListeners($this->eventDispatcher);
@@ -143,7 +123,7 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega
143123
$this->validateChecks($this->checksToRunAfter, $exercise);
144124

145125
foreach ($this->checksToRunBefore as $check) {
146-
$this->results->add($check->check($exercise, $input));
126+
$this->results->add($check->check($context->getExercise(), $context->getInput()));
147127

148128
if (!$this->results->isSuccessful()) {
149129
return $this->results;
@@ -153,13 +133,13 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega
153133
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.pre.execute', $exercise, $input));
154134

155135
try {
156-
$this->results->add($runner->verify($input));
136+
$this->results->add($runner->verify($context));
157137
} finally {
158138
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.post.execute', $exercise, $input));
159139
}
160140

161141
foreach ($this->checksToRunAfter as $check) {
162-
$this->results->add($check->check($exercise, $input));
142+
$this->results->add($check->check($context->getExercise(), $context->getInput()));
163143
}
164144

165145
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.post.check', $exercise, $input));
@@ -181,11 +161,13 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega
181161
*/
182162
public function run(ExerciseInterface $exercise, Input $input, OutputInterface $output): bool
183163
{
164+
$context = ExecutionContext::fromInputAndExercise($input, $exercise);
165+
184166
$exercise->defineListeners($this->eventDispatcher);
185167

186168
/** @var PhpLintCheck $lint */
187169
$lint = $this->checkRepository->getByClass(PhpLintCheck::class);
188-
$result = $lint->check($exercise, $input);
170+
$result = $lint->check($context->getExercise(), $context->getInput());
189171

190172
if ($result instanceof FailureInterface) {
191173
throw CouldNotRunException::fromFailure($result);
@@ -196,7 +178,7 @@ public function run(ExerciseInterface $exercise, Input $input, OutputInterface $
196178
try {
197179
$exitStatus = $this->runnerManager
198180
->getRunner($exercise)
199-
->run($input, $output);
181+
->run($context, $output);
200182
} finally {
201183
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('run.finish', $exercise, $input));
202184
}

Diff for: src/ExerciseRunner/CgiRunner.php

+30-28
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PhpSchool\PhpWorkshop\Exception\SolutionExecutionException;
1919
use PhpSchool\PhpWorkshop\Exercise\CgiExercise;
2020
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
21+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
2122
use PhpSchool\PhpWorkshop\Input\Input;
2223
use PhpSchool\PhpWorkshop\Output\OutputInterface;
2324
use PhpSchool\PhpWorkshop\Process\ProcessFactory;
@@ -99,36 +100,36 @@ public function getRequiredChecks(): array
99100
* * cgi.verify.student.executing
100101
* * cgi.verify.student-execute.fail (if the student's solution fails to execute)
101102
*
102-
* @param Input $input The command line arguments passed to the command.
103+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
103104
* @return CgiResult The result of the check.
104105
*/
105-
public function verify(Input $input): ResultInterface
106+
public function verify(ExecutionContext $context): ResultInterface
106107
{
107108
$scenario = $this->exercise->defineTestScenario();
108109

109-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.start', $this->exercise, $input));
110-
110+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.start', $this->exercise, $context->getInput()));
111111
$result = new CgiResult(
112112
array_map(
113-
function (RequestInterface $request) use ($input) {
114-
return $this->doVerify($request, $input);
113+
function (RequestInterface $request) use ($context) {
114+
return $this->doVerify($request, $context);
115115
},
116116
$scenario->getExecutions()
117117
)
118118
);
119-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $input));
119+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $context->getInput()));
120120
return $result;
121121
}
122122

123-
private function doVerify(RequestInterface $request, Input $input): CgiResultInterface
123+
private function doVerify(RequestInterface $request, ExecutionContext $context): CgiResultInterface
124124
{
125125
try {
126126
/** @var CgiExecuteEvent $event */
127127
$event = $this->eventDispatcher->dispatch(
128-
new CgiExecuteEvent('cgi.verify.reference-execute.pre', $this->exercise, $input, $request)
128+
new CgiExecuteEvent('cgi.verify.reference-execute.pre', $this->exercise, $context->getInput(), $request)
129129
);
130130
$solutionResponse = $this->executePhpFile(
131-
$input,
131+
$context,
132+
$context->getReferenceExecutionDirectory(),
132133
$this->exercise->getSolution()->getEntryPoint()->getAbsolutePath(),
133134
$event->getRequest(),
134135
'reference'
@@ -138,7 +139,7 @@ private function doVerify(RequestInterface $request, Input $input): CgiResultInt
138139
new CgiExecuteEvent(
139140
'cgi.verify.reference-execute.fail',
140141
$this->exercise,
141-
$input,
142+
$context->getInput(),
142143
$request,
143144
['exception' => $e]
144145
)
@@ -149,11 +150,12 @@ private function doVerify(RequestInterface $request, Input $input): CgiResultInt
149150
try {
150151
/** @var CgiExecuteEvent $event */
151152
$event = $this->eventDispatcher->dispatch(
152-
new CgiExecuteEvent('cgi.verify.student-execute.pre', $this->exercise, $input, $request)
153+
new CgiExecuteEvent('cgi.verify.student-execute.pre', $this->exercise, $context->getInput(), $request)
153154
);
154155
$userResponse = $this->executePhpFile(
155-
$input,
156-
$input->getRequiredArgument('program'),
156+
$context,
157+
$context->getStudentExecutionDirectory(),
158+
$context->getEntryPoint(),
157159
$event->getRequest(),
158160
'student'
159161
);
@@ -162,7 +164,7 @@ private function doVerify(RequestInterface $request, Input $input): CgiResultInt
162164
new CgiExecuteEvent(
163165
'cgi.verify.student-execute.fail',
164166
$this->exercise,
165-
$input,
167+
$context->getInput(),
166168
$request,
167169
['exception' => $e]
168170
)
@@ -202,16 +204,17 @@ private function getHeaders(ResponseInterface $response): array
202204
* @return ResponseInterface
203205
*/
204206
private function executePhpFile(
205-
Input $input,
207+
ExecutionContext $context,
208+
string $workingDirectory,
206209
string $fileName,
207210
RequestInterface $request,
208211
string $type
209212
): ResponseInterface {
210-
$process = $this->getPhpProcess(dirname($fileName), basename($fileName), $request);
213+
$process = $this->getPhpProcess($workingDirectory, $fileName, $request);
211214

212215
$process->start();
213216
$this->eventDispatcher->dispatch(
214-
new CgiExecuteEvent(sprintf('cgi.verify.%s.executing', $type), $this->exercise, $input, $request)
217+
new CgiExecuteEvent(sprintf('cgi.verify.%s.executing', $type), $this->exercise, $context->getInput(), $request)
215218
);
216219
$process->wait();
217220

@@ -280,25 +283,24 @@ private function getPhpProcess(string $workingDirectory, string $fileName, Reque
280283
* * cgi.run.student-execute.pre
281284
* * cgi.run.student.executing
282285
*
283-
* @param Input $input The command line arguments passed to the command.
286+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
284287
* @param OutputInterface $output A wrapper around STDOUT.
285288
* @return bool If the solution was successfully executed, eg. exit code was 0.
286289
*/
287-
public function run(Input $input, OutputInterface $output): bool
290+
public function run(ExecutionContext $context, OutputInterface $output): bool
288291
{
289292
$scenario = $this->exercise->defineTestScenario();
290293

291-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.start', $this->exercise, $input));
292-
294+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.start', $this->exercise, $context->getInput()));
293295
$success = true;
294296
foreach ($scenario->getExecutions() as $i => $request) {
295297
/** @var CgiExecuteEvent $event */
296298
$event = $this->eventDispatcher->dispatch(
297-
new CgiExecuteEvent('cgi.run.student-execute.pre', $this->exercise, $input, $request)
299+
new CgiExecuteEvent('cgi.run.student-execute.pre', $this->exercise, $context->getInput(), $request)
298300
);
299301
$process = $this->getPhpProcess(
300-
dirname($input->getRequiredArgument('program')),
301-
$input->getRequiredArgument('program'),
302+
$context->getStudentExecutionDirectory(),
303+
$context->getEntryPoint(),
302304
$event->getRequest()
303305
);
304306

@@ -307,7 +309,7 @@ public function run(Input $input, OutputInterface $output): bool
307309
new CgiExecuteEvent(
308310
'cgi.run.student.executing',
309311
$this->exercise,
310-
$input,
312+
$context->getInput(),
311313
$request,
312314
['output' => $output]
313315
)
@@ -324,10 +326,10 @@ public function run(Input $input, OutputInterface $output): bool
324326
$output->lineBreak();
325327

326328
$this->eventDispatcher->dispatch(
327-
new CgiExecuteEvent('cgi.run.student-execute.post', $this->exercise, $input, $request)
329+
new CgiExecuteEvent('cgi.run.student-execute.post', $this->exercise, $context->getInput(), $request)
328330
);
329331
}
330-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.finish', $this->exercise, $input));
332+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.finish', $this->exercise, $context->getInput()));
331333
return $success;
332334
}
333335
}

0 commit comments

Comments
 (0)