mirror of https://github.com/flightphp/core
Merge pull request #586 from flightphp/runway-reconfig
Changed it so runway commands are run from any repopull/588/head
commit
e18c8a7317
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace flight\commands;
|
||||||
|
|
||||||
|
use Nette\PhpGenerator\ClassType;
|
||||||
|
use Nette\PhpGenerator\PhpFile;
|
||||||
|
use Nette\PhpGenerator\PhpNamespace;
|
||||||
|
|
||||||
|
class ControllerCommand extends AbstractBaseCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $config JSON config from .runway-config.json
|
||||||
|
*/
|
||||||
|
public function __construct(array $config)
|
||||||
|
{
|
||||||
|
parent::__construct('make:controller', 'Create a controller', $config);
|
||||||
|
$this->argument('<controller>', 'The name of the controller to create (with or without the Controller suffix)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the function
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function execute(string $controller)
|
||||||
|
{
|
||||||
|
$io = $this->app()->io();
|
||||||
|
if (isset($this->config['app_root']) === false) {
|
||||||
|
$io->error('app_root not set in .runway-config.json', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/Controller$/', $controller)) {
|
||||||
|
$controller .= 'Controller';
|
||||||
|
}
|
||||||
|
|
||||||
|
$controllerPath = getcwd() . DIRECTORY_SEPARATOR . $this->config['app_root'] . 'controllers' . DIRECTORY_SEPARATOR . $controller . '.php';
|
||||||
|
if (file_exists($controllerPath) === true) {
|
||||||
|
$io->error($controller . ' already exists.', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dir(dirname($controllerPath)) === false) {
|
||||||
|
$io->info('Creating directory ' . dirname($controllerPath), true);
|
||||||
|
mkdir(dirname($controllerPath), 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = new PhpFile();
|
||||||
|
$file->setStrictTypes();
|
||||||
|
|
||||||
|
$namespace = new PhpNamespace('app\\controllers');
|
||||||
|
$namespace->addUse('flight\\Engine');
|
||||||
|
|
||||||
|
$class = new ClassType($controller);
|
||||||
|
$class->addProperty('app')
|
||||||
|
->setVisibility('protected')
|
||||||
|
->setType('flight\\Engine')
|
||||||
|
->addComment('@var Engine');
|
||||||
|
$method = $class->addMethod('__construct')
|
||||||
|
->addComment('Constructor')
|
||||||
|
->setVisibility('public')
|
||||||
|
->setBody('$this->app = $app;');
|
||||||
|
$method->addParameter('app')
|
||||||
|
->setType('flight\\Engine');
|
||||||
|
|
||||||
|
$namespace->add($class);
|
||||||
|
$file->addNamespace($namespace);
|
||||||
|
|
||||||
|
$this->persistClass($controller, $file);
|
||||||
|
|
||||||
|
$io->ok('Controller successfully created at ' . $controllerPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the class name to a file
|
||||||
|
*
|
||||||
|
* @param string $controllerName Name of the Controller
|
||||||
|
* @param PhpFile $file Class Object from Nette\PhpGenerator
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function persistClass(string $controllerName, PhpFile $file)
|
||||||
|
{
|
||||||
|
$printer = new \Nette\PhpGenerator\PsrPrinter();
|
||||||
|
file_put_contents(getcwd() . DIRECTORY_SEPARATOR . $this->config['app_root'] . 'controllers' . DIRECTORY_SEPARATOR . $controllerName . '.php', $printer->printFile($file));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace flight\commands;
|
||||||
|
|
||||||
|
use Flight;
|
||||||
|
use flight\net\Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property-read ?bool $get
|
||||||
|
* @property-read ?bool $post
|
||||||
|
* @property-read ?bool $delete
|
||||||
|
* @property-read ?bool $put
|
||||||
|
* @property-read ?bool $patch
|
||||||
|
*/
|
||||||
|
class RouteCommand extends AbstractBaseCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $config JSON config from .runway-config.json
|
||||||
|
*/
|
||||||
|
public function __construct(array $config)
|
||||||
|
{
|
||||||
|
parent::__construct('routes', 'Gets all routes for an application', $config);
|
||||||
|
|
||||||
|
$this->option('--get', 'Only return GET requests');
|
||||||
|
$this->option('--post', 'Only return POST requests');
|
||||||
|
$this->option('--delete', 'Only return DELETE requests');
|
||||||
|
$this->option('--put', 'Only return PUT requests');
|
||||||
|
$this->option('--patch', 'Only return PATCH requests');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the function
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
$io = $this->app()->io();
|
||||||
|
|
||||||
|
if(isset($this->config['index_root']) === false) {
|
||||||
|
$io->error('index_root not set in .runway-config.json', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->bold('Routes', true);
|
||||||
|
|
||||||
|
$cwd = getcwd();
|
||||||
|
|
||||||
|
$index_root = $cwd . '/' . $this->config['index_root'];
|
||||||
|
|
||||||
|
// This makes it so the framework doesn't actually execute
|
||||||
|
Flight::map('start', function () {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
include($index_root);
|
||||||
|
$routes = Flight::router()->getRoutes();
|
||||||
|
$arrayOfRoutes = [];
|
||||||
|
foreach ($routes as $route) {
|
||||||
|
if ($this->shouldAddRoute($route) === true) {
|
||||||
|
$middlewares = [];
|
||||||
|
if (!empty($route->middleware)) {
|
||||||
|
try {
|
||||||
|
$middlewares = array_map(function ($middleware) {
|
||||||
|
$middleware_class_name = explode("\\", get_class($middleware));
|
||||||
|
return preg_match("/^class@anonymous/", end($middleware_class_name)) ? 'Anonymous' : end($middleware_class_name);
|
||||||
|
}, $route->middleware);
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
$middlewares[] = 'Bad Middleware';
|
||||||
|
} finally {
|
||||||
|
if(is_string($route->middleware) === true) {
|
||||||
|
$middlewares[] = $route->middleware;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrayOfRoutes[] = [
|
||||||
|
'Pattern' => $route->pattern,
|
||||||
|
'Methods' => implode(', ', $route->methods),
|
||||||
|
'Alias' => $route->alias ?? '',
|
||||||
|
'Streamed' => $route->is_streamed ? 'Yes' : 'No',
|
||||||
|
'Middleware' => !empty($middlewares) ? implode(",", $middlewares) : '-'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$io->table($arrayOfRoutes, [
|
||||||
|
'head' => 'boldGreen'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to add the route based on the request
|
||||||
|
*
|
||||||
|
* @param Route $route Flight Route object
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function shouldAddRoute(Route $route)
|
||||||
|
{
|
||||||
|
$boolval = false;
|
||||||
|
|
||||||
|
$showAll = !$this->get && !$this->post && !$this->put && !$this->delete && !$this->patch;
|
||||||
|
if ($showAll === true) {
|
||||||
|
$boolval = true;
|
||||||
|
} else {
|
||||||
|
$methods = [ 'GET', 'POST', 'PUT', 'DELETE', 'PATCH' ];
|
||||||
|
foreach ($methods as $method) {
|
||||||
|
$lowercaseMethod = strtolower($method);
|
||||||
|
if (
|
||||||
|
$this->{$lowercaseMethod} === true &&
|
||||||
|
(
|
||||||
|
$route->methods[0] === '*' ||
|
||||||
|
in_array($method, $route->methods, true) === true
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$boolval = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $boolval;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace tests\commands;
|
||||||
|
|
||||||
|
use Ahc\Cli\Application;
|
||||||
|
use Ahc\Cli\IO\Interactor;
|
||||||
|
use flight\commands\ControllerCommand;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ControllerCommandTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected static $in = __DIR__ . '/input.test';
|
||||||
|
protected static $ou = __DIR__ . '/output.test';
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
file_put_contents(static::$in, '', LOCK_EX);
|
||||||
|
file_put_contents(static::$ou, '', LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown(): void
|
||||||
|
{
|
||||||
|
// Make sure we clean up after ourselves:
|
||||||
|
if (file_exists(static::$in)) {
|
||||||
|
unlink(static::$in);
|
||||||
|
}
|
||||||
|
if (file_exists(static::$ou)) {
|
||||||
|
unlink(static::$ou);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(__DIR__.'/controllers/TestController.php')) {
|
||||||
|
unlink(__DIR__.'/controllers/TestController.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(__DIR__.'/controllers/')) {
|
||||||
|
rmdir(__DIR__.'/controllers/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newApp(string $name, string $version = '')
|
||||||
|
{
|
||||||
|
$app = new Application($name, $version ?: '0.0.1', fn () => false);
|
||||||
|
|
||||||
|
return $app->io(new Interactor(static::$in, static::$ou));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfigAppRootNotSet()
|
||||||
|
{
|
||||||
|
$app = $this->newApp('test', '0.0.1');
|
||||||
|
$app->add(new ControllerCommand([]));
|
||||||
|
$app->handle(['runway', 'make:controller', 'Test']);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('app_root not set in .runway-config.json', file_get_contents(static::$ou));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerAlreadyExists()
|
||||||
|
{
|
||||||
|
$app = $this->newApp('test', '0.0.1');
|
||||||
|
mkdir(__DIR__.'/controllers/');
|
||||||
|
file_put_contents(__DIR__.'/controllers/TestController.php', '<?php class TestController {}');
|
||||||
|
$app->add(new ControllerCommand(['app_root' => 'tests/commands/']));
|
||||||
|
$app->handle(['runway', 'make:controller', 'Test']);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('TestController already exists.', file_get_contents(static::$ou));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateController()
|
||||||
|
{
|
||||||
|
$app = $this->newApp('test', '0.0.1');
|
||||||
|
$app->add(new ControllerCommand(['app_root' => 'tests/commands/']));
|
||||||
|
$app->handle(['runway', 'make:controller', 'Test']);
|
||||||
|
|
||||||
|
$this->assertFileExists(__DIR__.'/controllers/TestController.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace tests\commands;
|
||||||
|
|
||||||
|
use Ahc\Cli\Application;
|
||||||
|
use Ahc\Cli\IO\Interactor;
|
||||||
|
use Flight;
|
||||||
|
use flight\commands\RouteCommand;
|
||||||
|
use flight\Engine;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class RouteCommandTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected static $in = __DIR__ . '/input.test';
|
||||||
|
protected static $ou = __DIR__ . '/output.test';
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
file_put_contents(static::$in, '', LOCK_EX);
|
||||||
|
file_put_contents(static::$ou, '', LOCK_EX);
|
||||||
|
$_SERVER = [];
|
||||||
|
$_REQUEST = [];
|
||||||
|
Flight::init();
|
||||||
|
Flight::setEngine(new Engine());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown(): void
|
||||||
|
{
|
||||||
|
// Make sure we clean up after ourselves:
|
||||||
|
if (file_exists(static::$in)) {
|
||||||
|
unlink(static::$in);
|
||||||
|
}
|
||||||
|
if (file_exists(static::$ou)) {
|
||||||
|
unlink(static::$ou);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(__DIR__.'/index.php')) {
|
||||||
|
unlink(__DIR__.'/index.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($_REQUEST);
|
||||||
|
unset($_SERVER);
|
||||||
|
Flight::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newApp(string $name, string $version = '')
|
||||||
|
{
|
||||||
|
$app = new Application($name, $version ?: '0.0.1', fn () => false);
|
||||||
|
|
||||||
|
return $app->io(new Interactor(static::$in, static::$ou));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createIndexFile()
|
||||||
|
{
|
||||||
|
$index = <<<PHP
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require __DIR__ . '/../../vendor/autoload.php';
|
||||||
|
|
||||||
|
Flight::route('GET /', function () {});
|
||||||
|
Flight::post('/post', function () {})->addMiddleware(function() {});
|
||||||
|
Flight::delete('/delete', function () {});
|
||||||
|
Flight::put('/put', function () {});
|
||||||
|
Flight::patch('/patch', function () {})->addMiddleware('SomeMiddleware');
|
||||||
|
Flight::router()->case_sensitive = true;
|
||||||
|
|
||||||
|
Flight::start();
|
||||||
|
PHP;
|
||||||
|
|
||||||
|
file_put_contents(__DIR__.'/index.php', $index);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function removeColors(string $str): string
|
||||||
|
{
|
||||||
|
return preg_replace('/\e\[[\d;]*m/', '', $str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfigIndexRootNotSet()
|
||||||
|
{
|
||||||
|
$app = $this->newApp('test', '0.0.1');
|
||||||
|
$app->add(new RouteCommand([]));
|
||||||
|
$app->handle(['runway', 'routes']);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('index_root not set in .runway-config.json', file_get_contents(static::$ou));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetRoutes()
|
||||||
|
{
|
||||||
|
$app = $this->newApp('test', '0.0.1');
|
||||||
|
$this->createIndexFile();
|
||||||
|
$app->add(new RouteCommand(['index_root' => 'tests/commands/index.php']));
|
||||||
|
$app->handle(['runway', 'routes']);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('Routes', file_get_contents(static::$ou));
|
||||||
|
$this->assertStringContainsString('+---------+-----------+-------+----------+----------------+
|
||||||
|
| Pattern | Methods | Alias | Streamed | Middleware |
|
||||||
|
+---------+-----------+-------+----------+----------------+
|
||||||
|
| / | GET, HEAD | | No | - |
|
||||||
|
| /post | POST | | No | Closure |
|
||||||
|
| /delete | DELETE | | No | - |
|
||||||
|
| /put | PUT | | No | - |
|
||||||
|
| /patch | PATCH | | No | Bad Middleware |
|
||||||
|
+---------+-----------+-------+----------+----------------+', $this->removeColors(file_get_contents(static::$ou)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetPostRoute() {
|
||||||
|
$app = $this->newApp('test', '0.0.1');
|
||||||
|
$this->createIndexFile();
|
||||||
|
$app->add(new RouteCommand(['index_root' => 'tests/commands/index.php']));
|
||||||
|
$app->handle(['runway', 'routes', '--post']);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('Routes', file_get_contents(static::$ou));
|
||||||
|
$this->assertStringContainsString('+---------+---------+-------+----------+------------+
|
||||||
|
| Pattern | Methods | Alias | Streamed | Middleware |
|
||||||
|
+---------+---------+-------+----------+------------+
|
||||||
|
| /post | POST | | No | Closure |
|
||||||
|
+---------+---------+-------+----------+------------+', $this->removeColors(file_get_contents(static::$ou)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue