Skip to content

Commit b8db6b2

Browse files
committed
Add run command, refactor tests
1 parent a8a5067 commit b8db6b2

17 files changed

+345
-30
lines changed

app/config.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use PhpSchool\PhpWorkshop\Command\MenuCommand;
4747
use PhpSchool\PhpWorkshop\Command\PrintCommand;
4848
use PhpSchool\PhpWorkshop\Command\VerifyCommand;
49+
use PhpSchool\PhpWorkshop\Command\RunCommand;
4950
use PhpSchool\PhpWorkshop\CommandDefinition;
5051
use PhpSchool\PhpWorkshop\CommandRouter;
5152
use PhpSchool\PhpWorkshop\ExerciseCheck\StdOutExerciseCheck;
@@ -95,13 +96,14 @@
9596
CommandRouter::class => factory(function (ContainerInterface $c) {
9697
return new CommandRouter(
9798
[
98-
new CommandDefinition('run', [], MenuCommand::class),
99+
new CommandDefinition('menu', [], MenuCommand::class),
99100
new CommandDefinition('help', [], HelpCommand::class),
100101
new CommandDefinition('print', [], PrintCommand::class),
101102
new CommandDefinition('verify', ['program'], VerifyCommand::class),
103+
new CommandDefinition('run', ['program'], RunCommand::class),
102104
new CommandDefinition('credits', [], CreditsCommand::class)
103105
],
104-
'run',
106+
'menu',
105107
$c
106108
);
107109
}),
@@ -112,7 +114,7 @@
112114
return $colors;
113115
}),
114116
OutputInterface::class => factory(function (ContainerInterface $c) {
115-
return new StdOutput($c->get(Color::class));
117+
return new StdOutput($c->get(Color::class), $c->get(TerminalInterface::class));
116118
}),
117119

118120
ExerciseRepository::class => factory(function (ContainerInterface $c) {
@@ -154,7 +156,17 @@
154156
$c->get(ResultsRenderer::class)
155157
);
156158
}),
157-
159+
160+
RunCommand::class => factory(function (ContainerInterface $c) {
161+
return new RunCommand(
162+
$c->get(ExerciseRepository::class),
163+
$c->get(ExerciseDispatcher::class),
164+
$c->get(UserState::class),
165+
$c->get(UserStateSerializer::class),
166+
$c->get(OutputInterface::class)
167+
);
168+
}),
169+
158170
CreditsCommand::class => factory(function (ContainerInterface $c) {
159171
return new CreditsCommand(
160172
$c->get('coreContributors'),

src/Command/RunCommand.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\Command;
4+
5+
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
6+
use PhpSchool\PhpWorkshop\ExerciseRepository;
7+
use PhpSchool\PhpWorkshop\ExerciseRunner;
8+
use PhpSchool\PhpWorkshop\Output\OutputInterface;
9+
use PhpSchool\PhpWorkshop\ResultRenderer\ResultsRenderer;
10+
use PhpSchool\PhpWorkshop\UserState;
11+
use PhpSchool\PhpWorkshop\UserStateSerializer;
12+
13+
/**
14+
* Class RunCommand
15+
* @package PhpSchool\PhpWorkshop\Command
16+
* @author Michael Woodward <[email protected]>
17+
*/
18+
class RunCommand
19+
{
20+
/**
21+
* @var OutputInterface
22+
*/
23+
private $output;
24+
25+
/**
26+
* @var ExerciseRepository
27+
*/
28+
private $exerciseRepository;
29+
30+
/**
31+
* @var UserState
32+
*/
33+
private $userState;
34+
35+
/**
36+
* @var UserStateSerializer
37+
*/
38+
private $userStateSerializer;
39+
40+
/**
41+
* @var ExerciseDispatcher
42+
*/
43+
private $exerciseDispatcher;
44+
45+
/**
46+
* @param ExerciseRepository $exerciseRepository
47+
* @param ExerciseDispatcher $exerciseDispatcher
48+
* @param UserState $userState
49+
* @param UserStateSerializer $userStateSerializer
50+
* @param OutputInterface $output
51+
*/
52+
public function __construct(
53+
ExerciseRepository $exerciseRepository,
54+
ExerciseDispatcher $exerciseDispatcher,
55+
UserState $userState,
56+
UserStateSerializer $userStateSerializer,
57+
OutputInterface $output
58+
) {
59+
$this->output = $output;
60+
$this->exerciseRepository = $exerciseRepository;
61+
$this->userState = $userState;
62+
$this->userStateSerializer = $userStateSerializer;
63+
$this->exerciseDispatcher = $exerciseDispatcher;
64+
}
65+
66+
/**
67+
* @param string $appName
68+
* @param string $program
69+
*
70+
* @return int|void
71+
*/
72+
public function __invoke($appName, $program)
73+
{
74+
if (!file_exists($program)) {
75+
$this->output->printError(
76+
sprintf('Could not run. File: "%s" does not exist', $program)
77+
);
78+
return 1;
79+
}
80+
$program = realpath($program);
81+
82+
if (!$this->userState->isAssignedExercise()) {
83+
$this->output->printError("No active exercises. Select one from the menu");
84+
return 1;
85+
}
86+
87+
$exercise = $this->exerciseRepository->findByName($this->userState->getCurrentExercise());
88+
89+
$this->exerciseDispatcher->run($exercise, $program, $this->output);
90+
}
91+
}

src/Command/VerifyCommand.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@
1717
*/
1818
class VerifyCommand
1919
{
20-
/**
21-
* @var \PhpSchool\PhpWorkshop\ExerciseRunner
22-
*/
23-
private $runner;
24-
2520
/**
2621
* @var OutputInterface
2722
*/

src/ExerciseRunner/CgiRunner.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,22 @@ public function run($fileName, OutputInterface $output)
196196
$event = $this->eventDispatcher->dispatch(new CgiExecuteEvent('cgi.run.usr-execute.pre', $request));
197197
$process = $this->getProcess($fileName, $event->getRequest());
198198

199+
$output->writeTitle("Request");
200+
$output->emptyLine();
201+
$output->writeRequest($request);
202+
203+
$output->writeTitle("Output");
204+
$output->emptyLine();
199205
$process->run(function ($outputType, $outputBuffer) use ($output) {
200206
$output->write($outputBuffer);
201207
});
208+
$output->emptyLine();
202209

203210
if (!$process->isSuccessful()) {
204211
$success = false;
205212
}
213+
214+
$output->lineBreak();
206215
}
207216
return $success;
208217
}

src/ExerciseRunner/CliRunner.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,24 @@ public function verify($fileName)
129129
*/
130130
public function run($fileName, OutputInterface $output)
131131
{
132+
/** @var CliExecuteEvent $event */
132133
$event = $this->eventDispatcher->dispatch(
133134
new CliExecuteEvent('cli.run.user-execute.pre', new ArrayObject($this->exercise->getArgs()))
134135
);
135136

136-
$process = $this->getPhpProcess($fileName, $event->getArgs());
137+
$args = $event->getArgs();
138+
139+
if (count($args)) {
140+
$glue = max(array_map('strlen', $args->getArrayCopy())) > 30 ? "\n" : ', ';
141+
142+
$output->writeTitle('Arguments');
143+
$output->write(implode($glue, $args->getArrayCopy()));
144+
}
145+
146+
$output->writeTitle("\nOutput");
147+
$process = $this->getPhpProcess($fileName, $args);
137148
$process->run(function ($outputType, $outputBuffer) use ($output) {
138-
$output->write($outputBuffer);
149+
$output->writeLine($outputBuffer);
139150
});
140151

141152
return $process->isSuccessful();

src/Factory/EventDispatcherFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public function __invoke(ContainerInterface $container)
3030
$codePatcherListener = $container->get(CodePatchListener::class);
3131
$dispatcher->listen('verify.pre.execute', [$codePatcherListener, 'patch']);
3232
$dispatcher->listen('verify.post.execute', [$codePatcherListener, 'revert']);
33+
$dispatcher->listen('run.start', [$codePatcherListener, 'patch']);
34+
$dispatcher->listen('run.finish', [$codePatcherListener, 'revert']);
3335

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

src/Output/OutputInterface.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace PhpSchool\PhpWorkshop\Output;
44

5+
use Psr\Http\Message\RequestInterface;
6+
use Zend\Diactoros\Request;
7+
58
/**
69
* Interface StdOutput
710
* @package PhpSchool\PhpWorkshop
@@ -33,4 +36,19 @@ public function writeLine($line);
3336
* Write empty line
3437
*/
3538
public function emptyLine();
39+
40+
/**
41+
* @return string
42+
*/
43+
public function lineBreak();
44+
45+
/**
46+
* @param string $title
47+
*/
48+
public function writeTitle($title);
49+
50+
/**
51+
* @param RequestInterface $request
52+
*/
53+
public function writeRequest(RequestInterface $request);
3654
}

src/Output/StdOutput.php

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
namespace PhpSchool\PhpWorkshop\Output;
44

55
use Colors\Color;
6+
use PhpSchool\CliMenu\Terminal\TerminalInterface;
7+
use Psr\Http\Message\RequestInterface;
8+
use Zend\Diactoros\Request;
69

710
/**
811
* Class StdOutput
@@ -17,11 +20,18 @@ class StdOutput implements OutputInterface
1720
private $color;
1821

1922
/**
20-
* @param Color $color
23+
* @var TerminalInterface
2124
*/
22-
public function __construct(Color $color)
25+
private $terminal;
26+
27+
/**
28+
* @param Color $color
29+
* @param TerminalInterface $terminal
30+
*/
31+
public function __construct(Color $color, TerminalInterface $terminal)
2332
{
2433
$this->color = $color;
34+
$this->terminal = $terminal;
2535
}
2636

2737
/**
@@ -32,11 +42,19 @@ public function printError($error)
3242
$length = strlen($error) + 2;
3343
echo "\n";
3444
echo sprintf(" %s\n", $this->color->__invoke(str_repeat(' ', $length))->bg_red());
35-
echo sprintf(" %s\n", $this->color->__invoke(sprintf(" %s ", $error))->bg_red()->white()->bold());
45+
echo sprintf(" %s\n", $this->color->__invoke(sprintf(' %s ', $error))->bg_red()->white()->bold());
3646
echo sprintf(" %s\n", $this->color->__invoke(str_repeat(' ', $length))->bg_red());
3747
echo "\n";
3848
}
3949

50+
/**
51+
* @param string $title
52+
*/
53+
public function writeTitle($title)
54+
{
55+
echo sprintf("\n%s\n", $this->color->__invoke($title)->underline()->bold());
56+
}
57+
4058
/**
4159
* @param string $content
4260
*/
@@ -70,4 +88,50 @@ public function emptyLine()
7088
{
7189
echo "\n";
7290
}
91+
92+
/**
93+
* @return string
94+
*/
95+
public function lineBreak()
96+
{
97+
echo $this->color->__invoke(str_repeat('', $this->terminal->getWidth()))->yellow();
98+
}
99+
100+
/**
101+
* @param RequestInterface $request
102+
*/
103+
public function writeRequest(RequestInterface $request)
104+
{
105+
echo sprintf("URL: %s\n", $request->getUri());
106+
echo sprintf("METHOD: %s\n", $request->getMethod());
107+
108+
if ($request->getHeaders()) {
109+
echo 'HEADERS:';
110+
}
111+
112+
$indent = false;
113+
foreach ($request->getHeaders() as $name => $values) {
114+
if ($indent) {
115+
echo str_repeat(' ', 9);
116+
}
117+
118+
echo sprintf(" %s: %s\n", $name, implode(', ', $values));
119+
$indent = true;
120+
}
121+
122+
if ($body = (string) $request->getBody()) {
123+
echo "\nBODY:";
124+
125+
switch ($request->getHeaderLine('Content-Type')) {
126+
case 'application/json':
127+
echo json_encode(json_decode($body, true), JSON_PRETTY_PRINT);
128+
break;
129+
default:
130+
echo $body;
131+
break;
132+
}
133+
134+
$this->emptyLine();
135+
}
136+
}
73137
}

src/Utils/ArrayObject.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
namespace PhpSchool\PhpWorkshop\Utils;
44

55
use ArrayIterator;
6+
use Countable;
67
use IteratorAggregate;
78

89
/**
910
* Class ArrayObject
1011
* @package PhpSchool\PhpWorkshop\Utils
1112
* @author Aydin Hassan <[email protected]>
1213
*/
13-
class ArrayObject implements IteratorAggregate
14+
class ArrayObject implements IteratorAggregate, Countable
1415
{
1516

1617
/**
@@ -81,4 +82,12 @@ public function getArrayCopy()
8182
{
8283
return $this->array;
8384
}
85+
86+
/**
87+
* @return int
88+
*/
89+
public function count()
90+
{
91+
return count($this->array);
92+
}
8493
}

0 commit comments

Comments
 (0)