Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions flight/commands/ControllerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,24 @@ public function __construct(array $config)
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);

if (empty($this->config['runway'])) {
$io->warn('Using a .runway-config.json file is deprecated. Move your config values to app/config/config.php with `php runway config:migrate`.', true); // @codeCoverageIgnore
$runwayConfig = json_decode(file_get_contents($this->projectRoot . '/.runway-config.json'), true); // @codeCoverageIgnore
} else {
$runwayConfig = $this->config['runway'];
}

if (isset($runwayConfig['app_root']) === false) {
$io->error('app_root not set in app/config/config.php', true);
return;
}

if (!preg_match('/Controller$/', $controller)) {
$controller .= 'Controller';
}

$controllerPath = getcwd() . DIRECTORY_SEPARATOR . $this->config['app_root'] . 'controllers' . DIRECTORY_SEPARATOR . $controller . '.php';
$controllerPath = $this->projectRoot . '/' . $runwayConfig['app_root'] . 'controllers/' . $controller . '.php';
if (file_exists($controllerPath) === true) {
$io->error($controller . ' already exists.', true);
return;
Expand Down Expand Up @@ -70,7 +78,7 @@ public function execute(string $controller)
$namespace->add($class);
$file->addNamespace($namespace);

$this->persistClass($controller, $file);
$this->persistClass($controller, $file, $runwayConfig['app_root']);

$io->ok('Controller successfully created at ' . $controllerPath, true);
}
Expand All @@ -80,12 +88,13 @@ public function execute(string $controller)
*
* @param string $controllerName Name of the Controller
* @param PhpFile $file Class Object from Nette\PhpGenerator
* @param string $appRoot App Root from runway config
*
* @return void
*/
protected function persistClass(string $controllerName, PhpFile $file)
protected function persistClass(string $controllerName, PhpFile $file, string $appRoot)
{
$printer = new \Nette\PhpGenerator\PsrPrinter();
file_put_contents(getcwd() . DIRECTORY_SEPARATOR . $this->config['app_root'] . 'controllers' . DIRECTORY_SEPARATOR . $controllerName . '.php', $printer->printFile($file));
file_put_contents($this->projectRoot . '/' . $appRoot . 'controllers/' . $controllerName . '.php', $printer->printFile($file));
}
}
19 changes: 12 additions & 7 deletions flight/commands/RouteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ 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);
if (empty($this->config['runway'])) {
$io->warn('Using a .runway-config.json file is deprecated. Move your config values to app/config/config.php with `php runway config:migrate`.', true); // @codeCoverageIgnore
$runwayConfig = json_decode(file_get_contents($this->projectRoot . '/.runway-config.json'), true); // @codeCoverageIgnore
} else {
$runwayConfig = $this->config['runway'];
}

if (isset($runwayConfig['index_root']) === false) {
$io->error('index_root not set in app/config/config.php', true);
return;
}

$io->bold('Routes', true);

$cwd = getcwd();

$index_root = $cwd . '/' . $this->config['index_root'];
$index_root = $this->projectRoot . '/' . $runwayConfig['index_root'];

// This makes it so the framework doesn't actually execute
Flight::map('start', function () {
Expand All @@ -72,8 +77,8 @@ public function execute()
}
return preg_match("/^class@anonymous/", end($middleware_class_name)) ? 'Anonymous' : end($middleware_class_name);
}, $route->middleware);
} catch (\TypeError $e) {
$middlewares[] = 'Bad Middleware';
} catch (\TypeError $e) { // @codeCoverageIgnore
$middlewares[] = 'Bad Middleware'; // @codeCoverageIgnore
} finally {
if (is_string($route->middleware) === true) {
$middlewares[] = $route->middleware;
Expand Down
8 changes: 4 additions & 4 deletions flight/net/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function __construct(array $config = [])
}
$base = dirname($base);
if ($base === '\\') {
$base = '/';
$base = '/'; // @codeCoverageIgnore
}
$config = [
'url' => $url,
Expand Down Expand Up @@ -243,8 +243,8 @@ public function init(array $properties = []): self
$this->data->setData($data);
}
}
// Check PUT, PATCH, DELETE for application/x-www-form-urlencoded data or multipart/form-data
} elseif (in_array($this->method, [ 'PUT', 'DELETE', 'PATCH' ], true) === true) {
// Check PUT, PATCH, DELETE for application/x-www-form-urlencoded data or multipart/form-data
} elseif (in_array($this->method, ['PUT', 'DELETE', 'PATCH'], true) === true) {
$this->parseRequestBodyForHttpMethods();
}

Expand Down Expand Up @@ -478,7 +478,7 @@ public function negotiateContentType(array $supported): ?string
/**
* Retrieves the array of uploaded files.
*
* @return array<string, UploadedFile|array<int, UploadedFile>> Key is field name; value is either a single UploadedFile or an array of UploadedFile when multiple were uploaded.
* @return array<string, UploadedFile|array<int, UploadedFile>> Key is field name; value is either a single UploadedFile or an array of UploadedFile when multiple were uploaded.
*/
public function getUploadedFiles(): array
{
Expand Down
4 changes: 2 additions & 2 deletions tests/UploadedFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public function tearDown(): void
unlink('real_file');
}

// not found with file_exists...just delete it brute force
@unlink('tmp_symlink');
// not found with file_exists...just delete it brute force
@unlink('tmp_symlink');
}

public function testMoveToFalseSuccess(): void
Expand Down
36 changes: 24 additions & 12 deletions tests/commands/AiGenerateInstructionsCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
use PHPUnit\Framework\TestCase;
use tests\classes\NoExitInteractor;

class AiGenerateInstructionsCommandTest extends TestCase {
class AiGenerateInstructionsCommandTest extends TestCase
{
protected static $in;
protected static $ou;
protected $baseDir;

public function setUp(): void {
public function setUp(): void
{
self::$in = __DIR__ . DIRECTORY_SEPARATOR . 'input.test' . uniqid('', true) . '.txt';
self::$ou = __DIR__ . DIRECTORY_SEPARATOR . 'output.test' . uniqid('', true) . '.txt';
file_put_contents(self::$in, '');
Expand All @@ -25,7 +27,8 @@ public function setUp(): void {
}
}

public function tearDown(): void {
public function tearDown(): void
{
if (file_exists(self::$in)) {
unlink(self::$in);
}
Expand All @@ -35,7 +38,8 @@ public function tearDown(): void {
$this->recursiveRmdir($this->baseDir);
}

protected function recursiveRmdir($dir) {
protected function recursiveRmdir($dir)
{
if (!is_dir($dir)) {
return;
}
Expand All @@ -46,7 +50,8 @@ protected function recursiveRmdir($dir) {
return rmdir($dir);
}

protected function newApp($command): Application {
protected function newApp($command): Application
{
$app = new Application('test', '0.0.1', function ($exitCode) {
return $exitCode;
});
Expand All @@ -55,11 +60,13 @@ protected function newApp($command): Application {
return $app;
}

protected function setInput(array $lines): void {
protected function setInput(array $lines): void
{
file_put_contents(self::$in, implode("\n", $lines) . "\n");
}

protected function setProjectRoot($command, $path) {
protected function setProjectRoot($command, $path)
{
$reflection = new \ReflectionClass(get_class($command));
$property = null;
$currentClass = $reflection;
Expand All @@ -79,7 +86,8 @@ protected function setProjectRoot($command, $path) {
}
}

public function testFailsIfAiConfigMissing() {
public function testFailsIfAiConfigMissing()
{
$this->setInput([
'desc',
'none',
Expand Down Expand Up @@ -107,7 +115,8 @@ public function testFailsIfAiConfigMissing() {
$this->assertStringContainsString('Missing AI configuration', file_get_contents(self::$ou));
}

public function testWritesInstructionsToFiles() {
public function testWritesInstructionsToFiles()
{
$creds = [
'api_key' => 'key',
'model' => 'gpt-4o',
Expand Down Expand Up @@ -154,7 +163,8 @@ public function testWritesInstructionsToFiles() {
$this->assertFileExists($this->baseDir . '.windsurfrules');
}

public function testNoInstructionsReturnedFromLlm() {
public function testNoInstructionsReturnedFromLlm()
{
$creds = [
'api_key' => 'key',
'model' => 'gpt-4o',
Expand Down Expand Up @@ -196,7 +206,8 @@ public function testNoInstructionsReturnedFromLlm() {
$this->assertSame(1, $result);
}

public function testLlmApiCallFails() {
public function testLlmApiCallFails()
{
$creds = [
'api_key' => 'key',
'model' => 'gpt-4o',
Expand Down Expand Up @@ -234,7 +245,8 @@ public function testLlmApiCallFails() {
$this->assertSame(1, $result);
}

public function testUsesDeprecatedConfigFile() {
public function testUsesDeprecatedConfigFile()
{
$creds = [
'ai' => [
'api_key' => 'key',
Expand Down
10 changes: 5 additions & 5 deletions tests/commands/ControllerCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,26 @@ public function tearDown(): void

protected function newApp(string $name, string $version = '')
{
$app = @new Application($name, $version ?: '0.0.1', fn () => false);
$app = @new Application($name, $version ?: '0.0.1', fn() => false);

return @$app->io(new Interactor(static::$in, static::$ou));
}

public function testConfigAppRootNotSet(): void
{
$app = $this->newApp('test', '0.0.1');
$app->add(new ControllerCommand([]));
$app->add(new ControllerCommand(['runway' => ['something' => '']]));
@$app->handle(['runway', 'make:controller', 'Test']);

$this->assertStringContainsString('app_root not set in .runway-config.json', file_get_contents(static::$ou));
$this->assertStringContainsString('app_root not set in app/config/config.php', file_get_contents(static::$ou));
}

public function testControllerAlreadyExists(): void
{
$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->add(new ControllerCommand(['runway' => ['app_root' => 'tests/commands/']]));
$app->handle(['runway', 'make:controller', 'Test']);

$this->assertStringContainsString('TestController already exists.', file_get_contents(static::$ou));
Expand All @@ -76,7 +76,7 @@ public function testControllerAlreadyExists(): void
public function testCreateController(): void
{
$app = $this->newApp('test', '0.0.1');
$app->add(new ControllerCommand(['app_root' => 'tests/commands/']));
$app->add(new ControllerCommand(['runway' => ['app_root' => 'tests/commands/']]));
$app->handle(['runway', 'make:controller', 'Test']);

$this->assertFileExists(__DIR__ . '/controllers/TestController.php');
Expand Down
13 changes: 9 additions & 4 deletions tests/commands/RouteCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function setUp(): void
static::$ou = __DIR__ . DIRECTORY_SEPARATOR . 'output.test' . uniqid('', true) . '.txt';
file_put_contents(static::$in, '');
file_put_contents(static::$ou, '');

$_SERVER = [];
$_REQUEST = [];
Flight::init();
Expand Down Expand Up @@ -91,21 +92,22 @@ protected function removeColors(string $str): string
public function testConfigIndexRootNotSet(): void
{
$app = @$this->newApp('test', '0.0.1');
$app->add(new RouteCommand([]));
$app->add(new RouteCommand(['runway' => ['something' => 'else']]));
@$app->handle(['runway', 'routes']);

$this->assertStringContainsString('index_root not set in .runway-config.json', file_get_contents(static::$ou));
$this->assertStringContainsString('index_root not set in app/config/config.php', file_get_contents(static::$ou));
}

public function testGetRoutes(): void
{
$app = @$this->newApp('test', '0.0.1');
$this->createIndexFile();
$app->add(new RouteCommand(['index_root' => 'tests/commands/index.php']));
$app->add(new RouteCommand(['runway' => ['index_root' => 'tests/commands/index.php']]));
@$app->handle(['runway', 'routes']);

$this->assertStringContainsString('Routes', file_get_contents(static::$ou));
$expected = <<<'output'
Routes
+---------+--------------------+-------+----------+----------------+
| Pattern | Methods | Alias | Streamed | Middleware |
+---------+--------------------+-------+----------+----------------+
Expand All @@ -127,19 +129,22 @@ public function testGetPostRoute(): void
{
$app = @$this->newApp('test', '0.0.1');
$this->createIndexFile();
$app->add(new RouteCommand(['index_root' => 'tests/commands/index.php']));
$app->add(new RouteCommand(['runway' => ['index_root' => 'tests/commands/index.php']]));
@$app->handle(['runway', 'routes', '--post']);

$this->assertStringContainsString('Routes', file_get_contents(static::$ou));

$expected = <<<'output'
Routes
+---------+---------------+-------+----------+------------+
| Pattern | Methods | Alias | Streamed | Middleware |
+---------+---------------+-------+----------+------------+
| /post | POST, OPTIONS | | No | Closure |
+---------+---------------+-------+----------+------------+
output; // phpcs:ignore

$expected = str_replace(["\r\n", "\\n", "\n"], ["\n", "", "\n"], $expected);

$this->assertStringContainsString(
$expected,
$this->removeColors(file_get_contents(static::$ou))
Expand Down