diff --git a/app/config.php b/app/config.php index 17d0ffbb..e59ea364 100644 --- a/app/config.php +++ b/app/config.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Colors\Color; +use PhpSchool\PhpWorkshop\Listener\InitialCodeListener; use function DI\create; use function DI\factory; use Kadet\Highlighter\KeyLighter; @@ -201,17 +202,20 @@ }, //Listeners - PrepareSolutionListener::class => create(), - CodePatchListener::class => function (ContainerInterface $c) { + InitialCodeListener::class => function (ContainerInterface $c) { + return new InitialCodeListener(getcwd()); + }, + PrepareSolutionListener::class => create(), + CodePatchListener::class => function (ContainerInterface $c) { return new CodePatchListener($c->get(CodePatcher::class)); }, - SelfCheckListener::class => function (ContainerInterface $c) { + SelfCheckListener::class => function (ContainerInterface $c) { return new SelfCheckListener($c->get(ResultAggregator::class)); }, CheckExerciseAssignedListener::class => function (ContainerInterface $c) { return new CheckExerciseAssignedListener($c->get(UserState::class)); }, - ConfigureCommandListener::class => function (ContainerInterface $c) { + ConfigureCommandListener::class => function (ContainerInterface $c) { return new ConfigureCommandListener( $c->get(UserState::class), $c->get(ExerciseRepository::class), @@ -393,5 +397,10 @@ function (CgiResult $result) use ($c) { containerListener(SelfCheckListener::class) ], ], + 'create-initial-code' => [ + 'exercise.selected' => [ + containerListener(InitialCodeListener::class) + ] + ] ], ]; diff --git a/src/Exercise/ProvidesInitialCode.php b/src/Exercise/ProvidesInitialCode.php new file mode 100644 index 00000000..708fb996 --- /dev/null +++ b/src/Exercise/ProvidesInitialCode.php @@ -0,0 +1,21 @@ +dispatch(new Event('exercise.selected', ['exercise' => $exercise])); $eventDispatcher->dispatch( - new Event( - sprintf( - 'exercise.selected.%s', - AbstractExercise::normaliseName($exercise->getName()) - ) - ) + new Event(sprintf('exercise.selected.%s', AbstractExercise::normaliseName($exercise->getName()))) ); } } diff --git a/src/Listener/InitialCodeListener.php b/src/Listener/InitialCodeListener.php new file mode 100644 index 00000000..93e1cadd --- /dev/null +++ b/src/Listener/InitialCodeListener.php @@ -0,0 +1,48 @@ +workingDirectory = $workingDirectory; + } + + /** + * @param Event $event + */ + public function __invoke(Event $event): void + { + $exercise = $event->getParameter('exercise'); + + if (!$exercise instanceof ProvidesInitialCode) { + return; + } + + foreach ($exercise->getInitialCode()->getFiles() as $file) { + /** @var SolutionFile $file */ + if (!file_exists($this->workingDirectory . '/' . $file->getRelativePath())) { + copy($file->getAbsolutePath(), $this->workingDirectory . '/' . $file->getRelativePath()); + } + } + } +} diff --git a/src/Solution/SingleFileSolution.php b/src/Solution/SingleFileSolution.php index 151b9b8a..b32aac67 100644 --- a/src/Solution/SingleFileSolution.php +++ b/src/Solution/SingleFileSolution.php @@ -22,6 +22,10 @@ class SingleFileSolution implements SolutionInterface */ public function __construct(string $file) { + if (!file_exists($file)) { + throw new InvalidArgumentException(sprintf('File: "%s" does not exist', $file)); + } + $this->file = SolutionFile::fromFile((string) realpath($file)); } diff --git a/src/Solution/SolutionFile.php b/src/Solution/SolutionFile.php index fe4af028..b9a89d44 100644 --- a/src/Solution/SolutionFile.php +++ b/src/Solution/SolutionFile.php @@ -53,7 +53,7 @@ public static function fromFile(string $file): self * * @return string */ - private function getAbsolutePath(): string + public function getAbsolutePath(): string { return sprintf('%s/%s', $this->baseDirectory, $this->relativePath); } diff --git a/test/Asset/ExerciseWithInitialCode.php b/test/Asset/ExerciseWithInitialCode.php new file mode 100644 index 00000000..e32a9467 --- /dev/null +++ b/test/Asset/ExerciseWithInitialCode.php @@ -0,0 +1,53 @@ +filesystem = new Filesystem(); + + $this->cwd = sprintf('%s/%s', str_replace('\\', '/', sys_get_temp_dir()), $this->getName()); + mkdir($this->cwd, 0775, true); + } + + public function testExerciseCodeIsCopiedIfExerciseProvidesInitialCode(): void + { + $exercise = new ExerciseWithInitialCode(); + + $event = new Event('exercise.selected', ['exercise' => $exercise]); + + $listener = new InitialCodeListener($this->cwd); + $listener->__invoke($event); + + $this->assertFileExists($this->cwd . '/init-solution.php'); + $this->assertFileEquals( + $exercise->getInitialCode()->getFiles()[0]->getAbsolutePath(), + $this->cwd . '/init-solution.php' + ); + } + + public function testExerciseCodeIsNotCopiedIfExerciseDoesNotProvideInitialCode(): void + { + $exercise = new CliExerciseImpl(); + + $event = new Event('exercise.selected', ['exercise' => $exercise]); + + $listener = new InitialCodeListener($this->cwd); + $listener->__invoke($event); + + $this->assertEmpty(array_diff(scandir($this->cwd), ['.', '..'])); + } + + public function tearDown(): void + { + $this->filesystem->remove($this->cwd); + } +}