Skip to content
Open
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
13 changes: 8 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@
"psr-4": {
"Tests\\PHP8\\": [
"tests/named-arguments"
]
],
"Tests\\Server\\": "tests/server",
"Tests\\ServerV2\\": "tests/server-v2",
"tests\\groupcompactsyntax\\": "tests/groupcompactsyntax"
}
},
"require-dev": {
"ext-pdo_sqlite": "*",
"flightphp/container": "^1.0",
"flightphp/container": "^1.3",
"flightphp/runway": "^1.2",
"league/container": "^4.2",
"level-2/dice": "^4.0",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^9.6",
"rregeer/phpunit-coverage-check": "^0.3.1",
"squizlabs/php_codesniffer": "^3.11"
"squizlabs/php_codesniffer": "^4.0"
},
"config": {
"allow-plugins": {
Expand Down Expand Up @@ -84,7 +87,7 @@
],
"lint": "phpstan --no-progress --memory-limit=256M -cphpstan.neon",
"beautify": "phpcbf --standard=phpcs.xml",
"phpcs": "phpcs --standard=phpcs.xml -n",
"phpcs": "phpcs",
"post-install-cmd": [
"php -r \"if (!file_exists('phpcs.xml')) copy('phpcs.xml.dist', 'phpcs.xml');\""
]
Expand All @@ -97,4 +100,4 @@
"replace": {
"mikecao/flight": "2.0.2"
}
}
}
19 changes: 16 additions & 3 deletions flight/Engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,8 @@ public function handleException(Throwable $e): void
/**
* Registers the container handler
*
* @param ContainerInterface|callable(class-string<T> $id, array<int|string, mixed> $params): ?T $containerHandler Callback function or PSR-11 Container object that sets the container and how it will inject classes
* @param ContainerInterface|callable(class-string<T> $id, array<int|string, mixed> $params): ?T $containerHandler
* Callback function or PSR-11 Container object that sets the container and how it will inject classes
*
* @template T of object
*/
Expand Down Expand Up @@ -488,7 +489,14 @@ protected function processMiddleware(Route $route, string $eventName): bool
// Which loosely translates to $class->$method($params)
$start = microtime(true);
$middlewareResult = $middlewareObject($params);
$this->triggerEvent('flight.middleware.executed', $route, $middleware, $eventName, microtime(true) - $start);

$this->triggerEvent(
'flight.middleware.executed',
$route,
$middleware,
$eventName,
microtime(true) - $start
);

if ($useV3OutputBuffering === true) {
$this->response()->write(ob_get_clean());
Expand Down Expand Up @@ -860,7 +868,12 @@ public function _notFound(): void
public function _methodNotFound(Route $route): void
{
$this->response()->setHeader('Allow', implode(', ', $route->methods));
$this->halt(405, 'Method Not Allowed. Allowed Methods are: ' . implode(', ', $route->methods), empty(getenv('PHPUNIT_TEST')));

$this->halt(
405,
'Method Not Allowed. Allowed Methods are: ' . implode(', ', $route->methods),
empty(getenv('PHPUNIT_TEST'))
);
}

/**
Expand Down
4 changes: 3 additions & 1 deletion flight/Flight.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@
* @phpstan-method static void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* @phpstan-method static void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
*
* Note: IDEs will use standard @method tags for autocompletion, while PHPStan will use @phpstan-* tags for advanced type checking.
* Note: IDEs will use standard @method tags for autocompletion,
* while PHPStan will use @phpstan-* tags for advanced type checking.
*/
// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace
class Flight
{
/**
Expand Down
55 changes: 47 additions & 8 deletions flight/commands/AiGenerateInstructionsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ class AiGenerateInstructionsCommand extends AbstractBaseCommand
public function __construct(array $config)
{
parent::__construct('ai:generate-instructions', 'Generate project-specific AI coding instructions', $config);
$this->option('--config-file', 'Path to .runway-config.json file (deprecated, use config.php instead)', null, '');

$this->option(
'--config-file',
'Path to .runway-config.json file (deprecated, use config.php instead)',
null,
''
);
}

/**
Expand All @@ -40,7 +46,12 @@ public function execute(): int
if (empty($this->config['runway'])) {
$configFile = $this->configFile;
$io = $this->app()->io();
$io->warn('The --config-file option is deprecated. Move your config values to the \'runway\' key in the config.php file for configuration.', true);

$io->warn(
'The --config-file option is deprecated. '
. 'Move your config values to the \'runway\' key in the config.php file for configuration.',
true
);
$runwayConfig = json_decode(file_get_contents($configFile), true) ?? [];
} else {
$runwayConfig = $this->config['runway'];
Expand All @@ -56,12 +67,30 @@ public function execute(): int

// Ask questions
$projectDesc = $io->prompt('Please describe what your project is for?');
$database = $io->prompt('What database are you planning on using? (e.g. MySQL, SQLite, PostgreSQL, none)', 'none');
$templating = $io->prompt('What HTML templating engine will you plan on using (if any)? (recommend latte)', 'latte');

$database = $io->prompt(
'What database are you planning on using? (e.g. MySQL, SQLite, PostgreSQL, none)',
'none'
);

$templating = $io->prompt(
'What HTML templating engine will you plan on using (if any)? (recommend latte)',
'latte'
);

$security = $io->confirm('Is security an important element of this project?', 'y');
$performance = $io->confirm('Is performance and speed an important part of this project?', 'y');
$composerLibs = $io->prompt('What major composer libraries will you be using if you know them right now?', 'none');
$envSetup = $io->prompt('How will you set up your development environment? (e.g. Docker, Vagrant, PHP dev server, other)', 'Docker');

$composerLibs = $io->prompt(
'What major composer libraries will you be using if you know them right now?',
'none'
);

$envSetup = $io->prompt(
'How will you set up your development environment? (e.g. Docker, Vagrant, PHP dev server, other)',
'Docker'
);

$teamSize = $io->prompt('How many developers will be working on this project?', '1');
$api = $io->confirm('Will this project expose an API?', 'n');
$other = $io->prompt('Any other important requirements or context? (optional)', 'no');
Expand Down Expand Up @@ -107,7 +136,13 @@ public function execute(): int
$data = [
'model' => $model,
'messages' => [
['role' => 'system', 'content' => 'You are a helpful AI coding assistant focused on the Flight Framework for PHP. You are up to date with all your knowledge from https://docs.flightphp.com. As an expert into the programming language PHP, you are top notch at architecting out proper instructions for FlightPHP projects.'],
[
'role' => 'system',
'content' => 'You are a helpful AI coding assistant focused on the Flight Framework for PHP. '
. 'You are up to date with all your knowledge from https://docs.flightphp.com. '
. 'As an expert into the programming language PHP, '
. 'you are top notch at architecting out proper instructions for FlightPHP projects.'
],
['role' => 'user', 'content' => $prompt],
],
'temperature' => 0.2,
Expand All @@ -129,7 +164,11 @@ public function execute(): int
}

// Write to files
$io->info('Updating .github/copilot-instructions.md, .cursor/rules/project-overview.mdc, .gemini/GEMINI.md and .windsurfrules...', true);
$io->info(
'Updating .github/copilot-instructions.md, .cursor/rules/project-overview.mdc, .gemini/GEMINI.md and .windsurfrules...',
true
);

if (!is_dir($this->projectRoot . '.github')) {
mkdir($this->projectRoot . '.github', 0755, true);
}
Expand Down
6 changes: 5 additions & 1 deletion flight/commands/AiInitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ public function execute(): int
$defaultModel = 'claude-sonnet-4-5';
break;
}
$model = trim($io->prompt('Enter the model name you want to use (e.g. gpt-5, claude-sonnet-4-5, etc)', $defaultModel));

$model = trim($io->prompt(
'Enter the model name you want to use (e.g. gpt-5, claude-sonnet-4-5, etc)',
$defaultModel
));

$runwayAiConfig = [
'provider' => $api,
Expand Down
17 changes: 14 additions & 3 deletions flight/commands/ControllerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,16 @@ public function execute(string $controller): void
$io = $this->app()->io();

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
$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'];
}
Expand Down Expand Up @@ -95,6 +103,9 @@ public function execute(string $controller): void
protected function persistClass(string $controllerName, PhpFile $file, string $appRoot)
{
$printer = new \Nette\PhpGenerator\PsrPrinter();
file_put_contents($this->projectRoot . '/' . $appRoot . 'controllers/' . $controllerName . '.php', $printer->printFile($file));
file_put_contents(
$this->projectRoot . '/' . $appRoot . 'controllers/' . $controllerName . '.php',
$printer->printFile($file)
);
}
}
8 changes: 1 addition & 7 deletions flight/commands/RouteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,7 @@ public function shouldAddRoute(Route $route)
$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
)
) {
if ($this->{$lowercaseMethod} === true && ($route->methods[0] === '*' || in_array($method, $route->methods, true) === true)) {
$boolval = true;
break;
}
Expand Down
18 changes: 8 additions & 10 deletions flight/core/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,14 @@ class Dispatcher
*
* @template T of object
*
* @throws InvalidArgumentException If $containerHandler is not a `callable` or instance of `Psr\Container\ContainerInterface`.
* @throws InvalidArgumentException
* If $containerHandler is not a `callable` or instance of `Psr\Container\ContainerInterface`.
*/
public function setContainerHandler($containerHandler): void
{
$containerInterfaceNS = '\Psr\Container\ContainerInterface';

if (
is_a($containerHandler, $containerInterfaceNS)
|| is_callable($containerHandler)
) {
if (is_a($containerHandler, $containerInterfaceNS) || is_callable($containerHandler)) {
$this->containerHandler = $containerHandler;

return;
Expand Down Expand Up @@ -289,10 +287,7 @@ public function filter(array $filters, array &$params, &$output): void
*/
public function execute($callback, array &$params = [])
{
if (
is_string($callback) === true
&& (strpos($callback, '->') !== false || strpos($callback, '::') !== false)
) {
if (is_string($callback) === true && (strpos($callback, '->') !== false || strpos($callback, '::') !== false)) {
$callback = $this->parseStringClassAndMethod($callback);
}

Expand Down Expand Up @@ -419,7 +414,10 @@ protected function verifyValidClassCallable($class, $method, $resolvedClass): vo

// Final check to make sure it's actually a class and a method, or throw an error
if (is_object($class) === false && class_exists($class) === false) {
$exception = new Exception("Class '$class' not found. Is it being correctly autoloaded with Flight::path()?");
$exception = new Exception(
"Class '$class' not found. "
. "Is it being correctly autoloaded with Flight::path()?"
);

// If this tried to resolve a class in a container and failed somehow, throw the exception
} elseif (!$resolvedClass && $this->containerException !== null) {
Expand Down
19 changes: 9 additions & 10 deletions flight/net/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -439,15 +439,13 @@ public static function parseQuery(string $url): array
*/
public static function getScheme(): string
{
if (
(strtolower(self::getVar('HTTPS')) === 'on')
||
(self::getVar('HTTP_X_FORWARDED_PROTO') === 'https')
||
(self::getVar('HTTP_FRONT_END_HTTPS') === 'on')
||
(self::getVar('REQUEST_SCHEME') === 'https')
) {
if (strtolower(self::getVar('HTTPS')) === 'on') {
return 'https';
} elseif (self::getVar('HTTP_X_FORWARDED_PROTO') === 'https') {
return 'https';
} elseif (self::getVar('HTTP_FRONT_END_HTTPS') === 'on') {
return 'https';
} elseif (self::getVar('REQUEST_SCHEME') === 'https') {
return 'https';
}

Expand Down Expand Up @@ -478,7 +476,8 @@ 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
3 changes: 2 additions & 1 deletion flight/net/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,8 @@ protected function processResponseCallbacks(): void
* Downloads a file.
*
* @param string $filePath The path to the file to be downloaded.
* @param string $fileName The name the downloaded file should have. If not provided or is an empty string, the name of the file on disk will be used.
* @param string $fileName The name the downloaded file should have.
* If not provided or is an empty string, the name of the file on disk will be used.
*
* @throws Exception If the file cannot be found.
*
Expand Down
12 changes: 9 additions & 3 deletions flight/net/UploadedFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,14 @@ class UploadedFile
* @param int $error The error code associated with the uploaded file.
* @param bool|null $isPostUploadedFile Indicates if the file was uploaded via POST method.
*/
public function __construct(string $name, string $mimeType, int $size, string $tmpName, int $error, ?bool $isPostUploadedFile = null)
{
public function __construct(
string $name,
string $mimeType,
int $size,
string $tmpName,
int $error,
?bool $isPostUploadedFile = null
) {
$this->name = $name;
$this->mimeType = $mimeType;
$this->size = $size;
Expand Down Expand Up @@ -154,7 +160,7 @@ public function moveTo(string $targetPath): void
$uploadFunctionToCall = $isUploadedFile === true ?
// Standard POST upload - use move_uploaded_file for security
'move_uploaded_file' :
// Handle non-POST uploads (PATCH, PUT, DELETE) or other valid temp files
// Handle non-POST uploads (PATCH, PUT, DELETE) or other valid temp files
'rename';

$result = $uploadFunctionToCall($this->tmpName, $targetPath);
Expand Down
1 change: 1 addition & 0 deletions flight/util/ReturnTypeWillChange.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

// This file is only here so that the PHP8 attribute for doesn't throw an error in files
// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace
class ReturnTypeWillChange
{
//
Expand Down
Loading
Loading