diff --git a/.editorconfig b/.editorconfig index 19ae126..e8d15f4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,9 +5,8 @@ indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true [*.md] indent_size = 2 - -[tests/views/*.php] -insert_final_newline = false diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index 59a33e4..03cc3ba 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -16,12 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl - Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher) - Run test server: `composer test-server` or `composer test-server-v2` - Lint code: `composer lint` (uses phpstan/phpstan, level 6) -- Beautify code: `composer beautify` (uses squizlabs/php_codesniffer, PSR1) -- Check code style: `composer phpcs` +- Format code: `composer format` (uses squizlabs/php_codesniffer, PSR12) - Test coverage: `composer test-coverage` ## Coding Standards -- Follow PSR1 coding standards (enforced by PHPCS) +- Follow PSR12 coding standards (enforced by PHPCS) - Use strict comparisons (`===`, `!==`) - PHPStan level 6 compliance - Focus on PHP 7.4 compatibility (avoid PHP 8+ only features) diff --git a/.gitattributes b/.gitattributes index c01e089..72af06c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,9 +5,9 @@ /.gitattributes export-ignore /.gitignore export-ignore /CONTRIBUTING.md export-ignore -/index.php export-ignore /phpcs.xml.dist export-ignore /phpstan-baseline.neon export-ignore /phpstan.dist.neon export-ignore -/phpunit-watcher.yml export-ignore +/phpunit-watcher.yml.dist export-ignore /phpunit.xml.dist export-ignore +/README.md export-ignore diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 59a33e4..03cc3ba 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -16,12 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl - Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher) - Run test server: `composer test-server` or `composer test-server-v2` - Lint code: `composer lint` (uses phpstan/phpstan, level 6) -- Beautify code: `composer beautify` (uses squizlabs/php_codesniffer, PSR1) -- Check code style: `composer phpcs` +- Format code: `composer format` (uses squizlabs/php_codesniffer, PSR12) - Test coverage: `composer test-coverage` ## Coding Standards -- Follow PSR1 coding standards (enforced by PHPCS) +- Follow PSR12 coding standards (enforced by PHPCS) - Use strict comparisons (`===`, `!==`) - PHPStan level 6 compliance - Focus on PHP 7.4 compatibility (avoid PHP 8+ only features) diff --git a/.gitignore b/.gitignore index cb308cf..ac7efc8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,9 @@ -.idea/ -.vscode/ -vendor/ -composer.phar -composer.lock -.phpunit.result.cache -coverage/ *.sublime* -clover.xml +.phpunit.result.cache +/coverage/ +/vendor/ +composer.lock phpcs.xml phpstan.neon +phpunit-watcher.yml phpunit.xml -.runway-config.json -.runway-creds.json -.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b1af6d..d6a5acc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Coding Standards** - We use PSR1 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: * PHPStan is at level 6. - * `===` instead of truthy or falsey statements like `==` or `!is_array()`. + * `===` instead of truthy or falsey statements like `==`. * **PHP 7.4 Focused** - We do not make PHP 8+ focused enhancements on the framework as the focus is maintaining PHP 7.4. diff --git a/composer.json b/composer.json index 33d2951..0d4817c 100644 --- a/composer.json +++ b/composer.json @@ -1,19 +1,19 @@ { "name": "flightphp/core", "description": "Flight is a fast, simple, extensible framework for PHP. Flight enables you to quickly and easily build RESTful web applications. This is the maintained fork of mikecao/flight", - "homepage": "http://flightphp.com", + "homepage": "https://docs.flightphp.com/", "license": "MIT", "authors": [ { "name": "Mike Cao", "email": "mike@mikecao.com", - "homepage": "http://www.mikecao.com/", + "homepage": "https://mikecao.com/", "role": "Original Developer" }, { "name": "Franyer Sánchez", "email": "franyeradriansanchez@gmail.com", - "homepage": "https://faslatam.42web.io", + "homepage": "https://faslatam.42web.io/", "role": "Maintainer" }, { @@ -27,21 +27,16 @@ "ext-json": "*" }, "autoload": { - "files": [ - "flight/autoload.php" - ] - }, - "autoload-dev": { "classmap": [ - "tests/classes/" + "src/Flight.php" ], "psr-4": { - "Tests\\PHP8\\": [ - "tests/named-arguments" - ], - "Tests\\Server\\": "tests/server", - "Tests\\ServerV2\\": "tests/server-v2", - "tests\\groupcompactsyntax\\": "tests/groupcompactsyntax" + "flight\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "tests\\": "tests" } }, "require-dev": { @@ -54,7 +49,9 @@ "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^9.6", "rregeer/phpunit-coverage-check": "^0.3.1", - "squizlabs/php_codesniffer": "^4.0" + "spatie/phpunit-watcher": "^1.23", + "squizlabs/php_codesniffer": "^4.0", + "symfony/var-dumper": "^5.4" }, "config": { "allow-plugins": { @@ -65,15 +62,12 @@ }, "scripts": { "test": "phpunit", - "test-watcher": [ - "phpunit-watcher || composer global require spatie/phpunit-watcher --dev", - "phpunit-watcher watch" - ], + "test-watcher": "phpunit-watcher watch", "test-coverage": [ - "rm -f clover.xml", + "rm -rf coverage", "@putenv XDEBUG_MODE=coverage", - "phpunit --coverage-html=coverage --coverage-clover=clover.xml", - "coverage-check clover.xml 100" + "phpunit --coverage-html coverage --coverage-clover coverage/clover.xml", + "coverage-check coverage/clover.xml 100" ], "test-server": [ "echo \"Running Test Server\"", @@ -81,12 +75,7 @@ ], "test-server-v2": [ "echo \"Running Test Server\"", - "@php -S localhost:8000 -t tests/server-v2" - ], - "test-coverage:win": [ - "del clover.xml", - "phpunit --coverage-html=coverage --coverage-clover=clover.xml", - "coverage-check clover.xml 100" + "@php -S localhost:8000 -t tests/server_v2" ], "test-performance": [ "echo \"Running Performance Tests...\"", @@ -97,13 +86,18 @@ "rm server.pid", "echo \"Performance Tests Completed.\"" ], - "lint": "phpstan --no-progress --memory-limit=256M", - "beautify": "phpcbf", - "phpcs": "phpcs", + "lint": [ + "phpstan --no-progress --memory-limit=256M", + "phpcs" + ], + "format": [ + "phpcbf" + ], "post-install-cmd": [ "@php -r \"if (!file_exists('phpcs.xml')) copy('phpcs.xml.dist', 'phpcs.xml');\"", "@php -r \"if (!file_exists('phpstan.neon')) copy('phpstan.dist.neon', 'phpstan.neon');\"", - "@php -r \"if (!file_exists('phpunit.xml')) copy('phpunit.xml.dist', 'phpunit.xml');\"" + "@php -r \"if (!file_exists('phpunit.xml')) copy('phpunit.xml.dist', 'phpunit.xml');\"", + "@php -r \"if (!file_exists('phpunit-watcher.yml')) copy('phpunit-watcher.yml.dist', 'phpunit-watcher.yml');\"" ] }, "suggest": { diff --git a/flight/Flight.php b/flight/Flight.php deleted file mode 100644 index c2e9a01..0000000 --- a/flight/Flight.php +++ /dev/null @@ -1,145 +0,0 @@ -, n0nag0n - * - * @method static void start() - * @method static void path(string $dir) - * @method static void stop(int $code = null) - * @method static void halt(int $code = 200, string $message = '', bool $actuallyExit = true) - * @method static void register(string $name, string $class, array $params = [], callable $callback = null) - * @method static void unregister(string $methodName) - * @method static void registerContainerHandler($containerHandler) - * @method static EventDispatcher eventDispatcher() - * @method static Route route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') - * @method static void group(string $pattern, callable $callback, array $group_middlewares = []) - * @method static Route post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') - * @method static Route put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') - * @method static Route patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') - * @method static Route delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') - * @method static void resource(string $pattern, string $controllerClass, array $methods = []) - * @method static Router router() - * @method static string getUrl(string $alias, array $params = []) - * @method static void map(string $name, callable $callback) - * @method static void before(string $name, Closure $callback) - * @method static void after(string $name, Closure $callback) - * @method static void set($key, $value) - * @method static mixed get($key = null) - * @method static bool has(string $key) - * @method static void clear($key = null) - * @method static void render(string $file, array $data = null, string $key = null) - * @method static View view() - * @method void onEvent(string $event, callable $callback) - * @method void triggerEvent(string $event, ...$args) - * @method static Request request() - * @method static Response response() - * @method static void redirect(string $url, int $code = 303) - * @method static void json($data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) - * @method static void jsonHalt($data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0) - * @method static void jsonp($data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) - * @method static void error(Throwable $exception) - * @method static void notFound() - * @method static void methodNotFound(Route $route) - * @method static void etag(string $id, string $type = 'strong') - * @method static void lastModified(int $time) - * @method static void download(string $filePath) - * - * @phpstan-template FlightTemplate of object - * @phpstan-method static void register(string $name, class-string $class, array $params = [], (callable(class-string $class, array $params): void)|null $callback = null) - * @phpstan-method static void registerContainerHandler(ContainerInterface|callable(class-string $id, array $params): ?FlightTemplate $containerHandler) - * @phpstan-method static Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method static void group(string $pattern, callable $callback, (class-string|callable|array{0: class-string, 1: string})[] $group_middlewares = []) - * @phpstan-method static Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method static Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method static Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method static Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method static void resource(string $pattern, class-string $controllerClass, array> $methods = []) - * @phpstan-method static string getUrl(string $alias, array $params = []) - * @phpstan-method static void before(string $name, Closure(array &$params, string &$output): (void|false) $callback) - * @phpstan-method static void after(string $name, Closure(array &$params, string &$output): (void|false) $callback) - * @phpstan-method static void set(string|iterable $key, mixed $value) - * @phpstan-method static mixed get(?string $key) - * @phpstan-method static void render(string $file, ?array $data = null, ?string $key = null) - * @phpstan-method static void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) - * @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. - */ -// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace -class Flight -{ - /** - * @var Engine - */ - private static Engine $engine; - - /** - * Don't allow object instantiation - * - * @codeCoverageIgnore - * @return void - */ - private function __construct() - { - // - } - - /** - * Forbid cloning the class - * - * @codeCoverageIgnore - * @return void - */ - private function __clone() - { - // - } - - /** - * Handles calls to static methods. - * - * @param string $name Method name - * @param array $params Method parameters - * - * @return mixed Callback results - * @throws Exception - */ - public static function __callStatic(string $name, array $params) - { - return self::app()->{$name}(...$params); - } - - /** @return Engine Application instance */ - public static function app(): Engine - { - return self::$engine ?? self::$engine = new Engine(); - } - - /** - * Set the engine instance - * - * @param Engine $engine Vroom vroom! - */ - public static function setEngine(Engine $engine): void - { - self::$engine = $engine; - } -} diff --git a/flight/autoload.php b/flight/autoload.php deleted file mode 100644 index 0a31c86..0000000 --- a/flight/autoload.php +++ /dev/null @@ -1,10 +0,0 @@ - - */ -class Loader -{ - /** - * Registered classes. - * - * @var array, ?callable}> $classes - */ - protected array $classes = []; - - /** - * If this is disabled, classes can load with underscores - */ - protected static bool $v2ClassLoading = true; - - /** - * Class instances. - * - * @var array - */ - protected array $instances = []; - - /** - * Autoload directories. - * - * @var array - */ - protected static array $dirs = []; - - /** - * Registers a class. - * - * @param string $name Registry name - * @param class-string|Closure(): T $class Class name or function to instantiate class - * @param array $params Class initialization parameters - * @param ?Closure(T $instance): void $callback $callback Function to call after object instantiation - * - * @template T of object - */ - public function register(string $name, $class, array $params = [], ?callable $callback = null): void - { - unset($this->instances[$name]); - - $this->classes[$name] = [$class, $params, $callback]; - } - - /** - * Unregisters a class. - * - * @param string $name Registry name - */ - public function unregister(string $name): void - { - unset($this->classes[$name]); - } - - /** - * Loads a registered class. - * - * @param string $name Method name - * @param bool $shared Shared instance - * - * @throws Exception - * - * @return ?object Class instance - */ - public function load(string $name, bool $shared = true): ?object - { - $obj = null; - - if (isset($this->classes[$name])) { - [0 => $class, 1 => $params, 2 => $callback] = $this->classes[$name]; - - $exists = isset($this->instances[$name]); - - if ($shared) { - $obj = ($exists) ? - $this->getInstance($name) : - $this->newInstance($class, $params); - - if (!$exists) { - $this->instances[$name] = $obj; - } - } else { - $obj = $this->newInstance($class, $params); - } - - if ($callback && (!$shared || !$exists)) { - $ref = [&$obj]; - \call_user_func_array($callback, $ref); - } - } - - return $obj; - } - - /** - * Gets a single instance of a class. - * - * @param string $name Instance name - * - * @return ?object Class instance - */ - public function getInstance(string $name): ?object - { - return $this->instances[$name] ?? null; - } - - /** - * Gets a new instance of a class. - * - * @param class-string|Closure(): class-string $class Class name or callback function to instantiate class - * @param array $params Class initialization parameters - * - * @template T of object - * - * @throws Exception - * - * @return T Class instance - */ - public function newInstance($class, array $params = []) - { - if (\is_callable($class)) { - return \call_user_func_array($class, $params); - } - - return new $class(...$params); - } - - /** - * Gets a registered callable - * - * @param string $name Registry name - * - * @return mixed Class information or null if not registered - */ - public function get(string $name) - { - return $this->classes[$name] ?? null; - } - - /** - * Resets the object to the initial state. - */ - public function reset(): void - { - $this->classes = []; - $this->instances = []; - } - - // Autoloading Functions - - /** - * Starts/stops autoloader. - * - * @param bool $enabled Enable/disable autoloading - * @param string|iterable $dirs Autoload directories - */ - public static function autoload(bool $enabled = true, $dirs = []): void - { - if ($enabled) { - spl_autoload_register([__CLASS__, 'loadClass']); - } else { - spl_autoload_unregister([__CLASS__, 'loadClass']); // @codeCoverageIgnore - } - - if (!empty($dirs)) { - self::addDirectory($dirs); - } - } - - /** - * Autoloads classes. - * - * Classes are not allowed to have underscores in their names. - * - * @param string $class Class name - */ - public static function loadClass(string $class): void - { - $replace_chars = self::$v2ClassLoading === true ? ['\\', '_'] : ['\\']; - $classFile = str_replace($replace_chars, '/', $class) . '.php'; - - foreach (self::$dirs as $dir) { - $filePath = "$dir/$classFile"; - - if (file_exists($filePath)) { - require_once $filePath; - return; - } - } - } - - /** - * Adds a directory for autoloading classes. - * - * @param string|iterable $dir Directory path - */ - public static function addDirectory($dir): void - { - if (\is_array($dir) || \is_object($dir)) { - foreach ($dir as $value) { - self::addDirectory($value); - } - } elseif (\is_string($dir)) { - if (!\in_array($dir, self::$dirs, true)) { - self::$dirs[] = $dir; - } - } - } - - - /** - * Sets the value for V2 class loading. - * - * @param bool $value The value to set for V2 class loading. - * - * @return void - */ - public static function setV2ClassLoading(bool $value): void - { - self::$v2ClassLoading = $value; - } -} diff --git a/index.php b/index.php deleted file mode 100644 index 0db24be..0000000 --- a/index.php +++ /dev/null @@ -1,12 +0,0 @@ - - index.php - flight + src tests diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 57ab298..d104bd5 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -5,6 +5,5 @@ includes: parameters: level: 6 paths: - - flight - - index.php + - src treatPhpDocTypesAsCertain: false diff --git a/phpunit-watcher.yml b/phpunit-watcher.yml deleted file mode 100644 index d31e912..0000000 --- a/phpunit-watcher.yml +++ /dev/null @@ -1,13 +0,0 @@ -hideManual: true -watch: - directories: - - tests - - flight - fileMask: '*.php' -notifications: - passingTests: false - failingTests: false -phpunit: - binaryPath: ./vendor/bin/phpunit - arguments: '--stop-on-failure' - timeout: 180 \ No newline at end of file diff --git a/phpunit-watcher.yml.dist b/phpunit-watcher.yml.dist new file mode 100644 index 0000000..86c3979 --- /dev/null +++ b/phpunit-watcher.yml.dist @@ -0,0 +1,13 @@ +hideManual: true +watch: + directories: + - tests + - src + fileMask: '*.php' +notifications: + passingTests: false + failingTests: false +phpunit: + binaryPath: ./vendor/bin/phpunit + arguments: '--stop-on-failure' + timeout: 180 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b890bb7..c1a85f7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,16 +13,16 @@ colors="true"> - flight/ + src/ - flight/autoload.php + src/autoload.php tests/ - tests/named-arguments/ + tests/named_arguments/ diff --git a/flight/Engine.php b/src/Engine.php similarity index 72% rename from flight/Engine.php rename to src/Engine.php index a74a21d..0acb1d7 100644 --- a/flight/Engine.php +++ b/src/Engine.php @@ -25,22 +25,23 @@ use Psr\Container\ContainerInterface; * and generating an HTTP response. * * @license MIT, https://docs.flightphp.com/license - * @copyright Copyright (c) 2011-2025, Mike Cao , n0nag0n + * @copyright Copyright (c) 2011-2026, + * Mike Cao , n0nag0n , fadrian06 * * @method void start() - * @method void stop() + * @method void stop(?int $code = null) * @method void halt(int $code = 200, string $message = '', bool $actuallyExit = true) * @method EventDispatcher eventDispatcher() - * @method Route route(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '') - * @method void group(string $pattern, callable $callback, array $group_middlewares = []) - * @method Route post(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '') - * @method Route put(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '') - * @method Route patch(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '') - * @method Route delete(string $pattern, callable|string|array $callback, bool $pass_route = false, string $alias = '') - * @method void resource(string $pattern, string $controllerClass, array $methods = []) + * @method Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') + * @method void group(string $pattern, callable $callback, array $group_middlewares = []) + * @method Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') + * @method Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') + * @method Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') + * @method Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') + * @method void resource(string $pattern, class-string $controllerClass, array> $methods = []) * @method Router router() - * @method string getUrl(string $alias) - * @method void render(string $file, array $data = null, string $key = null) + * @method string getUrl(string $alias, array $params) + * @method void render(string $file, ?array $data, string $key = null) * @method View view() * @method void onEvent(string $event, callable $callback) * @method void triggerEvent(string $event, ...$args) @@ -56,35 +57,10 @@ use Psr\Container\ContainerInterface; * @method void etag(string $id, string $type = 'strong') * @method void lastModified(int $time) * @method void download(string $filePath) - * - * @phpstan-template EngineTemplate of object - * @phpstan-method void registerContainerHandler(ContainerInterface|callable(class-string $id, array $params): ?EngineTemplate $containerHandler) - * @phpstan-method Route route(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method void group(string $pattern, callable $callback, (class-string|callable|array{0: class-string, 1: string})[] $group_middlewares = []) - * @phpstan-method Route post(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method Route put(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method Route patch(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method Route delete(string $pattern, callable|string|array{0: class-string, 1: string} $callback, bool $pass_route = false, string $alias = '') - * @phpstan-method void resource(string $pattern, class-string $controllerClass, array> $methods = []) - * @phpstan-method string getUrl(string $alias, array $params = []) - * @phpstan-method void before(string $name, Closure(array &$params, string &$output): (void|false) $callback) - * @phpstan-method void after(string $name, Closure(array &$params, string &$output): (void|false) $callback) - * @phpstan-method void set(string|iterable $key, ?mixed $value = null) - * @phpstan-method mixed get(?string $key) - * @phpstan-method void render(string $file, ?array $data = null, ?string $key = null) - * @phpstan-method void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) - * @phpstan-method void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0) - * @phpstan-method 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. - * - * phpcs:disable PSR2.Methods.MethodDeclaration.Underscore */ class Engine { - /** - * @var array List of methods that can be extended in the Engine class. - */ + /** @var array List of methods that can be extended in the Engine class */ private const MAPPABLE_METHODS = [ 'start', 'stop', @@ -112,53 +88,76 @@ class Engine 'triggerEvent' ]; - /** @var array Stored variables. */ - protected array $vars = []; + /** @var array */ + private array $vars = [ + 'flight.base_url' => null, + 'flight.case_sensitive' => false, + 'flight.handle_errors' => true, + 'flight.log_errors' => false, + 'flight.views.path' => './views', + 'flight.views.extension' => '.php', + 'flight.content_length' => true, + ]; - /** Class loader. */ protected Loader $loader; - - /** @var Dispatcher Method and class dispatcher. */ protected Dispatcher $dispatcher; - - /** Event dispatcher. */ protected EventDispatcher $eventDispatcher; - /** If the framework has been initialized or not. */ - protected bool $initialized = false; - - /** If the request has been handled or not. */ - protected bool $requestHandled = false; + /** If the request has been handled or not */ + private bool $requestHandled = false; public function __construct() { $this->loader = new Loader(); $this->dispatcher = new Dispatcher(); - $this->init(); + + // Register default components + $this->loader->register('eventDispatcher', EventDispatcher::class); + $this->loader->register('request', Request::class); + + $this->loader->register('response', Response::class, [], function (Response $response): void { + $response->content_length = $this->get('flight.content_length'); + }); + + $this->loader->register('router', Router::class, [], function (Router $router): void { + $router->caseSensitive = $this->vars['flight.case_sensitive']; + }); + + $this->loader->register('view', View::class, [], function (View $view): void { + $view->path = $this->vars['flight.views.path']; + $view->extension = $this->vars['flight.views.extension']; + }); + + foreach (self::MAPPABLE_METHODS as $name) { + $this->dispatcher->set($name, [$this, "_$name"]); + } + + // Enable error handling + if ($this->get('flight.handle_errors')) { + set_error_handler([$this, 'handleError']); + set_exception_handler([$this, 'handleException']); + } } /** - * Handles calls to class methods. - * * @param string $name Method name - * @param array $params Method parameters - * - * @throws Exception - * @return mixed Callback results + * @param array $arguments Method parameters + * @throws Throwable + * @return mixed */ - public function __call(string $name, array $params) + public function __call(string $name, array $arguments) { $callback = $this->dispatcher->get($name); - if (\is_callable($callback)) { - return $this->dispatcher->run($name, $params); + if (is_callable($callback)) { + return $this->dispatcher->run($name, $arguments); } if (!$this->loader->get($name)) { throw new Exception("$name must be a mapped method."); } - $shared = empty($params) || $params[0]; + $shared = empty($arguments) || $arguments[0]; return $this->loader->load($name, $shared); } @@ -167,79 +166,14 @@ class Engine // Core Methods // ////////////////// - /** Initializes the framework. */ - public function init(): void - { - $initialized = $this->initialized; - $self = $this; - - if ($initialized) { - $this->vars = []; - $this->loader->reset(); - $this->dispatcher->reset(); - } - - // Add this class to Dispatcher - $this->dispatcher->setEngine($this); - - // Register default components - $this->map('eventDispatcher', function () { - return EventDispatcher::getInstance(); - }); - $this->loader->register('request', Request::class); - $this->loader->register('response', Response::class); - $this->loader->register('router', Router::class); - - $this->loader->register('view', View::class, [], function (View $view) use ($self) { - $view->path = $self->get('flight.views.path'); - $view->extension = $self->get('flight.views.extension'); - }); - - foreach (self::MAPPABLE_METHODS as $name) { - $this->dispatcher->set($name, [$this, "_$name"]); - } - - // Default configuration settings - $this->set('flight.base_url'); - $this->set('flight.case_sensitive', false); - $this->set('flight.handle_errors', true); - $this->set('flight.log_errors', false); - $this->set('flight.views.path', './views'); - $this->set('flight.views.extension', '.php'); - $this->set('flight.content_length', true); - $this->set('flight.v2.output_buffering', false); - - // Startup configuration - $this->before('start', function () use ($self) { - // Enable error handling - if ($self->get('flight.handle_errors')) { - set_error_handler([$self, 'handleError']); - set_exception_handler([$self, 'handleException']); - } - - // Set case-sensitivity - $self->router()->caseSensitive = $self->get('flight.case_sensitive'); - // Set Content-Length - $self->response()->content_length = $self->get('flight.content_length'); - // This is to maintain legacy handling of output buffering - // which causes a lot of problems. This will be removed - // in v4 - $self->response()->v2_output_buffering = $this->get('flight.v2.output_buffering'); - }); - - $this->initialized = true; - } - /** - * Custom error handler. Converts errors into exceptions. - * - * @param int $errno Error number - * @param string $errstr Error string - * @param string $errfile Error file name - * @param int $errline Error file line number - * - * @return false + * Converts errors into exceptions + * @param int $errno Level of the error raised. + * @param string $errstr Error message. + * @param string $errfile Filename that the error was raised in. + * @param int $errline Line number where the error was raised. * @throws ErrorException + * @return false */ public function handleError(int $errno, string $errstr, string $errfile, int $errline): bool { @@ -250,27 +184,21 @@ class Engine return false; } - /** - * Custom exception handler. Logs exceptions. - * - * @param Throwable $e Thrown exception - */ - public function handleException(Throwable $e): void + /** Logs exceptions */ + public function handleException(Throwable $ex): void { if ($this->get('flight.log_errors')) { - error_log($e->getMessage()); // @codeCoverageIgnore + error_log($ex->getMessage()); } - $this->error($e); + $this->error($ex); } /** * Registers the container handler - * - * @param ContainerInterface|callable(class-string $id, array $params): ?T $containerHandler - * Callback function or PSR-11 Container object that sets the container and how it will inject classes - * * @template T of object + * @param ContainerInterface|callable(class-string): T $containerHandler + * Callback function or PSR-11 Container object that sets the container and how it will inject classes */ public function registerContainerHandler($containerHandler): void { @@ -278,25 +206,26 @@ class Engine } /** - * Maps a callback to a framework method. - * - * @param string $name Method name - * @param callable $callback Callback function - * + * Maps a callback to a framework method * @throws Exception If trying to map over a framework method */ public function map(string $name, callable $callback): void { - if (method_exists($this, $name)) { + $this->ensureMethodNotExists($name)->dispatcher->set($name, $callback); + } + + /** @throws Exception */ + private function ensureMethodNotExists(string $method): self + { + if (method_exists($this, $method)) { throw new Exception('Cannot override an existing framework method.'); } - $this->dispatcher->set($name, $callback); + return $this; } /** * Registers a class to a framework method. - * * # Usage example: * ``` * $app = new Engine; @@ -304,57 +233,47 @@ class Engine * * $app->user(); # <- Return a User instance * ``` - * + * @template T of object * @param string $name Method name * @param class-string $class Class name * @param array $params Class initialization parameters - * @param ?Closure(T $instance): void $callback Function to call after object instantiation - * - * @template T of object + * @param ?callable(T): void $callback Function to call after object instantiation * @throws Exception If trying to map over a framework method */ public function register(string $name, string $class, array $params = [], ?callable $callback = null): void { - if (method_exists($this, $name)) { - throw new Exception('Cannot override an existing framework method.'); - } - - $this->loader->register($name, $class, $params, $callback); + $this->ensureMethodNotExists($name)->loader->register($name, $class, $params, $callback); } - /** Unregisters a class to a framework method. */ + /** Unregisters a class to a framework method */ public function unregister(string $methodName): void { $this->loader->unregister($methodName); } /** - * Adds a pre-filter to a method. - * + * Adds a pre-filter to a method * @param string $name Method name - * @param Closure(array &$params, string &$output): (void|false) $callback + * @param callable(array &$params, string &$output): (void|false) $callback */ public function before(string $name, callable $callback): void { - $this->dispatcher->hook($name, 'before', $callback); + $this->dispatcher->hook($name, Dispatcher::FILTER_BEFORE, $callback); } /** - * Adds a post-filter to a method. - * + * Adds a post-filter to a method * @param string $name Method name - * @param Closure(array &$params, string &$output): (void|false) $callback + * @param callable(array &$params, string &$output): (void|false) $callback */ public function after(string $name, callable $callback): void { - $this->dispatcher->hook($name, 'after', $callback); + $this->dispatcher->hook($name, Dispatcher::FILTER_AFTER, $callback); } /** - * Gets a variable. - * + * Gets a variable * @param ?string $key Variable name - * * @return mixed Variable value or `null` if `$key` doesn't exists. */ public function get(?string $key = null) @@ -367,15 +286,14 @@ class Engine } /** - * Sets a variable. - * + * Sets a variable * @param string|iterable $key * Variable name as `string` or an iterable of `'varName' => $varValue` - * @param ?mixed $value Ignored if `$key` is an `iterable` + * @param mixed $value Ignored if `$key` is an `iterable` */ public function set($key, $value = null): void { - if (\is_iterable($key)) { + if (is_iterable($key)) { foreach ($key as $k => $v) { $this->vars[$k] = $v; } @@ -387,10 +305,8 @@ class Engine } /** - * Checks if a variable has been set. - * + * Checks if a variable has been set * @param string $key Variable name - * * @return bool Variable status */ public function has(string $key): bool @@ -399,8 +315,7 @@ class Engine } /** - * Unsets a variable. If no key is passed in, clear all variables. - * + * Unsets a variable. If no key is passed in, clear all variables * @param ?string $key Variable name, if `$key` isn't provided, it clear all variables. */ public function clear(?string $key = null): void @@ -414,22 +329,11 @@ class Engine } /** - * Adds a path for class autoloading. - * - * @param string $dir Directory path - */ - public function path(string $dir): void - { - $this->loader->addDirectory($dir); - } - - /** - * Processes each routes middleware. - * + * Processes each routes middleware * @param Route $route The route to process the middleware for. * @param string $eventName If this is the before or after method. */ - protected function processMiddleware(Route $route, string $eventName): bool + private function processMiddleware(Route $route, string $eventName): bool { $atLeastOneMiddlewareFailed = false; @@ -437,6 +341,7 @@ class Engine $middlewares = $eventName === Dispatcher::FILTER_BEFORE ? $route->middleware : array_reverse($route->middleware); + $params = $route->params; foreach ($middlewares as $middleware) { @@ -444,23 +349,23 @@ class Engine $middlewareObject = false; // Closure functions can only run on the before event - if ($eventName === Dispatcher::FILTER_BEFORE && is_object($middleware) === true && ($middleware instanceof Closure)) { + if ($eventName === Dispatcher::FILTER_BEFORE && is_object($middleware) && $middleware instanceof Closure) { $middlewareObject = $middleware; // If the object has already been created, we can just use it if the event name exists. - } elseif (is_object($middleware) === true) { - $middlewareObject = method_exists($middleware, $eventName) === true ? [$middleware, $eventName] : false; + } elseif (is_object($middleware)) { + $middlewareObject = method_exists($middleware, $eventName) ? [$middleware, $eventName] : false; // If the middleware is a string, we need to create the object and then call the event. - } elseif (is_string($middleware) === true && method_exists($middleware, $eventName) === true) { + } elseif (is_string($middleware) && method_exists($middleware, $eventName)) { $resolvedClass = null; // if there's a container assigned, we should use it to create the object - if ($this->dispatcher->mustUseContainer($middleware) === true) { + if ($this->dispatcher->mustUseContainer($middleware)) { $resolvedClass = $this->dispatcher->resolveContainerClass($middleware, $params); // otherwise just assume it's a plain jane class, so inject the engine // just like in Dispatcher::invokeCallable() - } elseif (class_exists($middleware) === true) { + } elseif (class_exists($middleware)) { $resolvedClass = new $middleware($this); } @@ -471,16 +376,14 @@ class Engine } // If nothing was resolved, go to the next thing - if ($middlewareObject === false) { + if (!$middlewareObject) { continue; } // This is the way that v3 handles output buffering (which captures output correctly) - $useV3OutputBuffering = - $this->response()->v2_output_buffering === false && - $route->is_streamed === false; + $useV3OutputBuffering = !$route->is_streamed; - if ($useV3OutputBuffering === true) { + if ($useV3OutputBuffering) { ob_start(); } @@ -498,7 +401,7 @@ class Engine microtime(true) - $start ); - if ($useV3OutputBuffering === true) { + if ($useV3OutputBuffering) { $this->response()->write(ob_get_clean()); } @@ -550,17 +453,6 @@ class Engine $response = $this->response(); $router = $this->router(); - if ($response->v2_output_buffering === true) { - // Flush any existing output - if (ob_get_length() > 0) { - $response->write(ob_get_clean()); // @codeCoverageIgnore - } - - // Enable output buffering - // This is closed in the Engine->_stop() method - ob_start(); - } - // Route the request $failedMiddlewareCheck = false; while ($route = $router->route($request)) { @@ -610,22 +502,18 @@ class Engine $this->triggerEvent('flight.middleware.before', $route); } - $useV3OutputBuffering = - $this->response()->v2_output_buffering === false && - $route->is_streamed === false; + $useV3OutputBuffering = !$route->is_streamed; - if ($useV3OutputBuffering === true) { + if ($useV3OutputBuffering) { ob_start(); } // Call route handler $routeStart = microtime(true); - $continue = $this->dispatcher->execute( - $route->callback, - $params - ); + $continue = $this->dispatcher->execute($route->callback, $params); $this->triggerEvent('flight.route.executed', $route, microtime(true) - $routeStart); - if ($useV3OutputBuffering === true) { + + if ($useV3OutputBuffering) { $response->write(ob_get_clean()); } @@ -638,6 +526,7 @@ class Engine $failedMiddlewareCheck = true; break; } + $this->triggerEvent('flight.middleware.after', $route); } @@ -648,7 +537,6 @@ class Engine } $router->next(); - $dispatched = false; } @@ -662,7 +550,7 @@ class Engine } elseif ($dispatched === false) { // Get the previous route and check if the method failed, but the URL was good. $lastRouteExecuted = $router->executedRoute; - if ($lastRouteExecuted !== null && $lastRouteExecuted->matchUrl($request->url) === true && $lastRouteExecuted->matchMethod($request->method) === false) { + if ($lastRouteExecuted !== null && $lastRouteExecuted->matchUrl($request->url) && !$lastRouteExecuted->matchMethod($request->method)) { $this->methodNotFound($lastRouteExecuted); } else { $this->notFound(); @@ -720,10 +608,6 @@ class Engine $response->status($code); } - if ($response->v2_output_buffering === true && ob_get_length() > 0) { - $response->write(ob_get_clean()); - } - $response->send(); } } @@ -948,9 +832,6 @@ class Engine ->status($code) ->header('Content-Type', 'application/json') ->write($json); - if ($this->response()->v2_output_buffering === true) { - $this->response()->send(); - } } /** @@ -973,10 +854,8 @@ class Engine ): void { $this->json($data, $code, $encode, $charset, $option); $jsonBody = $this->response()->getBody(); - if ($this->response()->v2_output_buffering === false) { - $this->response()->clearBody(); - $this->response()->send(); - } + $this->response()->clearBody(); + $this->response()->send(); $this->halt($code, $jsonBody, empty(getenv('PHPUNIT_TEST'))); } @@ -1007,9 +886,6 @@ class Engine ->status($code) ->header('Content-Type', 'application/javascript; charset=' . $charset) ->write($callback . '(' . $json . ');'); - if ($this->response()->v2_output_buffering === true) { - $this->response()->send(); - } } /** diff --git a/src/Flight.php b/src/Flight.php new file mode 100644 index 0000000..0752ab4 --- /dev/null +++ b/src/Flight.php @@ -0,0 +1,309 @@ +, n0nag0n , fadrian06 + */ +// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace +class Flight +{ + private static Engine $engine; + + /** + * @param array $arguments + * @return mixed + * @throws Throwable + */ + public static function __callStatic(string $name, array $arguments) + { + return self::app()->{$name}(...$arguments); + } + + public static function app(): Engine + { + return self::$engine ?? self::$engine = new Engine(); + } + + public static function setEngine(Engine $engine): void + { + self::$engine = $engine; + } + + public static function start(): void + { + self::app()->start(); + } + + public static function stop(?int $code = null): void + { + self::app()->stop($code); + } + + public static function halt(int $code = 200, string $message = '', bool $actuallyExit = true): void + { + self::app()->halt($code, $message, $actuallyExit); + } + + /** + * @template T of object + * @param class-string $class + * @param mixed[] $params + * @param ?callable(T): void $callback + */ + public static function register(string $name, string $class, array $params = [], ?callable $callback = null): void + { + self::app()->register($name, $class, $params, $callback); + } + + public static function unregister(string $methodName): void + { + self::app()->unregister($methodName); + } + + /** + * @template T of object + * @param ContainerInterface|callable(class-string, mixed[]): ?T $containerHandler + */ + public static function registerContainerHandler($containerHandler): void + { + self::app()->registerContainerHandler($containerHandler); + } + + public static function eventDispatcher(): EventDispatcher + { + return self::app()->eventDispatcher(); + } + + /** @param callable|string|array{0: class-string, 1: string} $callback */ + public static function route( + string $pattern, + $callback, + bool $pass_route = false, + string $alias = '' + ): Route { + return self::app()->route($pattern, $callback, $pass_route, $alias); + } + + /** @param array $group_middlewares */ + public static function group(string $pattern, callable $callback, array $group_middlewares = []): void + { + self::app()->group($pattern, $callback, $group_middlewares); + } + + /** @param callable|string|array{0: class-string, 1: string} $callback */ + public static function post( + string $pattern, + $callback, + bool $pass_route = false, + string $alias = '' + ): Route { + return self::app()->post($pattern, $callback, $pass_route, $alias); + } + + /** @param callable|string|array{0: class-string, 1: string} $callback */ + public static function put( + string $pattern, + $callback, + bool $pass_route = false, + string $alias = '' + ): Route { + return self::app()->put($pattern, $callback, $pass_route, $alias); + } + + /** @param callable|string|array{0: class-string, 1: string} $callback */ + public static function patch( + string $pattern, + $callback, + bool $pass_route = false, + string $alias = '' + ): Route { + return self::app()->patch($pattern, $callback, $pass_route, $alias); + } + + /** @param callable|string|array{0: class-string, 1: string} $callback */ + public static function delete( + string $pattern, + $callback, + bool $pass_route = false, + string $alias = '' + ): Route { + return self::app()->delete($pattern, $callback, $pass_route, $alias); + } + + /** + * @param class-string $controllerClass + * @param array> $methods + */ + public static function resource(string $pattern, string $controllerClass, array $methods = []): void + { + self::app()->resource($pattern, $controllerClass, $methods); + } + + public static function router(): Router + { + return self::app()->router(); + } + + /** @param array $params */ + public static function getUrl(string $alias, array $params = []): string + { + return self::app()->getUrl($alias, $params); + } + + public static function map(string $name, callable $callback): void + { + self::app()->map($name, $callback); + } + + /** @param callable(array &$params, string &$output): (void|false) $callback */ + public static function before(string $name, callable $callback): void + { + self::app()->before($name, $callback); + } + + /** @param callable(array &$params, string &$output): (void|false) $callback */ + public static function after(string $name, callable $callback): void + { + self::app()->after($name, $callback); + } + + /** + * @param string|iterable $key + * @param mixed $value + */ + public static function set($key, $value): void + { + self::app()->set($key, $value); + } + + /** @return mixed */ + public static function get(?string $key = null) + { + return self::app()->get($key); + } + + public static function has(string $key): bool + { + return self::app()->has($key); + } + + public static function clear(?string $key = null): void + { + self::app()->clear($key); + } + + /** @param ?array $data */ + public static function render(string $file, ?array $data = null, ?string $key = null): void + { + self::app()->render($file, $data, $key); + } + + public static function view(): View + { + return self::app()->view(); + } + + public static function onEvent(string $event, callable $callback): void + { + self::app()->onEvent($event, $callback); + } + + /** @param mixed ...$args */ + public static function triggerEvent(string $event, ...$args): void + { + self::app()->triggerEvent($event, ...$args); + } + + public static function request(): Request + { + return self::app()->request(); + } + + public static function response(): Response + { + return self::app()->response(); + } + + public static function redirect(string $url, int $code = 303): void + { + self::app()->redirect($url, $code); + } + + /** @param mixed $data */ + public static function json( + $data, + int $code = 200, + bool $encode = true, + string $charset = 'utf8', + int $encodeOption = 0 + ): void { + self::app()->json($data, $code, $encode, $charset, $encodeOption); + } + + /** @param mixed $data */ + public static function jsonHalt( + $data, + int $code = 200, + bool $encode = true, + string $charset = 'utf8', + int $encodeOption = 0 + ): void { + self::app()->jsonHalt($data, $code, $encode, $charset, $encodeOption); + } + + /** @param mixed $data */ + public static function jsonp( + $data, + string $param = 'jsonp', + int $code = 200, + bool $encode = true, + string $charset = 'utf8', + int $encodeOption = 0 + ): void { + self::app()->jsonp($data, $param, $code, $encode, $charset, $encodeOption); + } + + public static function error(Throwable $exception): void + { + self::app()->error($exception); + } + + public static function notFound(): void + { + self::app()->notFound(); + } + + public function methodNotFound(Route $route): void + { + self::app()->methodNotFound($route); + } + + public static function etag(string $id, string $type = 'strong'): void + { + self::app()->etag($id, $type); + } + + public static function lastModified(int $time): void + { + self::app()->lastModified($time); + } + + public static function download(string $filePath): void + { + self::app()->download($filePath); + } +} diff --git a/flight/commands/AiGenerateInstructionsCommand.php b/src/commands/AiGenerateInstructionsCommand.php similarity index 100% rename from flight/commands/AiGenerateInstructionsCommand.php rename to src/commands/AiGenerateInstructionsCommand.php diff --git a/flight/commands/AiInitCommand.php b/src/commands/AiInitCommand.php similarity index 100% rename from flight/commands/AiInitCommand.php rename to src/commands/AiInitCommand.php diff --git a/flight/commands/ControllerCommand.php b/src/commands/ControllerCommand.php similarity index 100% rename from flight/commands/ControllerCommand.php rename to src/commands/ControllerCommand.php diff --git a/flight/commands/RouteCommand.php b/src/commands/RouteCommand.php similarity index 100% rename from flight/commands/RouteCommand.php rename to src/commands/RouteCommand.php diff --git a/flight/core/Dispatcher.php b/src/core/Dispatcher.php similarity index 95% rename from flight/core/Dispatcher.php rename to src/core/Dispatcher.php index 12f3393..a3fe0eb 100644 --- a/flight/core/Dispatcher.php +++ b/src/core/Dispatcher.php @@ -18,9 +18,8 @@ use TypeError; * allows you to hook other functions to an event that can modify the * input parameters and/or the output. * - * @license MIT, http://flightphp.com/license + * @license MIT, https://docs.flightphp.com/license/ * @copyright Copyright (c) 2011, Mike Cao - * @phpstan-template EngineTemplate of object */ class Dispatcher { @@ -30,7 +29,6 @@ class Dispatcher /** Exception message if thrown by setting the container as a callable method. */ protected ?Throwable $containerException = null; - /** @var ?Engine $engine Engine instance. */ protected ?Engine $engine = null; /** @var array Mapped events. */ @@ -76,13 +74,6 @@ class Dispatcher ); } - /** - * Sets the engine instance - * - * @param Engine $engine Flight instance - * - * @return void - */ public function setEngine(Engine $engine): void { $this->engine = $engine; @@ -160,14 +151,7 @@ class Dispatcher return $output; } - /** - * Assigns a callback to an event. - * - * @param string $name Event name. - * @param callable(): (void|mixed) $callback Callback function. - * - * @return $this - */ + /** Assigns a callback to an event */ public function set(string $name, callable $callback): self { $this->events[$name] = $callback; @@ -175,13 +159,7 @@ class Dispatcher return $this; } - /** - * Gets an assigned callback. - * - * @param string $name Event name. - * - * @return null|(callable(): (void|mixed)) $callback Callback function. - */ + /** Gets an assigned callback */ public function get(string $name): ?callable { return $this->events[$name] ?? null; @@ -500,11 +478,7 @@ class Dispatcher } } - /** - * Resets the object to the initial state. - * - * @return $this - */ + /** Resets the object to the initial state */ public function reset(): self { $this->events = []; diff --git a/flight/core/EventDispatcher.php b/src/core/EventDispatcher.php similarity index 65% rename from flight/core/EventDispatcher.php rename to src/core/EventDispatcher.php index 8e60d1a..823354c 100644 --- a/flight/core/EventDispatcher.php +++ b/src/core/EventDispatcher.php @@ -6,51 +6,44 @@ namespace flight\core; class EventDispatcher { - /** @var self|null Singleton instance of the EventDispatcher */ + /** Singleton instance of the EventDispatcher */ private static ?self $instance = null; - /** @var array> */ + /** @var array> */ protected array $listeners = []; - /** - * Singleton instance of the EventDispatcher. - * - * @return self - */ + /** Singleton instance of the EventDispatcher */ public static function getInstance(): self { - if (self::$instance === null) { + if (!self::$instance) { self::$instance = new self(); } + return self::$instance; } /** * Register a callback for an event. - * * @param string $event Event name - * @param callable $callback Callback function + * @param callable(): mixed $callback Callback function */ public function on(string $event, callable $callback): void { - if (isset($this->listeners[$event]) === false) { - $this->listeners[$event] = []; - } + $this->listeners[$event] ??= []; $this->listeners[$event][] = $callback; } /** * Trigger an event with optional arguments. - * * @param string $event Event name * @param mixed ...$args Arguments to pass to the callbacks - * * @return mixed */ public function trigger(string $event, ...$args) { $result = null; - if (isset($this->listeners[$event]) === true) { + + if (isset($this->listeners[$event])) { foreach ($this->listeners[$event] as $callback) { $result = call_user_func_array($callback, $args); @@ -60,27 +53,24 @@ class EventDispatcher } } } + return $result; } /** * Check if an event has any registered listeners. - * * @param string $event Event name - * * @return bool True if the event has listeners, false otherwise */ public function hasListeners(string $event): bool { - return isset($this->listeners[$event]) === true && count($this->listeners[$event]) > 0; + return isset($this->listeners[$event]) && count($this->listeners[$event]) > 0; } /** * Get all listeners registered for a specific event. - * * @param string $event Event name - * - * @return array Array of callbacks registered for the event + * @return array Array of callbacks registered for the event */ public function getListeners(string $event): array { @@ -89,7 +79,6 @@ class EventDispatcher /** * Get a list of all events that have registered listeners. - * * @return array Array of event names */ public function getAllRegisteredEvents(): array @@ -99,41 +88,31 @@ class EventDispatcher /** * Remove a specific listener for an event. - * * @param string $event the event name - * @param callable $callback the exact callback to remove - * - * @return void + * @param callable(): mixed $callback the exact callback to remove */ public function removeListener(string $event, callable $callback): void { - if (isset($this->listeners[$event]) === true && count($this->listeners[$event]) > 0) { - $this->listeners[$event] = array_filter($this->listeners[$event], function ($listener) use ($callback) { - return $listener !== $callback; - }); + if ($this->hasListeners($event)) { + $this->listeners[$event] = array_filter( + $this->listeners[$event], + static fn(callable $listener): bool => $listener !== $callback, + ); + $this->listeners[$event] = array_values($this->listeners[$event]); // Re-index the array } } /** * Remove all listeners for a specific event. - * * @param string $event the event name - * - * @return void */ public function removeAllListeners(string $event): void { - if (isset($this->listeners[$event]) === true) { - unset($this->listeners[$event]); - } + unset($this->listeners[$event]); } - /** - * Remove the current singleton instance of the EventDispatcher. - * - * @return void - */ + /** Remove the current singleton instance of the EventDispatcher. */ public static function resetInstance(): void { self::$instance = null; diff --git a/src/core/Loader.php b/src/core/Loader.php new file mode 100644 index 0000000..897c772 --- /dev/null +++ b/src/core/Loader.php @@ -0,0 +1,101 @@ + + */ +class Loader +{ + /** @var array, ?callable(object): void}> */ + protected array $classes = []; + + /** @var array */ + protected array $instances = []; + + /** + * @template T of object + * @param class-string|callable(): T $class Class name or function to instantiate class + * @param array $params Class initialization parameters + * @param ?callable(T): void $callback $callback Function to call after object instantiation + */ + public function register( + string $alias, + $class, + array $params = [], + ?callable $callback = null + ): void { + $this->classes[$alias] = [$class, $params, $callback]; + unset($this->instances[$alias]); + } + + public function unregister(string $alias): void + { + unset($this->classes[$alias]); + } + + /** + * @throws Throwable + * @return ?object Class instance + */ + public function load(string $alias, bool $shared = true): ?object + { + if (!key_exists($alias, $this->classes)) { + return null; + } + + [$class, $params, $callback] = $this->classes[$alias]; + $instanceExists = key_exists($alias, $this->instances); + + $obj = $shared && $instanceExists + ? $this->instances[$alias] ?? null + : $this->instances[$alias] = $this->newInstance($class, $params); + + if ($callback && (!$shared || !$instanceExists)) { + $callback($obj); + } + + return $obj; + } + + /** + * Gets a new instance of a class + * @template T of object + * @param class-string|callable(): T $class Class name or callback function to instantiate class + * @param array $params Class initialization parameters + * @throws Throwable + * @return T Class instance + */ + public function newInstance($class, array $params = []): object + { + return is_callable($class) ? $class(...$params) : new $class(...$params); + } + + + /** + * Gets a registered callable + * @return ?array{class-string|callable(): object, array, ?callable(object): void} + * Class information or null if not registered + */ + public function get(string $alias): ?array + { + return $this->classes[$alias] ?? null; + } + + /** Resets the object to the initial state */ + public function reset(): self + { + $this->classes = []; + $this->instances = []; + + return $this; + } +} diff --git a/flight/database/PdoWrapper.php b/src/database/PdoWrapper.php similarity index 100% rename from flight/database/PdoWrapper.php rename to src/database/PdoWrapper.php diff --git a/flight/database/SimplePdo.php b/src/database/SimplePdo.php similarity index 100% rename from flight/database/SimplePdo.php rename to src/database/SimplePdo.php diff --git a/flight/net/Request.php b/src/net/Request.php similarity index 100% rename from flight/net/Request.php rename to src/net/Request.php diff --git a/flight/net/Response.php b/src/net/Response.php similarity index 95% rename from flight/net/Response.php rename to src/net/Response.php index 1a738cf..e848640 100644 --- a/flight/net/Response.php +++ b/src/net/Response.php @@ -22,15 +22,6 @@ class Response */ public bool $content_length = true; - /** - * This is to maintain legacy handling of output buffering - * which causes a lot of problems. This will be removed - * in v4 - * - * @var boolean - */ - public bool $v2_output_buffering = false; - /** * HTTP status codes * @@ -271,7 +262,7 @@ class Response $this->clearBody(); // This needs to clear the output buffer if it's on - if ($this->v2_output_buffering === false && ob_get_length() > 0) { + if (ob_get_length() > 0) { ob_clean(); } @@ -421,18 +412,8 @@ class Response */ public function send(): void { - // legacy way of handling this - if ($this->v2_output_buffering === true) { - if (ob_get_length() > 0) { - ob_end_clean(); // @codeCoverageIgnore - } - } - $start = microtime(true); - // Only for the v3 output buffering. - if ($this->v2_output_buffering === false) { - $this->processResponseCallbacks(); - } + $this->processResponseCallbacks(); if ($this->headersSent() === false) { $this->sendHeaders(); diff --git a/flight/net/Route.php b/src/net/Route.php similarity index 100% rename from flight/net/Route.php rename to src/net/Route.php diff --git a/flight/net/Router.php b/src/net/Router.php similarity index 100% rename from flight/net/Router.php rename to src/net/Router.php diff --git a/flight/net/UploadedFile.php b/src/net/UploadedFile.php similarity index 100% rename from flight/net/UploadedFile.php rename to src/net/UploadedFile.php diff --git a/flight/template/View.php b/src/template/View.php similarity index 100% rename from flight/template/View.php rename to src/template/View.php diff --git a/flight/util/Collection.php b/src/util/Collection.php similarity index 100% rename from flight/util/Collection.php rename to src/util/Collection.php diff --git a/flight/util/Json.php b/src/util/Json.php similarity index 100% rename from flight/util/Json.php rename to src/util/Json.php diff --git a/flight/util/ReturnTypeWillChange.php b/src/util/ReturnTypeWillChange.php similarity index 100% rename from flight/util/ReturnTypeWillChange.php rename to src/util/ReturnTypeWillChange.php diff --git a/tests/AutoloadTest.php b/tests/AutoloadTest.php index 97ee31a..77fb014 100644 --- a/tests/AutoloadTest.php +++ b/tests/AutoloadTest.php @@ -15,7 +15,6 @@ class AutoloadTest extends TestCase protected function setUp(): void { $this->app = new Engine(); - $this->app->path(__DIR__ . '/classes'); } // Autoload a class diff --git a/tests/DocExamplesTest.php b/tests/DocExamplesTest.php index 96121f3..c3ac378 100644 --- a/tests/DocExamplesTest.php +++ b/tests/DocExamplesTest.php @@ -16,7 +16,7 @@ class DocExamplesTest extends TestCase { $_SERVER = []; $_REQUEST = []; - Flight::init(); + Flight::app(); Flight::setEngine(new Engine()); } @@ -45,25 +45,6 @@ class DocExamplesTest extends TestCase $this->assertEquals('[]', Flight::response()->getBody()); } - public function testMapNotFoundMethodV2OutputBuffering(): void - { - Flight::map('notFound', function () { - Flight::json([], 404); - }); - - Flight::request()->url = '/not-found'; - - Flight::route('/', function () { - echo 'hello world!'; - }); - - Flight::set('flight.v2.output_buffering', true); - Flight::start(); - ob_get_clean(); - $this->assertEquals(404, Flight::response()->status()); - $this->assertEquals('[]', Flight::response()->getBody()); - } - public function testMapErrorMethod(): void { Flight::map('error', function (Throwable $error) { @@ -81,12 +62,9 @@ class DocExamplesTest extends TestCase Flight::request()->method = 'GET'; Flight::request()->url = '/'; - $router->get( - '/', - function () { - Flight::response()->write('from resp '); - } - ); + $router->get('/', static function () { + Flight::response()->write('from resp '); + }); Flight::start(); diff --git a/tests/EngineTest.php b/tests/EngineTest.php index d89e453..5e5dfaa 100644 --- a/tests/EngineTest.php +++ b/tests/EngineTest.php @@ -32,13 +32,7 @@ class EngineTest extends TestCase public function testInitBeforeStart(): void { - $engine = new class extends Engine { - public function getInitializedVar() - { - return $this->initialized; - } - }; - $this->assertTrue($engine->getInitializedVar()); + $engine = new Engine; // we need to setup a dummy route $engine->route('/someRoute', function () {}); @@ -49,25 +43,6 @@ class EngineTest extends TestCase $this->assertTrue($engine->response()->content_length); } - public function testInitBeforeStartV2OutputBuffering(): void - { - $engine = new class extends Engine { - public function getInitializedVar(): bool - { - return $this->initialized; - } - }; - $engine->set('flight.v2.output_buffering', true); - $this->assertTrue($engine->getInitializedVar()); - $engine->start(); - - // This is a necessary evil because of how the v2 output buffer works. - ob_end_clean(); - - $this->assertFalse($engine->router()->caseSensitive); - $this->assertTrue($engine->response()->content_length); - } - public function testHandleErrorNoErrorNumber(): void { $engine = new Engine(); @@ -153,26 +128,6 @@ class EngineTest extends TestCase $engine->start(); } - public function testStartWithRouteButReturnedValueThrows404V2OutputBuffering(): void - { - $_SERVER['REQUEST_METHOD'] = 'GET'; - $_SERVER['REQUEST_URI'] = '/someRoute'; - - $engine = new class extends Engine { - public function getInitializedVar(): bool - { - return $this->initialized; - } - }; - $engine->set('flight.v2.output_buffering', true); - $engine->route('/someRoute', function () { - echo 'i ran'; - return true; - }, true); - $this->expectOutputString('

404 Not Found

The page you have requested could not be found.

'); - $engine->start(); - } - public function testDoubleReturnTrueRoutesContinueIteration(): void { $_SERVER['REQUEST_METHOD'] = 'GET'; @@ -322,34 +277,6 @@ class EngineTest extends TestCase $this->assertEquals(500, $engine->response()->status()); } - public function testStopWithCodeV2OutputBuffering(): void - { - $engine = new class extends Engine { - public function getLoader() - { - return $this->loader; - } - }; - // doing this so we can overwrite some parts of the response - $engine->getLoader()->register('response', function () { - return new class extends Response { - public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): self - { - return $this; - } - }; - }); - $engine->set('flight.v2.output_buffering', true); - $engine->route('/testRoute', function () use ($engine) { - echo 'I am a teapot'; - $engine->stop(500); - }); - $engine->request()->url = '/testRoute'; - $engine->start(); - $this->expectOutputString('I am a teapot'); - $this->assertEquals(500, $engine->response()->status()); - } - public function testPostRoute(): void { $engine = new Engine(); @@ -519,16 +446,6 @@ class EngineTest extends TestCase $engine->json(['key1' => 'value1', 'key2' => 'value2', 'utf8_emoji' => "\xB1\x31"]); } - public function testJsonV2OutputBuffering(): void - { - $engine = new Engine(); - $engine->response()->v2_output_buffering = true; - $engine->json(['key1' => 'value1', 'key2' => 'value2']); - $this->expectOutputString('{"key1":"value1","key2":"value2"}'); - $this->assertEquals('application/json', $engine->response()->headers()['Content-Type']); - $this->assertEquals(200, $engine->response()->status()); - } - public function testJsonHalt(): void { $engine = new Engine(); @@ -549,17 +466,6 @@ class EngineTest extends TestCase $this->assertEquals('whatever({"key1":"value1","key2":"value2"});', $engine->response()->getBody()); } - public function testJsonPV2OutputBuffering(): void - { - $engine = new Engine(); - $engine->response()->v2_output_buffering = true; - $engine->request()->query['jsonp'] = 'whatever'; - $engine->jsonp(['key1' => 'value1', 'key2' => 'value2']); - $this->expectOutputString('whatever({"key1":"value1","key2":"value2"});'); - $this->assertEquals('application/javascript; charset=utf-8', $engine->response()->headers()['Content-Type']); - $this->assertEquals(200, $engine->response()->status()); - } - public function testJsonpBadParam(): void { $engine = new Engine(); @@ -569,16 +475,6 @@ class EngineTest extends TestCase $this->assertEquals(200, $engine->response()->status()); } - public function testJsonpBadParamV2OutputBuffering(): void - { - $engine = new Engine(); - $engine->response()->v2_output_buffering = true; - $engine->jsonp(['key1' => 'value1', 'key2' => 'value2']); - $this->expectOutputString('({"key1":"value1","key2":"value2"});'); - $this->assertEquals('application/javascript; charset=utf-8', $engine->response()->headers()['Content-Type']); - $this->assertEquals(200, $engine->response()->status()); - } - public function testEtagSimple(): void { $engine = new Engine(); diff --git a/tests/EventSystemTest.php b/tests/EventSystemTest.php index 9a229b6..4126289 100644 --- a/tests/EventSystemTest.php +++ b/tests/EventSystemTest.php @@ -15,7 +15,7 @@ class EventSystemTest extends TestCase { // Reset the Flight engine before each test to ensure a clean state Flight::setEngine(new Engine()); - Flight::app()->init(); + Flight::app(); Flight::eventDispatcher()->resetInstance(); // Clear any existing listeners } diff --git a/tests/FlightTest.php b/tests/FlightTest.php index 5b0b516..b407f70 100644 --- a/tests/FlightTest.php +++ b/tests/FlightTest.php @@ -20,7 +20,7 @@ class FlightTest extends TestCase { $_SERVER = []; $_REQUEST = []; - Flight::init(); + Flight::app(); Flight::setEngine(new Engine()); Flight::set('flight.views.path', __DIR__ . '/views'); } @@ -71,8 +71,6 @@ class FlightTest extends TestCase // Register a class public function testRegister(): void { - Flight::path(__DIR__ . '/classes'); - Flight::register('user', User::class); $user = Flight::user(); @@ -277,25 +275,6 @@ class FlightTest extends TestCase $this->assertEquals('test', Flight::response()->getBody()); } - public function testHookOutputBufferingV2OutputBuffering(): void - { - Flight::route('/test', function () { - echo 'test'; - }); - - Flight::before('start', function ($output) { - echo 'hooked before start'; - }); - - Flight::set('flight.v2.output_buffering', true); - Flight::request()->url = '/test'; - - $this->expectOutputString('hooked before starttest'); - ob_start(); - Flight::start(); - $this->assertEquals('hooked before starttest', Flight::response()->getBody()); - } - public function testStreamRoute(): void { $response_mock = new class extends Response { diff --git a/tests/LoaderTest.php b/tests/LoaderTest.php index de37efa..7016130 100644 --- a/tests/LoaderTest.php +++ b/tests/LoaderTest.php @@ -5,9 +5,9 @@ declare(strict_types=1); namespace tests; use flight\core\Loader; -use tests\classes\Factory; -use tests\classes\User; use PHPUnit\Framework\TestCase; +use tests\classes\User; +use tests\classes\Factory; use tests\classes\TesterClass; class LoaderTest extends TestCase @@ -17,63 +17,41 @@ class LoaderTest extends TestCase protected function setUp(): void { $this->loader = new Loader(); - $this->loader->autoload(true, __DIR__ . '/classes'); - } - - // Autoload a class - public function testAutoload(): void - { - $this->loader->register('tests', User::class); - - $test = $this->loader->load('tests'); - - self::assertIsObject($test); - self::assertInstanceOf(User::class, $test); } - // Register a class public function testRegister(): void { $this->loader->register('a', User::class); - $user = $this->loader->load('a'); - self::assertIsObject($user); self::assertInstanceOf(User::class, $user); - self::assertEquals('', $user->name); + self::assertSame('', $user->name); } - // Register a class with constructor parameters public function testRegisterWithConstructor(): void { $this->loader->register('b', User::class, ['Bob']); - $user = $this->loader->load('b'); - self::assertIsObject($user); self::assertInstanceOf(User::class, $user); - self::assertEquals('Bob', $user->name); + self::assertSame('Bob', $user->name); } - // Register a class with initialization public function testRegisterWithInitialization(): void { - $this->loader->register('c', User::class, ['Bob'], function ($user) { + $this->loader->register('c', User::class, ['Bob'], static function (User $user): void { $user->name = 'Fred'; }); $user = $this->loader->load('c'); - self::assertIsObject($user); self::assertInstanceOf(User::class, $user); self::assertEquals('Fred', $user->name); } - // Get a non-shared instance of a class public function testSharedInstance(): void { $this->loader->register('d', User::class); - $user1 = $this->loader->load('d'); $user2 = $this->loader->load('d'); $user3 = $this->loader->load('d', false); @@ -82,38 +60,24 @@ class LoaderTest extends TestCase self::assertNotSame($user1, $user3); } - // Gets an object from a factory method public function testRegisterUsingCallable(): void { - $this->loader->register('e', ['\tests\classes\Factory', 'create']); - + $this->loader->register('e', [Factory::class, 'create']); $obj = $this->loader->load('e'); - - self::assertIsObject($obj); - self::assertInstanceOf(Factory::class, $obj); - $obj2 = $this->loader->load('e'); + $obj3 = $this->loader->load('e', false); - self::assertIsObject($obj2); - self::assertInstanceOf(Factory::class, $obj2); + self::assertInstanceOf(Factory::class, $obj); self::assertSame($obj, $obj2); - - $obj3 = $this->loader->load('e', false); - self::assertIsObject($obj3); self::assertInstanceOf(Factory::class, $obj3); self::assertNotSame($obj, $obj3); } - // Gets an object from a callback function public function testRegisterUsingCallback(): void { - $this->loader->register('f', function () { - return Factory::create(); - }); - + $this->loader->register('f', static fn(): Factory => Factory::create()); $obj = $this->loader->load('f'); - self::assertIsObject($obj); self::assertInstanceOf(Factory::class, $obj); } @@ -121,15 +85,22 @@ class LoaderTest extends TestCase { $this->loader->register('g', User::class); $current_class = $this->loader->get('g'); - $this->assertEquals([User::class, [], null], $current_class); + + $this->assertSame([User::class, [], null], $current_class); + $this->loader->unregister('g'); $unregistered_class_result = $this->loader->get('g'); + $this->assertNull($unregistered_class_result); } public function testNewInstance6Params(): void { - $TesterClass = $this->loader->newInstance(TesterClass::class, ['Bob', 'Fred', 'Joe', 'Jane', 'Sally', 'Suzie']); + $TesterClass = $this->loader->newInstance( + TesterClass::class, + ['Bob', 'Fred', 'Joe', 'Jane', 'Sally', 'Suzie'] + ); + $this->assertEquals('Bob', $TesterClass->param1); $this->assertEquals('Fred', $TesterClass->param2); $this->assertEquals('Joe', $TesterClass->param3); @@ -137,32 +108,4 @@ class LoaderTest extends TestCase $this->assertEquals('Sally', $TesterClass->param5); $this->assertEquals('Suzie', $TesterClass->param6); } - - public function testAddDirectoryAsArray(): void - { - $loader = new class extends Loader { - public function getDirectories() - { - return self::$dirs; - } - }; - $loader->addDirectory([__DIR__ . '/classes']); - self::assertEquals([ - dirname(__DIR__), - __DIR__ . '/classes' - ], $loader->getDirectories()); - } - - public function testV2ClassLoading(): void - { - $loader = new class extends Loader { - public static function getV2ClassLoading() - { - return self::$v2ClassLoading; - } - }; - $this->assertTrue($loader::getV2ClassLoading()); - $loader::setV2ClassLoading(false); - $this->assertFalse($loader::getV2ClassLoading()); - } } diff --git a/tests/RenderTest.php b/tests/RenderTest.php index ab71965..36391f9 100644 --- a/tests/RenderTest.php +++ b/tests/RenderTest.php @@ -21,7 +21,6 @@ class RenderTest extends TestCase public function testRenderView(): void { $this->app->render('hello', ['name' => 'Bob']); - $this->expectOutputString('Hello, Bob!'); } diff --git a/tests/classes/TesterClass.php b/tests/classes/TesterClass.php index 289ee04..a0066f4 100644 --- a/tests/classes/TesterClass.php +++ b/tests/classes/TesterClass.php @@ -4,17 +4,23 @@ declare(strict_types=1); namespace tests\classes; -class TesterClass +final class TesterClass { - public $param1; - public $param2; - public $param3; - public $param4; - public $param5; - public $param6; + public ?string $param1; + public ?string $param2; + public ?string $param3; + public ?string $param4; + public ?string $param5; + public ?string $param6; - public function __construct($param1, $param2, $param3, $param4, $param5, $param6) - { + public function __construct( + ?string $param1, + ?string $param2, + ?string $param3, + ?string $param4, + ?string $param5, + ?string $param6 + ) { $this->param1 = $param1; $this->param2 = $param2; $this->param3 = $param3; diff --git a/tests/classes/User.php b/tests/classes/User.php index 0d14102..1a6c30b 100644 --- a/tests/classes/User.php +++ b/tests/classes/User.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace tests\classes; -class User +final class User { public string $name; diff --git a/tests/commands/RouteCommandTest.php b/tests/commands/RouteCommandTest.php index 3aea0b1..5cea39d 100644 --- a/tests/commands/RouteCommandTest.php +++ b/tests/commands/RouteCommandTest.php @@ -26,7 +26,7 @@ class RouteCommandTest extends TestCase $_SERVER = []; $_REQUEST = []; - Flight::init(); + Flight::app(); Flight::setEngine(new Engine()); } diff --git a/tests/groupcompactsyntax/FlightRouteCompactSyntaxTest.php b/tests/group_compact_syntax/FlightRouteCompactSyntaxTest.php similarity index 96% rename from tests/groupcompactsyntax/FlightRouteCompactSyntaxTest.php rename to tests/group_compact_syntax/FlightRouteCompactSyntaxTest.php index 84d168f..2c8d3a1 100644 --- a/tests/groupcompactsyntax/FlightRouteCompactSyntaxTest.php +++ b/tests/group_compact_syntax/FlightRouteCompactSyntaxTest.php @@ -2,13 +2,10 @@ declare(strict_types=1); -namespace tests\groupcompactsyntax; +namespace tests\group_compact_syntax; use Flight; use PHPUnit\Framework\TestCase; -use tests\groupcompactsyntax\PostsController; -use tests\groupcompactsyntax\TodosController; -use tests\groupcompactsyntax\UsersController; final class FlightRouteCompactSyntaxTest extends TestCase { diff --git a/tests/groupcompactsyntax/PostsController.php b/tests/group_compact_syntax/PostsController.php similarity index 93% rename from tests/groupcompactsyntax/PostsController.php rename to tests/group_compact_syntax/PostsController.php index f95f60d..5e693fb 100644 --- a/tests/groupcompactsyntax/PostsController.php +++ b/tests/group_compact_syntax/PostsController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace tests\groupcompactsyntax; +namespace tests\group_compact_syntax; final class PostsController { diff --git a/tests/groupcompactsyntax/TodosController.php b/tests/group_compact_syntax/TodosController.php similarity index 83% rename from tests/groupcompactsyntax/TodosController.php rename to tests/group_compact_syntax/TodosController.php index 91c30cf..744f6b7 100644 --- a/tests/groupcompactsyntax/TodosController.php +++ b/tests/group_compact_syntax/TodosController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace tests\groupcompactsyntax; +namespace tests\group_compact_syntax; final class TodosController { diff --git a/tests/groupcompactsyntax/UsersController.php b/tests/group_compact_syntax/UsersController.php similarity index 84% rename from tests/groupcompactsyntax/UsersController.php rename to tests/group_compact_syntax/UsersController.php index d6372b5..7323771 100644 --- a/tests/groupcompactsyntax/UsersController.php +++ b/tests/group_compact_syntax/UsersController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace tests\groupcompactsyntax; +namespace tests\group_compact_syntax; final class UsersController { diff --git a/tests/named-arguments/ExampleClass.php b/tests/named_arguments/ExampleClass.php similarity index 78% rename from tests/named-arguments/ExampleClass.php rename to tests/named_arguments/ExampleClass.php index 508068c..9555047 100644 --- a/tests/named-arguments/ExampleClass.php +++ b/tests/named_arguments/ExampleClass.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace tests\named_arguments; + // phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace class ExampleClass { diff --git a/tests/named-arguments/FlightTest.php b/tests/named_arguments/FlightTest.php similarity index 98% rename from tests/named-arguments/FlightTest.php rename to tests/named_arguments/FlightTest.php index 6593450..9053b02 100644 --- a/tests/named-arguments/FlightTest.php +++ b/tests/named_arguments/FlightTest.php @@ -2,10 +2,9 @@ declare(strict_types=1); -namespace Tests\PHP8; +namespace tests\named_arguments; use DateTimeImmutable; -use ExampleClass; use Flight; use flight\Container; use flight\Engine; diff --git a/tests/server/AuthCheck.php b/tests/server/AuthCheck.php index 79e8f67..c042c1b 100644 --- a/tests/server/AuthCheck.php +++ b/tests/server/AuthCheck.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tests\Server; +namespace tests\server; class AuthCheck { diff --git a/tests/server/LayoutMiddleware.php b/tests/server/LayoutMiddleware.php index 150985b..01058c0 100644 --- a/tests/server/LayoutMiddleware.php +++ b/tests/server/LayoutMiddleware.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tests\Server; +namespace tests\server; use Flight; diff --git a/tests/server/OverwriteBodyMiddleware.php b/tests/server/OverwriteBodyMiddleware.php index 98e8468..6a3dfa8 100644 --- a/tests/server/OverwriteBodyMiddleware.php +++ b/tests/server/OverwriteBodyMiddleware.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tests\Server; +namespace tests\server; use Flight; diff --git a/tests/server/Pascal_Snake_Case.php b/tests/server/Pascal_Snake_Case.php index d80ed41..df9a66f 100644 --- a/tests/server/Pascal_Snake_Case.php +++ b/tests/server/Pascal_Snake_Case.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tests\Server; +namespace tests\server; class Pascal_Snake_Case // phpcs:ignore { diff --git a/tests/server/index.php b/tests/server/index.php index 6bb9dca..f4193e8 100644 --- a/tests/server/index.php +++ b/tests/server/index.php @@ -7,10 +7,10 @@ use flight\core\Loader; use flight\database\PdoWrapper; use tests\classes\Container; use tests\classes\ContainerDefault; -use Tests\Server\AuthCheck; -use Tests\Server\LayoutMiddleware; -use Tests\Server\OverwriteBodyMiddleware; -use Tests\Server\Pascal_Snake_Case; +use tests\server\AuthCheck; +use tests\server\LayoutMiddleware; +use tests\server\OverwriteBodyMiddleware; +use tests\server\Pascal_Snake_Case; /* * This is the test file where we can open up a quick test server and make diff --git a/tests/server-v2/index.php b/tests/server_v2/index.php similarity index 99% rename from tests/server-v2/index.php rename to tests/server_v2/index.php index 4f45d99..1aadcc1 100644 --- a/tests/server-v2/index.php +++ b/tests/server_v2/index.php @@ -9,7 +9,7 @@ declare(strict_types=1); * @author Kristaps Muižnieks https://github.com/krmu */ -namespace Tests\ServerV2 { +namespace tests\server_v2 { class AuthCheck { public function before(): void @@ -23,7 +23,7 @@ namespace Tests\ServerV2 { namespace { - use Tests\ServerV2\AuthCheck; + use tests\server_v2\AuthCheck; require_once __DIR__ . '/../phpunit_autoload.php'; diff --git a/tests/server-v2/template.phtml b/tests/server_v2/template.phtml similarity index 100% rename from tests/server-v2/template.phtml rename to tests/server_v2/template.phtml