Skip to content

Commit e18c8a7

Browse files
authored
Merge pull request #586 from flightphp/runway-reconfig
Changed it so runway commands are run from any repo
2 parents ad58c09 + 234b3dd commit e18c8a7

8 files changed

Lines changed: 438 additions & 9 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ coverage/
88
*.sublime*
99
clover.xml
1010
phpcs.xml
11+
.runway-config.json

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
},
4242
"require-dev": {
4343
"ext-pdo_sqlite": "*",
44+
"flightphp/runway": "^0.2.0",
4445
"league/container": "^4.2",
4546
"level-2/dice": "^4.0",
4647
"phpstan/extension-installer": "^1.3",

flight/Engine.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -652,10 +652,12 @@ public function _group(string $pattern, callable $callback, array $group_middlew
652652
* @param string $pattern URL pattern to match
653653
* @param callable|string $callback Callback function or string class->method
654654
* @param bool $pass_route Pass the matching route object to the callback
655+
*
656+
* @return Route
655657
*/
656-
public function _post(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): void
658+
public function _post(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): Route
657659
{
658-
$this->router()->map('POST ' . $pattern, $callback, $pass_route, $route_alias);
660+
return $this->router()->map('POST ' . $pattern, $callback, $pass_route, $route_alias);
659661
}
660662

661663
/**
@@ -664,10 +666,12 @@ public function _post(string $pattern, $callback, bool $pass_route = false, stri
664666
* @param string $pattern URL pattern to match
665667
* @param callable|string $callback Callback function or string class->method
666668
* @param bool $pass_route Pass the matching route object to the callback
669+
*
670+
* @return Route
667671
*/
668-
public function _put(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): void
672+
public function _put(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): Route
669673
{
670-
$this->router()->map('PUT ' . $pattern, $callback, $pass_route, $route_alias);
674+
return $this->router()->map('PUT ' . $pattern, $callback, $pass_route, $route_alias);
671675
}
672676

673677
/**
@@ -676,10 +680,12 @@ public function _put(string $pattern, $callback, bool $pass_route = false, strin
676680
* @param string $pattern URL pattern to match
677681
* @param callable|string $callback Callback function or string class->method
678682
* @param bool $pass_route Pass the matching route object to the callback
683+
*
684+
* @return Route
679685
*/
680-
public function _patch(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): void
686+
public function _patch(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): Route
681687
{
682-
$this->router()->map('PATCH ' . $pattern, $callback, $pass_route, $route_alias);
688+
return $this->router()->map('PATCH ' . $pattern, $callback, $pass_route, $route_alias);
683689
}
684690

685691
/**
@@ -688,10 +694,12 @@ public function _patch(string $pattern, $callback, bool $pass_route = false, str
688694
* @param string $pattern URL pattern to match
689695
* @param callable|string $callback Callback function or string class->method
690696
* @param bool $pass_route Pass the matching route object to the callback
697+
*
698+
* @return Route
691699
*/
692-
public function _delete(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): void
700+
public function _delete(string $pattern, $callback, bool $pass_route = false, string $route_alias = ''): Route
693701
{
694-
$this->router()->map('DELETE ' . $pattern, $callback, $pass_route, $route_alias);
702+
return $this->router()->map('DELETE ' . $pattern, $callback, $pass_route, $route_alias);
695703
}
696704

697705
/**
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace flight\commands;
6+
7+
use Nette\PhpGenerator\ClassType;
8+
use Nette\PhpGenerator\PhpFile;
9+
use Nette\PhpGenerator\PhpNamespace;
10+
11+
class ControllerCommand extends AbstractBaseCommand
12+
{
13+
/**
14+
* Construct
15+
*
16+
* @param array<string,mixed> $config JSON config from .runway-config.json
17+
*/
18+
public function __construct(array $config)
19+
{
20+
parent::__construct('make:controller', 'Create a controller', $config);
21+
$this->argument('<controller>', 'The name of the controller to create (with or without the Controller suffix)');
22+
}
23+
24+
/**
25+
* Executes the function
26+
*
27+
* @return void
28+
*/
29+
public function execute(string $controller)
30+
{
31+
$io = $this->app()->io();
32+
if (isset($this->config['app_root']) === false) {
33+
$io->error('app_root not set in .runway-config.json', true);
34+
return;
35+
}
36+
37+
if (!preg_match('/Controller$/', $controller)) {
38+
$controller .= 'Controller';
39+
}
40+
41+
$controllerPath = getcwd() . DIRECTORY_SEPARATOR . $this->config['app_root'] . 'controllers' . DIRECTORY_SEPARATOR . $controller . '.php';
42+
if (file_exists($controllerPath) === true) {
43+
$io->error($controller . ' already exists.', true);
44+
return;
45+
}
46+
47+
if (is_dir(dirname($controllerPath)) === false) {
48+
$io->info('Creating directory ' . dirname($controllerPath), true);
49+
mkdir(dirname($controllerPath), 0755, true);
50+
}
51+
52+
$file = new PhpFile();
53+
$file->setStrictTypes();
54+
55+
$namespace = new PhpNamespace('app\\controllers');
56+
$namespace->addUse('flight\\Engine');
57+
58+
$class = new ClassType($controller);
59+
$class->addProperty('app')
60+
->setVisibility('protected')
61+
->setType('flight\\Engine')
62+
->addComment('@var Engine');
63+
$method = $class->addMethod('__construct')
64+
->addComment('Constructor')
65+
->setVisibility('public')
66+
->setBody('$this->app = $app;');
67+
$method->addParameter('app')
68+
->setType('flight\\Engine');
69+
70+
$namespace->add($class);
71+
$file->addNamespace($namespace);
72+
73+
$this->persistClass($controller, $file);
74+
75+
$io->ok('Controller successfully created at ' . $controllerPath, true);
76+
}
77+
78+
/**
79+
* Saves the class name to a file
80+
*
81+
* @param string $controllerName Name of the Controller
82+
* @param PhpFile $file Class Object from Nette\PhpGenerator
83+
*
84+
* @return void
85+
*/
86+
protected function persistClass(string $controllerName, PhpFile $file)
87+
{
88+
$printer = new \Nette\PhpGenerator\PsrPrinter();
89+
file_put_contents(getcwd() . DIRECTORY_SEPARATOR . $this->config['app_root'] . 'controllers' . DIRECTORY_SEPARATOR . $controllerName . '.php', $printer->printFile($file));
90+
}
91+
}

flight/commands/RouteCommand.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace flight\commands;
6+
7+
use Flight;
8+
use flight\net\Route;
9+
10+
/**
11+
* @property-read ?bool $get
12+
* @property-read ?bool $post
13+
* @property-read ?bool $delete
14+
* @property-read ?bool $put
15+
* @property-read ?bool $patch
16+
*/
17+
class RouteCommand extends AbstractBaseCommand
18+
{
19+
/**
20+
* Construct
21+
*
22+
* @param array<string,mixed> $config JSON config from .runway-config.json
23+
*/
24+
public function __construct(array $config)
25+
{
26+
parent::__construct('routes', 'Gets all routes for an application', $config);
27+
28+
$this->option('--get', 'Only return GET requests');
29+
$this->option('--post', 'Only return POST requests');
30+
$this->option('--delete', 'Only return DELETE requests');
31+
$this->option('--put', 'Only return PUT requests');
32+
$this->option('--patch', 'Only return PATCH requests');
33+
}
34+
35+
/**
36+
* Executes the function
37+
*
38+
* @return void
39+
*/
40+
public function execute()
41+
{
42+
$io = $this->app()->io();
43+
44+
if(isset($this->config['index_root']) === false) {
45+
$io->error('index_root not set in .runway-config.json', true);
46+
return;
47+
}
48+
49+
$io->bold('Routes', true);
50+
51+
$cwd = getcwd();
52+
53+
$index_root = $cwd . '/' . $this->config['index_root'];
54+
55+
// This makes it so the framework doesn't actually execute
56+
Flight::map('start', function () {
57+
return;
58+
});
59+
include($index_root);
60+
$routes = Flight::router()->getRoutes();
61+
$arrayOfRoutes = [];
62+
foreach ($routes as $route) {
63+
if ($this->shouldAddRoute($route) === true) {
64+
$middlewares = [];
65+
if (!empty($route->middleware)) {
66+
try {
67+
$middlewares = array_map(function ($middleware) {
68+
$middleware_class_name = explode("\\", get_class($middleware));
69+
return preg_match("/^class@anonymous/", end($middleware_class_name)) ? 'Anonymous' : end($middleware_class_name);
70+
}, $route->middleware);
71+
} catch (\TypeError $e) {
72+
$middlewares[] = 'Bad Middleware';
73+
} finally {
74+
if(is_string($route->middleware) === true) {
75+
$middlewares[] = $route->middleware;
76+
}
77+
}
78+
}
79+
80+
$arrayOfRoutes[] = [
81+
'Pattern' => $route->pattern,
82+
'Methods' => implode(', ', $route->methods),
83+
'Alias' => $route->alias ?? '',
84+
'Streamed' => $route->is_streamed ? 'Yes' : 'No',
85+
'Middleware' => !empty($middlewares) ? implode(",", $middlewares) : '-'
86+
];
87+
}
88+
}
89+
$io->table($arrayOfRoutes, [
90+
'head' => 'boldGreen'
91+
]);
92+
}
93+
94+
/**
95+
* Whether or not to add the route based on the request
96+
*
97+
* @param Route $route Flight Route object
98+
*
99+
* @return boolean
100+
*/
101+
public function shouldAddRoute(Route $route)
102+
{
103+
$boolval = false;
104+
105+
$showAll = !$this->get && !$this->post && !$this->put && !$this->delete && !$this->patch;
106+
if ($showAll === true) {
107+
$boolval = true;
108+
} else {
109+
$methods = [ 'GET', 'POST', 'PUT', 'DELETE', 'PATCH' ];
110+
foreach ($methods as $method) {
111+
$lowercaseMethod = strtolower($method);
112+
if (
113+
$this->{$lowercaseMethod} === true &&
114+
(
115+
$route->methods[0] === '*' ||
116+
in_array($method, $route->methods, true) === true
117+
)
118+
) {
119+
$boolval = true;
120+
break;
121+
}
122+
}
123+
}
124+
return $boolval;
125+
}
126+
}

index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
require 'flight/Flight.php';
5+
require_once 'flight/Flight.php';
66
// require 'flight/autoload.php';
77

88
Flight::route('/', function () {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace tests\commands;
6+
7+
use Ahc\Cli\Application;
8+
use Ahc\Cli\IO\Interactor;
9+
use flight\commands\ControllerCommand;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class ControllerCommandTest extends TestCase
13+
{
14+
15+
protected static $in = __DIR__ . '/input.test';
16+
protected static $ou = __DIR__ . '/output.test';
17+
18+
public function setUp(): void
19+
{
20+
file_put_contents(static::$in, '', LOCK_EX);
21+
file_put_contents(static::$ou, '', LOCK_EX);
22+
}
23+
24+
public function tearDown(): void
25+
{
26+
// Make sure we clean up after ourselves:
27+
if (file_exists(static::$in)) {
28+
unlink(static::$in);
29+
}
30+
if (file_exists(static::$ou)) {
31+
unlink(static::$ou);
32+
}
33+
34+
if (file_exists(__DIR__.'/controllers/TestController.php')) {
35+
unlink(__DIR__.'/controllers/TestController.php');
36+
}
37+
38+
if (file_exists(__DIR__.'/controllers/')) {
39+
rmdir(__DIR__.'/controllers/');
40+
}
41+
}
42+
43+
protected function newApp(string $name, string $version = '')
44+
{
45+
$app = new Application($name, $version ?: '0.0.1', fn () => false);
46+
47+
return $app->io(new Interactor(static::$in, static::$ou));
48+
}
49+
50+
public function testConfigAppRootNotSet()
51+
{
52+
$app = $this->newApp('test', '0.0.1');
53+
$app->add(new ControllerCommand([]));
54+
$app->handle(['runway', 'make:controller', 'Test']);
55+
56+
$this->assertStringContainsString('app_root not set in .runway-config.json', file_get_contents(static::$ou));
57+
}
58+
59+
public function testControllerAlreadyExists()
60+
{
61+
$app = $this->newApp('test', '0.0.1');
62+
mkdir(__DIR__.'/controllers/');
63+
file_put_contents(__DIR__.'/controllers/TestController.php', '<?php class TestController {}');
64+
$app->add(new ControllerCommand(['app_root' => 'tests/commands/']));
65+
$app->handle(['runway', 'make:controller', 'Test']);
66+
67+
$this->assertStringContainsString('TestController already exists.', file_get_contents(static::$ou));
68+
}
69+
70+
public function testCreateController()
71+
{
72+
$app = $this->newApp('test', '0.0.1');
73+
$app->add(new ControllerCommand(['app_root' => 'tests/commands/']));
74+
$app->handle(['runway', 'make:controller', 'Test']);
75+
76+
$this->assertFileExists(__DIR__.'/controllers/TestController.php');
77+
}
78+
79+
}

0 commit comments

Comments
 (0)