Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e97dcb3

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

17 files changed

+277
-278
lines changed

‎app/config.php‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
3939
use PhpSchool\PhpWorkshop\ExerciseRenderer;
4040
use PhpSchool\PhpWorkshop\ExerciseRepository;
41+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContextFactory;
42+
use PhpSchool\PhpWorkshop\ExerciseRunner\EnvironmentManager;
4143
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CgiRunnerFactory;
4244
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory;
4345
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CustomVerifyingRunnerFactory;
@@ -134,7 +136,8 @@
134136
$c->get(RunnerManager::class),
135137
$c->get(ResultAggregator::class),
136138
$c->get(EventDispatcher::class),
137-
$c->get(CheckRepository::class)
139+
$c->get(CheckRepository::class),
140+
new ExecutionContextFactory()
138141
);
139142
},
140143
ResultAggregator::class => create(ResultAggregator::class),
@@ -186,11 +189,23 @@
186189
EventDispatcher::class => factory(EventDispatcherFactory::class),
187190
EventDispatcherFactory::class => create(),
188191

192+
EnvironmentManager::class => function (ContainerInterface $c) {
193+
return new EnvironmentManager($c->get(Filesystem::class));
194+
},
195+
189196
//Exercise Runners
190197
RunnerManager::class => function (ContainerInterface $c) {
191198
$manager = new RunnerManager();
192-
$manager->addFactory(new CliRunnerFactory($c->get(EventDispatcher::class), $c->get(ProcessFactory::class)));
193-
$manager->addFactory(new CgiRunnerFactory($c->get(EventDispatcher::class), $c->get(ProcessFactory::class)));
199+
$manager->addFactory(new CliRunnerFactory(
200+
$c->get(EventDispatcher::class),
201+
$c->get(ProcessFactory::class),
202+
$c->get(EnvironmentManager::class)
203+
));
204+
$manager->addFactory(new CgiRunnerFactory(
205+
$c->get(EventDispatcher::class),
206+
$c->get(ProcessFactory::class),
207+
$c->get(EnvironmentManager::class)
208+
));
194209
$manager->addFactory(new CustomVerifyingRunnerFactory());
195210
return $manager;
196211
},

‎src/ExerciseDispatcher.php‎

Lines changed: 17 additions & 35 deletions
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+
privateRunnerManager $runnerManager,
49+
privateResultAggregator $results,
50+
privateEventDispatcher $eventDispatcher,
51+
privateCheckRepository $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
}

‎src/ExerciseRunner/CgiRunner.php‎

Lines changed: 43 additions & 27 deletions
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;
@@ -63,7 +64,8 @@ class CgiRunner implements ExerciseRunnerInterface
6364
public function __construct(
6465
private CgiExercise $exercise,
6566
private EventDispatcher $eventDispatcher,
66-
private ProcessFactory $processFactory
67+
private ProcessFactory $processFactory,
68+
private EnvironmentManager $environmentManager
6769
) {
6870
}
6971

@@ -99,36 +101,43 @@ public function getRequiredChecks(): array
99101
* * cgi.verify.student.executing
100102
* * cgi.verify.student-execute.fail (if the student's solution fails to execute)
101103
*
102-
* @param Input $input The command line arguments passed to the command.
104+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
103105
* @return CgiResult The result of the check.
104106
*/
105-
public function verify(Input$input): ResultInterface
107+
public function verify(ExecutionContext$context): ResultInterface
106108
{
107109
$scenario = $this->exercise->defineTestScenario();
108110

109-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.start', $this->exercise, $input));
111+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.start', $this->exercise, $context->getInput()));
112+
113+
$this->environmentManager->prepareStudent($context, $scenario);
114+
$this->environmentManager->prepareReference($context, $scenario);
110115

111116
$result = new CgiResult(
112117
array_map(
113-
function (RequestInterface $request) use ($input) {
114-
return $this->doVerify($request, $input);
118+
function (RequestInterface $request) use ($context) {
119+
return $this->doVerify($request, $context);
115120
},
116121
$scenario->getExecutions()
117122
)
118123
);
119-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $input));
124+
125+
$this->environmentManager->cleanup($context, $scenario);
126+
127+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $context->getInput()));
120128
return $result;
121129
}
122130

123-
private function doVerify(RequestInterface $request, Input$input): CgiResultInterface
131+
private function doVerify(RequestInterface $request, ExecutionContext$context): CgiResultInterface
124132
{
125133
try {
126134
/** @var CgiExecuteEvent $event */
127135
$event = $this->eventDispatcher->dispatch(
128-
new CgiExecuteEvent('cgi.verify.reference-execute.pre', $this->exercise, $input, $request)
136+
new CgiExecuteEvent('cgi.verify.reference-execute.pre', $this->exercise, $context->getInput(), $request)
129137
);
130138
$solutionResponse = $this->executePhpFile(
131-
$input,
139+
$context,
140+
$context->getReferenceExecutionDirectory(),
132141
$this->exercise->getSolution()->getEntryPoint()->getAbsolutePath(),
133142
$event->getRequest(),
134143
'reference'
@@ -138,7 +147,7 @@ private function doVerify(RequestInterface $request, Input $input): CgiResultInt
138147
new CgiExecuteEvent(
139148
'cgi.verify.reference-execute.fail',
140149
$this->exercise,
141-
$input,
150+
$context->getInput(),
142151
$request,
143152
['exception' => $e]
144153
)
@@ -149,11 +158,12 @@ private function doVerify(RequestInterface $request, Input $input): CgiResultInt
149158
try {
150159
/** @var CgiExecuteEvent $event */
151160
$event = $this->eventDispatcher->dispatch(
152-
new CgiExecuteEvent('cgi.verify.student-execute.pre', $this->exercise, $input, $request)
161+
new CgiExecuteEvent('cgi.verify.student-execute.pre', $this->exercise, $context->getInput(), $request)
153162
);
154163
$userResponse = $this->executePhpFile(
155-
$input,
156-
$input->getRequiredArgument('program'),
164+
$context,
165+
$context->getStudentExecutionDirectory(),
166+
$context->getEntryPoint(),
157167
$event->getRequest(),
158168
'student'
159169
);
@@ -162,7 +172,7 @@ private function doVerify(RequestInterface $request, Input $input): CgiResultInt
162172
new CgiExecuteEvent(
163173
'cgi.verify.student-execute.fail',
164174
$this->exercise,
165-
$input,
175+
$context->getInput(),
166176
$request,
167177
['exception' => $e]
168178
)
@@ -202,16 +212,17 @@ private function getHeaders(ResponseInterface $response): array
202212
* @return ResponseInterface
203213
*/
204214
private function executePhpFile(
205-
Input $input,
215+
ExecutionContext $context,
216+
string $workingDirectory,
206217
string $fileName,
207218
RequestInterface $request,
208219
string $type
209220
): ResponseInterface {
210-
$process = $this->getPhpProcess(dirname($fileName), basename($fileName), $request);
221+
$process = $this->getPhpProcess($workingDirectory, $fileName, $request);
211222

212223
$process->start();
213224
$this->eventDispatcher->dispatch(
214-
new CgiExecuteEvent(sprintf('cgi.verify.%s.executing', $type), $this->exercise, $input, $request)
225+
new CgiExecuteEvent(sprintf('cgi.verify.%s.executing', $type), $this->exercise, $context->getInput(), $request)
215226
);
216227
$process->wait();
217228

@@ -280,25 +291,27 @@ private function getPhpProcess(string $workingDirectory, string $fileName, Reque
280291
* * cgi.run.student-execute.pre
281292
* * cgi.run.student.executing
282293
*
283-
* @param Input $input The command line arguments passed to the command.
294+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
284295
* @param OutputInterface $output A wrapper around STDOUT.
285296
* @return bool If the solution was successfully executed, eg. exit code was 0.
286297
*/
287-
public function run(Input$input, OutputInterface $output): bool
298+
public function run(ExecutionContext$context, OutputInterface $output): bool
288299
{
289300
$scenario = $this->exercise->defineTestScenario();
290301

291-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.start', $this->exercise, $input));
302+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.start', $this->exercise, $context->getInput()));
303+
304+
$this->environmentManager->prepareStudent($context, $scenario);
292305

293306
$success = true;
294307
foreach ($scenario->getExecutions() as $i => $request) {
295308
/** @var CgiExecuteEvent $event */
296309
$event = $this->eventDispatcher->dispatch(
297-
new CgiExecuteEvent('cgi.run.student-execute.pre', $this->exercise, $input, $request)
310+
new CgiExecuteEvent('cgi.run.student-execute.pre', $this->exercise, $context->getInput(), $request)
298311
);
299312
$process = $this->getPhpProcess(
300-
dirname($input->getRequiredArgument('program')),
301-
$input->getRequiredArgument('program'),
313+
$context->getStudentExecutionDirectory(),
314+
$context->getEntryPoint(),
302315
$event->getRequest()
303316
);
304317

@@ -307,7 +320,7 @@ public function run(Input $input, OutputInterface $output): bool
307320
new CgiExecuteEvent(
308321
'cgi.run.student.executing',
309322
$this->exercise,
310-
$input,
323+
$context->getInput(),
311324
$request,
312325
['output' => $output]
313326
)
@@ -324,10 +337,13 @@ public function run(Input $input, OutputInterface $output): bool
324337
$output->lineBreak();
325338

326339
$this->eventDispatcher->dispatch(
327-
new CgiExecuteEvent('cgi.run.student-execute.post', $this->exercise, $input, $request)
340+
new CgiExecuteEvent('cgi.run.student-execute.post', $this->exercise, $context->getInput(), $request)
328341
);
329342
}
330-
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.finish', $this->exercise, $input));
343+
344+
$this->environmentManager->cleanup($context, $scenario);
345+
346+
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.finish', $this->exercise, $context->getInput()));
331347
return $success;
332348
}
333349
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /