mirror of https://github.com/flightphp/core
parent
ad58c09b57
commit
234b3ddb0a
@ -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