diff --git a/.env b/.env
deleted file mode 100644
index e69de29..0000000
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 848d6db..bb82d42 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,4 +1,4 @@
-name: Configure and Run Tests Before Release
+name: Release
on:
push:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 0073413..11c9475 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,4 +1,4 @@
-name: Execute Tests
+name: Tests
on:
push:
@@ -63,11 +63,8 @@ jobs:
- name: Push changes to main
run: |
- git fetch origin main dev
- git checkout main
- git config pull.rebase false
- git pull origin main
- git merge origin/dev --allow-unrelated-histories --no-ff
- git push origin main
+ git checkout -b main
+ git reset --hard dev
+ git push -u -f origin main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Router/MapRoute.php b/Router/MapRoute.php
index 3ac6a2b..9de010c 100644
--- a/Router/MapRoute.php
+++ b/Router/MapRoute.php
@@ -2,8 +2,8 @@
namespace PhpSlides\Router;
-use PhpSlides\Src\Controller\Controller;
-use PhpSlides\Src\Foundation\Application;
+use PhpSlides\Core\Controller\Controller;
+use PhpSlides\Core\Foundation\Application;
use PhpSlides\Router\Interface\MapInterface;
/**
@@ -18,8 +18,8 @@
*/
class MapRoute extends Controller implements MapInterface
{
- use \PhpSlides\Src\Utils\Validate;
- use \PhpSlides\Src\Utils\Routes\StrictTypes;
+ use \PhpSlides\Core\Utils\Validate;
+ use \PhpSlides\Core\Utils\Routes\StrictTypes;
/**
* @var string|array $route The route(s) to be mapped.
@@ -64,14 +64,13 @@ public function match(string $method, string|array $route): bool|array
* | $_REQUEST['uri'] will be empty if req uri is /
* ----------------------------------------------
*/
- self::$request_uri = strtolower(
- preg_replace("/(^\/)|(\/$)/", '', Application::$request_uri),
- );
+ self::$request_uri =
+ preg_replace("/(^\/)|(\/$)/", '', Application::$request_uri);
self::$request_uri = empty(self::$request_uri) ? '/' : self::$request_uri;
self::$route = is_array($route)
? $route
- : strtolower(preg_replace("/(^\/)|(\/$)/", '', $route));
+ : preg_replace("/(^\/)|(\/$)/", '', $route);
// Firstly, resolve route with pattern
if (is_array(self::$route))
@@ -191,9 +190,15 @@ public function match(string $method, string|array $route): bool|array
* -----------------------------------
*/
$reqUri = str_replace('/', '\\/', $reqUri);
+ $route = self::$route;
+
+ if (Application::$caseInSensitive === true) {
+ $reqUri = strtolower($reqUri);
+ $route = strtolower($route);
+ }
// now matching route with regex
- if (preg_match("/$reqUri/", self::$route . '$'))
+ if (preg_match("/$reqUri/", $route . '$'))
{
// checks if the requested method is of the given route
if (
@@ -247,6 +252,7 @@ private function match_routing (): bool|array
{
$uri = [];
$str_route = '';
+ $request_uri = self::$request_uri;
if (is_array(self::$route))
{
@@ -255,14 +261,20 @@ private function match_routing (): bool|array
$each_route = preg_replace("/(^\/)|(\/$)/", '', self::$route[$i]);
empty($each_route)
- ? array_push($uri, strtolower('/'))
- : array_push($uri, strtolower($each_route));
+ ? array_push($uri, '/')
+ : array_push($uri, Application::$caseInSensitive === true ? strtolower($each_route) : $each_route);
}
}
else
{
$str_route = empty(self::$route) ? '/' : self::$route;
}
+
+
+ if (Application::$caseInSensitive === true) {
+ $request_uri = strtolower($request_uri);
+ $str_route = strtolower($str_route);
+ }
if (
in_array(self::$request_uri, $uri) ||
@@ -329,9 +341,15 @@ private function pattern (): array|bool
*/
private function validatePattern (string $pattern): array|bool
{
+ $request_uri = self::$request_uri;
$pattern = preg_replace("/(^\/)|(\/$)/", '', trim(substr($pattern, 8)));
- if (fnmatch($pattern, self::$request_uri))
+ if (Application::$caseInSensitive === true) {
+ $request_uri = strtolower($request_uri);
+ $pattern = strtolower($pattern);
+ }
+
+ if (fnmatch($pattern, $request_uri))
{
if (
!in_array($_SERVER['REQUEST_METHOD'], self::$method) &&
@@ -349,4 +367,4 @@ private function validatePattern (string $pattern): array|bool
}
return false;
}
-}
+}
\ No newline at end of file
diff --git a/Router/Route.php b/Router/Route.php
index f6805c0..cb070d2 100644
--- a/Router/Route.php
+++ b/Router/Route.php
@@ -17,8 +17,8 @@
use Closure;
use PhpSlides\Exception;
-use PhpSlides\Src\Traits\FileHandler;
-use PhpSlides\Src\Controller\Controller;
+use PhpSlides\Core\Traits\FileHandler;
+use PhpSlides\Core\Controller\Controller;
use PhpSlides\Router\Interface\RouteInterface;
/**
@@ -51,6 +51,8 @@ class Route extends Controller implements RouteInterface
private ?array $mapRoute = null;
+ private bool $caseSensitive = false;
+
private ?Closure $handleInvalidParameterType = null;
private static array $routes;
@@ -140,14 +142,14 @@ public function name(string $name): self
* @param string $route
* @param Closure $callback
*/
- public function route(string $route, Closure $callback): self
+ public function route(string $route, callable $callback): self
{
- $route = rtrim('/', self::$map['route']) . '/' . ltrim('/', $route);
+ $route = rtrim(self::$map['route'], '/') . '/' . ltrim($route, '/');
if (self::$map) {
$this->mapRoute = [
'route' => $route,
- 'method' => self::$map['method'],
+ 'method' => '*',
'callback' => $callback,
];
} else {
@@ -215,6 +217,12 @@ public function handleInvalidParameterType(Closure $closure): self
return $this;
}
+ public function caseSensitive(): self
+ {
+ $this->caseSensitive = true;
+ return $this;
+ }
+
/**
* Applies Authentication Guard to the current route.
*
@@ -393,6 +401,9 @@ public function __destruct()
$route_index = end(self::$route);
$route_index = is_array($route_index) ? $route_index[0] : $route_index;
+ $GLOBALS['__registered_routes'][$route_index]['caseSensitive'] =
+ $this->caseSensitive;
+
if (self::$map !== null) {
$GLOBALS['__registered_routes'][$route_index]['map'] = self::$map;
}
diff --git a/Router/view.php b/Router/view.php
index 0be1e52..7935cca 100644
--- a/Router/view.php
+++ b/Router/view.php
@@ -2,8 +2,8 @@
namespace PhpSlides\Router;
-use component;
-use PhpSlides\Src\Foundation\Application;
+use function component;
+use PhpSlides\Core\Foundation\Application;
/**
* --------------------------------------------------------------
@@ -31,11 +31,11 @@ final class view
*
* --------------------------------------------------------------
*/
- final public static function render(string $view, mixed ...$props): mixed
+ final public static function render (string $view, mixed ...$props): mixed
{
// split :: into array and extract the folder and files
$file = preg_replace('/(::)|::/', '/', $view);
- $file = strtolower(trim($file, '\/\/'));
+ $file = trim($file, '\/\/');
$file_uri = Application::$viewsDir . $file;
header('Content-Type: text/html');
diff --git a/composer.json b/composer.json
index 7af20e9..899caad 100644
--- a/composer.json
+++ b/composer.json
@@ -4,7 +4,7 @@
"homepage": "https://github.com/PhpSlides",
"type": "library",
"license": "MIT",
- "keywords": [ "framework", "phpslides" ],
+ "keywords": ["framework", "phpslides"],
"support": {
"issues": "https://github.com/PhpSlides/framework/issues",
"source": "https://github.com/PhpSlides/framework"
@@ -31,22 +31,23 @@
},
"autoload": {
"psr-4": {
- "PhpSlides\\": [ "src/Exception/" ],
- "PhpSlides\\Src\\": [ "src/" ],
- "PhpSlides\\Router\\": [ "Router/" ]
+ "PhpSlides\\": "src/Exception/",
+ "PhpSlides\\Core\\": "src/",
+ "PhpSlides\\Router\\": "Router/"
},
- "files": [ "src/Bootstrap/App.php" ]
+ "files": ["src/Bootstrap/App.php"]
},
"autoload-dev": {
"psr-4": {
- "PhpSlides\\Tests\\": "tests/"
+ "PhpSlides\\Tests\\": "tests/__tests__/"
}
},
"config": {
"preferred-install": "dist"
},
"scripts": {
- "test": "vendor/bin/phpunit"
+ "test": "phpunit || vendor/bin/phpunit || php vendor/bin/phpunit",
+ "post-install-cmd": ["PhpSlides\\Core\\Cache\\Cache::clear()"]
},
"minimum-stability": "stable",
"prefer-stable": true
diff --git a/phpunit.xml b/phpunit.xml
index a1a41f3..aff9389 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -10,7 +10,7 @@
backupStaticProperties="false">
- tests/tests
+ tests/__tests__
diff --git a/src/Bootstrap/App.php b/src/Bootstrap/App.php
index d43ba7c..341170c 100644
--- a/src/Bootstrap/App.php
+++ b/src/Bootstrap/App.php
@@ -3,4 +3,4 @@
/**
* Start the PhpSlides Application
*/
-(new \PhpSlides\Src\Foundation\Application())->create();
+(new \PhpSlides\Core\Foundation\Application())->create();
diff --git a/src/Cache/Cache.php b/src/Cache/Cache.php
index 959b6a9..678defb 100644
--- a/src/Cache/Cache.php
+++ b/src/Cache/Cache.php
@@ -1,8 +1,8 @@
load(__DIR__ . '/cors.php');
diff --git a/src/Config/cors.php b/src/Config/cors.php
index 5961680..421ce3a 100644
--- a/src/Config/cors.php
+++ b/src/Config/cors.php
@@ -1,32 +1,34 @@
safeLoad(Application::$configsDir . 'cors.php')
- ->getLoad() ?:
- [];
+ (new FileLoader())
+ ->safeLoad(Application::$configsDir . 'cors.php')
+ ->getLoad() ?:
+ [];
-foreach ($cors as $key => $value) {
+foreach ($cors as $key => $value)
+{
$key = 'Access-Control-' . str_replace('_', '-', ucwords($key, '_'));
$value = is_array($value) ? implode(', ', $value) : $value;
$header_value =
- $key . ': ' . (is_bool($value) ? var_export($value, true) : $value);
+ $key . ': ' . (is_bool($value) ? var_export($value, true) : $value);
header($header_value);
}
/**
* Handle preflight requests (OPTIONS method)
*/
-if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
+if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS')
+{
class Log
{
use Logger;
- public function __construct()
+ public function __construct ()
{
self::log();
}
diff --git a/src/Config/env.config.php b/src/Config/env.config.php
index 529b126..b23efa8 100644
--- a/src/Config/env.config.php
+++ b/src/Config/env.config.php
@@ -1,13 +1,16 @@
load();
-} catch (Exception $e) {
+}
+catch ( Exception $e )
+{
exit($e->getMessage());
}
diff --git a/src/Config/guards.php b/src/Config/guards.php
index 08fa606..1b5ca82 100644
--- a/src/Config/guards.php
+++ b/src/Config/guards.php
@@ -1,9 +1,9 @@
safeLoad(Application::$configsDir . 'guards.php')
- ->getLoad() ?:
- [];
+ ->safeLoad(Application::$configsDir . 'guards.php')
+ ->getLoad() ?:
+ [];
diff --git a/src/Config/jwt.config.php b/src/Config/jwt.config.php
index 99619d1..a736504 100644
--- a/src/Config/jwt.config.php
+++ b/src/Config/jwt.config.php
@@ -1,8 +1,8 @@
safeLoad(Application::$configsDir . 'jwt.php')
diff --git a/src/Controller/ClassController.php b/src/Controller/ClassController.php
index 6a1570c..ee694e0 100644
--- a/src/Controller/ClassController.php
+++ b/src/Controller/ClassController.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace PhpSlides\Src\Controller;
+namespace PhpSlides\Core\Controller;
use PhpSlides\Exception;
@@ -23,22 +23,25 @@ class ClassController extends Controller
* @return mixed From class methods and __invoke function
*/
- protected static function __class(
- object|string $class,
- string $method,
- array|null $param = null,
+ protected static function __class (
+ object|string $class,
+ string $method,
+ array|null $param = null,
) {
- if (class_exists($class)) {
+ if (class_exists($class))
+ {
$instance = new $class();
$class_info = [
- 'method' => $method,
- 'class_name' => $class,
- 'class_methods' => get_class_methods($instance),
+ 'method' => $method,
+ 'class_name' => $class,
+ 'class_methods' => get_class_methods($instance),
];
return self::class_info($class_info, $param);
- } else {
+ }
+ else
+ {
throw new Exception("No controller class found as - $class", 1);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Controller/Controller.php b/src/Controller/Controller.php
index f1d78b3..81eb77a 100644
--- a/src/Controller/Controller.php
+++ b/src/Controller/Controller.php
@@ -1,6 +1,6 @@
$method(new Request($param));
- } elseif (
- count($class_methods) - 1 === $i &&
- $method !== $class_methods
- ) {
+ }
+ elseif (
+ count($class_methods) - 1 === $i &&
+ $method !== $class_methods
+ )
+ {
throw new Exception(
- "No controller method found as '$method'. Try using __invoke method.",
- 1,
+ "No controller method found as '$method'. Try using __invoke method.",
+ 1,
);
}
}
diff --git a/src/Database/Connection.php b/src/Database/Connection.php
index 2383204..e5da4f9 100644
--- a/src/Database/Connection.php
+++ b/src/Database/Connection.php
@@ -1,6 +1,6 @@
parse(get_called_class());
-
- // Assign the parsed table name to the static property $_tablename
- static::$_tablename = $parsed;
- }
-}
\ No newline at end of file
diff --git a/src/Database/Forgery.php b/src/Database/Forgery.php
new file mode 100644
index 0000000..328d84f
--- /dev/null
+++ b/src/Database/Forgery.php
@@ -0,0 +1,60 @@
+parse(get_called_class());
+
+ // Assign the parsed table name to the static property $_tablename
+ static::$_tablename = $parsed;
+ }
+}
diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php
index 10a37ef..45fc0a2 100644
--- a/src/Exception/Exception.php
+++ b/src/Exception/Exception.php
@@ -2,11 +2,10 @@
namespace PhpSlides;
-use PhpSlides\Src\Loader\FileLoader;
+use PhpSlides\Core\Loader\FileLoader;
use Exception as DefaultException;
use PhpSlides\Interface\SlidesException;
-
/**
* The Exception class provides enhanced exception handling for the PhpSlides application.
*/
@@ -50,38 +49,34 @@ public function filterStackTrace(): array
* This filter removes all file paths that come from the vendor folders.
*/
- /*
- $majorFilter = array_filter($this->getTrace(), function ($item) {
- $ss = strpos($item['file'], '/vendor/') === false;
- $sss = strpos($item['file'], '\vendor\\') === false;
+
+ $majorFilter = array_filter($this->getTrace(), function ($item) {
+ $ss = strpos($item['file'], '/vendor/') === false;
+ $sss = strpos($item['file'], '\vendor\\') === false;
- return $ss && $sss === true;
- });
- */
+ return $ss && $sss === true;
+ });
+
/**
* This filter adds only file paths from the vendor folders.
*/
- /*
- $minorFilter = array_filter($this->getTrace(), function ($item) {
- $ss = strpos($item['file'], '/vendor/') !== false;
- $sss = strpos($item['file'], '\vendor\\') !== false;
+ $minorFilter = array_filter($this->getTrace(), function ($item) {
+ $ss = strpos($item['file'], '/vendor/') !== false;
+ $sss = strpos($item['file'], '\vendor\\') !== false;
- return $ss || $sss === true;
- });
- */
+ return $ss || $sss === true;
+ });
/**
* Create a new array and merge them together.
* Major filters first, then the minor filters.
*/
- /*
- $majorFilterValue = array_values($majorFilter);
- $minorFilterValue = array_values($minorFilter);
- $newFilter = array_merge($majorFilterValue, $minorFilterValue);
- */
+ $majorFilterValue = array_values($majorFilter);
+ $minorFilterValue = array_values($minorFilter);
+ $newFilter = array_merge($majorFilterValue, $minorFilterValue);
/**
* Replace generated views files to the corresponding view
@@ -91,7 +86,7 @@ public function filterStackTrace(): array
$item['file'] = str_replace('.g.psl', '.psl', $item['file']);
return $item;
- }, $this->getTrace());
+ }, $newFilter);
return $newFilter;
}
diff --git a/src/Exception/template/index.php b/src/Exception/template/index.php
index a4801db..3caed81 100644
--- a/src/Exception/template/index.php
+++ b/src/Exception/template/index.php
@@ -1,7 +1,7 @@
- Parse Error
+ Uncaught Exception
Source File »
-
@@ -134,80 +138,84 @@
Call Stack »
- $value)
- {
- $key = $key + 1;
- $_file = $value['file'] ?? 'Unknown';
- $_line = $value['line'] ?? 1;
- echo "$key. {$_file}:{$_line}";
+ $value) {
+ $key = $key + 1;
+ $_file =
+ ltrim(
+ $value['file'] ?? 'Anonymous',
+ \PhpSlides\Core\Foundation\Application::$basePath,
+ ) ?? 'Unknown';
+ $_line = $value['line'] ?? 1;
+ echo "$key. {$_file}:{$_line}";
} ?>
-
+
diff --git a/src/Forgery/Database.php b/src/Forgery/Database.php
index c0ecbda..0039bfe 100644
--- a/src/Forgery/Database.php
+++ b/src/Forgery/Database.php
@@ -1,11 +1,11 @@
getMessage()}",
+ 'ERROR',
+ "Unable to create Database `$db_name`. [Exception]: {$e->getMessage()}",
);
}
}
@@ -60,23 +64,25 @@ protected static function createDB($db_name)
*
* @param string $db_name The name of the database to be dropped.
*/
- protected static function dropDB($db_name)
+ protected static function dropDB ($db_name)
{
- try {
+ try
+ {
// Initialize database connection
Connection::init();
// Check if the database exists
$query = DB::query(
- 'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME=%s',
- $db_name,
+ 'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME=%s',
+ $db_name,
);
// If the database does not exist, log a warning
- if (empty($query)) {
+ if (empty($query))
+ {
static::log(
- 'WARNING',
- "Cannot drop unexisting database `$db_name`",
+ 'WARNING',
+ "Cannot drop unexisting database `$db_name`",
);
return;
}
@@ -84,11 +90,13 @@ protected static function dropDB($db_name)
// Drop the database
DB::query('DROP DATABASE %b', $db_name);
static::log('INFO', "Dropped Database `$db_name`.");
- } catch (\Exception $e) {
+ }
+ catch ( \Exception $e )
+ {
// Log any exceptions that occur during the database drop
static::log(
- 'ERROR',
- "Unable to drop Database `$db_name`. [Exception]: {$e->getMessage()}",
+ 'ERROR',
+ "Unable to drop Database `$db_name`. [Exception]: {$e->getMessage()}",
);
}
}
@@ -102,24 +110,26 @@ protected static function dropDB($db_name)
* @param string $db_name The name of the database containing the table.
* @param string $db_table The name of the table to be dropped.
*/
- protected static function dropTable($db_name, $db_table)
+ protected static function dropTable ($db_name, $db_table)
{
- try {
+ try
+ {
// Initialize database connection
Connection::init();
// Check if the table exists in the database
$query = DB::query(
- 'SELECT * FROM information_schema.tables WHERE table_schema=%s AND table_name=%s',
- $db_name,
- $db_table,
+ 'SELECT * FROM information_schema.tables WHERE table_schema=%s AND table_name=%s',
+ $db_name,
+ $db_table,
);
// If the table does not exist, log a warning
- if (empty($query)) {
+ if (empty($query))
+ {
static::log(
- 'WARNING',
- "Cannot drop unexisting table `$db_table` in `$db_name` Database",
+ 'WARNING',
+ "Cannot drop unexisting table `$db_table` in `$db_name` Database",
);
return;
}
@@ -127,14 +137,16 @@ protected static function dropTable($db_name, $db_table)
// Drop the table
DB::query('DROP TABLE %b.%b', $db_name, $db_table);
static::log(
- 'INFO',
- "Dropped Table `$db_table` in `$db_name` Database.",
+ 'INFO',
+ "Dropped Table `$db_table` in `$db_name` Database.",
);
- } catch (\Exception $e) {
+ }
+ catch ( \Exception $e )
+ {
// Log any exceptions that occur during the table drop
static::log(
- 'ERROR',
- "Unable to drop Table `$db_table` in `$db_name` Database. [Exception]: {$e->getMessage()}",
+ 'ERROR',
+ "Unable to drop Table `$db_table` in `$db_name` Database. [Exception]: {$e->getMessage()}",
);
}
}
diff --git a/src/Forgery/Forge.php b/src/Forgery/Forge.php
index 4fef47b..e66a0da 100644
--- a/src/Forgery/Forge.php
+++ b/src/Forgery/Forge.php
@@ -1,10 +1,10 @@
null,
- 'UNIQUE' => null,
- 'INDEX' => null,
- 'FOREIGN' => null,
- 'REFERENCES' => null,
- 'DELETE' => null,
- 'UPDATE' => null,
- 'OTHERS' => null,
+ 'PRIMARY' => null,
+ 'UNIQUE' => null,
+ 'INDEX' => null,
+ 'FOREIGN' => null,
+ 'REFERENCES' => null,
+ 'DELETE' => null,
+ 'UPDATE' => null,
+ 'OTHERS' => null,
];
$db_columns = [];
- if ($table_already_exists) {
+ if ($table_already_exists)
+ {
$db_columns = array_keys(DB::columnList($table_name));
}
@@ -134,11 +143,10 @@ protected static function table($db_name)
* Filter the array, if the column already exists in the database
* then remove it from the array of columns that will be created.
*/
- $filePath = array_filter($filePath, function ($path) use (
- $table_already_exists,
- $db_columns,
- ) {
- if ($table_already_exists) {
+ $filePath = array_filter($filePath, function ($path) use ($table_already_exists, $db_columns, )
+ {
+ if ($table_already_exists)
+ {
$column_name = self::get_column_name($path);
return in_array($column_name, $db_columns) ? false : true;
}
@@ -148,7 +156,8 @@ protected static function table($db_name)
/**
* IF NO COLUMNS TO ADD, MOVE TO THE NEXT TABLE
*/
- if (empty($filePath)) {
+ if (empty($filePath))
+ {
continue;
}
@@ -157,81 +166,99 @@ protected static function table($db_name)
*/
$filePath = array_values($filePath);
- $columns = array_map(function ($file) {
- return [self::get_column_name($file), $file];
+ $columns = array_map(function ($file)
+ {
+ return [ self::get_column_name($file), $file ];
}, $filePath);
- $only_columns = array_map(function ($file) {
+ $only_columns = array_map(function ($file)
+ {
return self::get_column_name($file);
}, $filePath);
- for ($i = 0; $i < count($columns); $i++) {
+ for ($i = 0; $i < count($columns); $i++)
+ {
$res = (new SqlParser())->parse(
- column_name: $columns[$i][0],
- path: $columns[$i][1],
- constraint: $constraint,
- table_name: $table_name,
+ column_name: $columns[$i][0],
+ path: $columns[$i][1],
+ constraint: $constraint,
+ table_name: $table_name,
);
$query[] = $res[0];
$constraint = $res[1];
}
- if ($table_already_exists) {
- $query = array_map(function ($que) {
+ if ($table_already_exists)
+ {
+ $query = array_map(function ($que)
+ {
return "ADD COLUMN $que";
}, $query);
}
- if ($constraint['PRIMARY']) {
+ if ($constraint['PRIMARY'])
+ {
$key = implode(', ', (array) $constraint['PRIMARY']);
$query[] = $table_already_exists
- ? "ADD PRIMARY KEY ($key)"
- : "PRIMARY KEY ($key)";
+ ? "ADD PRIMARY KEY ($key)"
+ : "PRIMARY KEY ($key)";
}
- if ($constraint['INDEX']) {
+ if ($constraint['INDEX'])
+ {
$key = implode(', ', (array) $constraint['INDEX']);
- if ($constraint['UNIQUE']) {
+ if ($constraint['UNIQUE'])
+ {
$query[] = $table_already_exists
- ? "ADD UNIQUE INDEX ($key)"
- : "UNIQUE INDEX ($key)";
- } else {
+ ? "ADD UNIQUE INDEX ($key)"
+ : "UNIQUE INDEX ($key)";
+ }
+ else
+ {
$query[] = $table_already_exists
- ? "ADD INDEX ($key)"
- : "INDEX ($key)";
+ ? "ADD INDEX ($key)"
+ : "INDEX ($key)";
}
- } elseif ($constraint['UNIQUE']) {
+ }
+ elseif ($constraint['UNIQUE'])
+ {
$key = implode(', ', (array) $constraint['UNIQUE']);
$query[] = $table_already_exists
- ? "ADD UNIQUE ($key)"
- : "UNIQUE ($key)";
+ ? "ADD UNIQUE ($key)"
+ : "UNIQUE ($key)";
}
- if ($constraint['OTHERS']) {
+ if ($constraint['OTHERS'])
+ {
$key = $table_already_exists
- ? 'ADD ' . implode(', ', (array) $constraint['OTHERS'])
- : implode(', ', (array) $constraint['OTHERS']);
+ ? 'ADD ' . implode(', ', (array) $constraint['OTHERS'])
+ : implode(', ', (array) $constraint['OTHERS']);
$query[] = (string) $key;
}
- if ($constraint['FOREIGN']) {
- foreach ((array) $constraint['FOREIGN'] as $key) {
+ if ($constraint['FOREIGN'])
+ {
+ foreach ((array) $constraint['FOREIGN'] as $key)
+ {
$que = $table_already_exists
- ? "ADD FOREIGN KEY ($key)"
- : "FOREIGN KEY ($key)";
+ ? "ADD FOREIGN KEY ($key)"
+ : "FOREIGN KEY ($key)";
- if (isset($constraint['REFERENCES'][$key])) {
+ if (isset($constraint['REFERENCES'][$key]))
+ {
$value = $constraint['REFERENCES'][$key];
$que .= " REFERENCES $value";
}
- if (isset($constraint['UPDATE'][$key])) {
+ if (isset($constraint['UPDATE'][$key]))
+ {
$value = $constraint['UPDATE'][$key];
$que .= " ON UPDATE $value";
}
- if (isset($constraint['DELETE'][$key])) {
+ if (isset($constraint['DELETE'][$key]))
+ {
$value = $constraint['DELETE'][$key];
$que .= " ON DELETE $value";
}
@@ -245,24 +272,29 @@ protected static function table($db_name)
/**
* IF TABLE ALREADY EXISTS THEN IT'LL UPDATE THE COLUMNS
*/
- if ($table_already_exists) {
+ if ($table_already_exists)
+ {
DB::query('ALTER TABLE %b %l', $table_name, $query);
static::log(
- 'INFO',
- "Altered Table `$table_name` and adds column `$only_columns`",
+ 'INFO',
+ "Altered Table `$table_name` and adds column `$only_columns`",
);
- } else {
+ }
+ else
+ {
DB::query('CREATE TABLE %b (%l)', $table_name, $query);
static::log(
- 'INFO',
- "Created Table `$table_name` in `$db_name` Database",
+ 'INFO',
+ "Created Table `$table_name` in `$db_name` Database",
);
}
}
- } catch (\Exception $e) {
+ }
+ catch ( \Exception $e )
+ {
static::log(
- 'ERROR',
- "Unable to create Table `$table_name` in `$db_name` Database. [Exception]: {$e->getMessage()}",
+ 'ERROR',
+ "Unable to create Table `$table_name` in `$db_name` Database. [Exception]: {$e->getMessage()}",
);
return;
}
@@ -275,7 +307,7 @@ protected static function table($db_name)
* @param string $name The name to format
* @return string The replced name
*/
- protected static function format(string $name): string
+ protected static function format (string $name): string
{
// Convert the variable to the desired format
return strtolower(preg_replace('/(?column_types;
$definition = "`{$column['COLUMN_NAME']}` ";
- if ($column['TYPE']) {
+ if ($column['TYPE'])
+ {
$definition .= $column['TYPE'];
- if ($column['LENGTH']) {
+ if ($column['LENGTH'])
+ {
$definition .= "({$column['LENGTH']})";
}
}
- if ($column['UNSIGNED'] == 'TRUE') {
+ if ($column['UNSIGNED'] == 'TRUE')
+ {
$definition .= ' UNSIGNED';
}
- if ($column['ZEROFILL'] == 'TRUE') {
+ if ($column['ZEROFILL'] == 'TRUE')
+ {
$definition .= ' ZEROFILL';
}
- if ($column['CHARACTER']) {
+ if ($column['CHARACTER'])
+ {
$definition .= " CHARACTER SET {$this->trimQuote(
- $column['CHARACTER'],
+ $column['CHARACTER'],
)}";
}
- if ($column['COLLATION']) {
+ if ($column['COLLATION'])
+ {
$definition .= " COLLATE {$column['COLLATION']}";
}
- if ($column['NULL'] == 'FALSE' || $column['NULL'] === null) {
+ if ($column['NULL'] == 'FALSE' || $column['NULL'] === null)
+ {
$definition .= ' NOT NULL';
- } elseif ($column['NULL'] == 'TRUE') {
+ }
+ elseif ($column['NULL'] == 'TRUE')
+ {
$definition .= ' NULL';
}
- if ($column['DEFAULT'] !== null) {
- $types = ['NULL', '0', 'TRUE', 'FALSE', 'CURRENT_TIMESTAMP'];
+ if ($column['DEFAULT'] !== null)
+ {
+ $types = [ 'NULL', '0', 'TRUE', 'FALSE', 'CURRENT_TIMESTAMP' ];
if (
- in_array($column['DEFAULT'], $types) ||
- is_numeric($column['DEFAULT'])
- ) {
+ in_array($column['DEFAULT'], $types) ||
+ is_numeric($column['DEFAULT'])
+ )
+ {
$definition .= " DEFAULT {$column['DEFAULT']}";
- } else {
+ }
+ else
+ {
$definition .= " DEFAULT '{$this->trimQuote($column['DEFAULT'])}'";
}
}
- if ($column['AUTO_INCREMENT'] == 'TRUE') {
+ if ($column['AUTO_INCREMENT'] == 'TRUE')
+ {
$definition .= ' AUTO_INCREMENT';
}
- if ($column['UNIQUE'] == 'TRUE') {
+ if ($column['UNIQUE'] == 'TRUE')
+ {
$constraint['UNIQUE'][] = $column['COLUMN_NAME'];
}
- if ($column['INDEX'] == 'TRUE') {
+ if ($column['INDEX'] == 'TRUE')
+ {
$constraint['INDEX'][] = $column['COLUMN_NAME'];
}
- if ($column['PRIMARY'] == 'TRUE') {
+ if ($column['PRIMARY'] == 'TRUE')
+ {
$constraint['PRIMARY'][] = $column['COLUMN_NAME'];
}
- if ($column['CHECK']) {
+ if ($column['CHECK'])
+ {
$definition .= " CHECK ({$column['CHECK']})";
}
- if ($column['FOREIGN'] == true) {
+ if ($column['FOREIGN'] == true)
+ {
$constraint['FOREIGN'][] = $column['COLUMN_NAME'];
}
- if ($column['REFERENCES']) {
+ if ($column['REFERENCES'])
+ {
$constraint['REFERENCES'][$column['COLUMN_NAME']] =
- $column['REFERENCES'];
+ $column['REFERENCES'];
}
- if ($column['DELETE']) {
+ if ($column['DELETE'])
+ {
$constraint['DELETE'][$column['COLUMN_NAME']] = $column['DELETE'];
}
- if ($column['UPDATE']) {
- if ($column['FOREIGN']) {
+ if ($column['UPDATE'])
+ {
+ if ($column['FOREIGN'])
+ {
$constraint['UPDATE'][$column['COLUMN_NAME']] = $column['UPDATE'];
- } else {
+ }
+ else
+ {
$definition .= " ON UPDATE {$column['UPDATE']}";
}
}
- if ($column['COMMENT']) {
+ if ($column['COMMENT'])
+ {
$definition .= " COMMENT '{$this->trimQuote($column['COMMENT'])}'";
}
- if ($column['VISIBLE'] !== null) {
+ if ($column['VISIBLE'] !== null)
+ {
$definition .= ' ' . ($column['VISIBLE'] ? 'VISIBLE' : 'INVISIBLE');
}
- if ($column['STORAGE']) {
+ if ($column['STORAGE'])
+ {
$definition .= " STORAGE {$column['STORAGE']}";
}
- if ($column['GENERATED']) {
+ if ($column['GENERATED'])
+ {
$definition .= " GENERATED ALWAYS AS ({$column['GENERATED']})";
}
- if ($column['VIRTUAL']) {
+ if ($column['VIRTUAL'])
+ {
$definition .= ' VIRTUAL';
}
- if ($column['PERSISTENT']) {
+ if ($column['PERSISTENT'])
+ {
$definition .= ' PERSISTENT';
}
- if ($column['OTHERS']) {
+ if ($column['OTHERS'])
+ {
$constraint['OTHERS'][] = $column['OTHERS'];
}
- return [trim($definition), $constraint];
+ return [ trim($definition), $constraint ];
}
}
diff --git a/src/Formatter/ViewFormatter.php b/src/Formatter/ViewFormatter.php
index df85f33..48cf017 100644
--- a/src/Formatter/ViewFormatter.php
+++ b/src/Formatter/ViewFormatter.php
@@ -1,13 +1,13 @@
* @copyright 2024 Dave Conco
*/
@@ -44,11 +44,11 @@ public function __construct(string $contents)
$this->contents = $contents;
// Apply various formatting operations
+ $this->psl_tags();
+ $this->bracket_interpolation();
$this->includes();
$this->hot_reload();
$this->import_quotes();
- $this->bracket_interpolation();
- $this->psl_tags();
}
/**
diff --git a/src/Formatter/Views/FormatBracketInterpolation.php b/src/Formatter/Views/FormatBracketInterpolation.php
index cd9aab0..def3337 100644
--- a/src/Formatter/Views/FormatBracketInterpolation.php
+++ b/src/Formatter/Views/FormatBracketInterpolation.php
@@ -1,6 +1,6 @@
contents` property with the modified content.
*/
- protected function bracket_interpolation()
+ protected function bracket_interpolation ()
{
// Replace bracket interpolation {{! ... !}}
$formattedContents = preg_replace(
- '/\{\{!\s*.*?\s*!\}\}/s',
- '',
- $this->contents,
+ '/\{\{!\s*.*?\s*!\}\}/s',
+ '',
+ $this->contents,
);
// Replace bracket interpolation {{ ... }}
$formattedContents = preg_replace_callback(
- '/\{\{\s*(.*?)\s*\}\}/s',
- function ($matches) {
- $val = trim($matches[1], ';');
- return '<' . '?php print_r(' . $val . '); ?' . '>';
- },
- $formattedContents,
+ '/\{\{\s*(.*?)\s*\}\}/s',
+ function ($matches)
+ {
+ $val = trim($matches[1], ';');
+ return '<' . '?php print_r(' . $val . '); ?' . '>';
+ },
+ $formattedContents,
);
$this->contents = $formattedContents;
diff --git a/src/Formatter/Views/FormatHotReload.php b/src/Formatter/Views/FormatHotReload.php
index 0f6ead6..6b347a5 100644
--- a/src/Formatter/Views/FormatHotReload.php
+++ b/src/Formatter/Views/FormatHotReload.php
@@ -1,8 +1,8 @@
$value)
diff --git a/src/Foundation/Application.php b/src/Foundation/Application.php
index 1e8941e..d984f48 100644
--- a/src/Foundation/Application.php
+++ b/src/Foundation/Application.php
@@ -1,22 +1,21 @@
isHttps() ? 'https://' : 'http://';
@@ -191,7 +197,7 @@ public function create (): void
}
catch ( \Exception $e )
{
- Database::$_connect_error = $e->getMessage();
+ Forgery::$_connect_error = $e->getMessage();
goto EXECUTION;
}
new Forge();
diff --git a/src/Foundation/Configuration.php b/src/Foundation/Configuration.php
index 13409c2..ad1f94f 100644
--- a/src/Foundation/Configuration.php
+++ b/src/Foundation/Configuration.php
@@ -1,13 +1,13 @@
__route();
}
@@ -100,10 +111,10 @@ public static function ApiRoute()
* Placeholder function for handling form routes.
* Currently, the implementation for form routes is not defined.
*/
- public static function FormsRoute()
+ public static function FormRoute()
{
self::Load();
- $reg_route = $GLOBALS['__registered_forms_routes'] ?? null;
+ $reg_route = $GLOBALS['__registered_form_routes'] ?? null;
// Future form handling can be implemented here.
}
diff --git a/src/Globals/Functions.php b/src/Globals/Functions.php
index 801ef29..330e69f 100644
--- a/src/Globals/Functions.php
+++ b/src/Globals/Functions.php
@@ -2,9 +2,10 @@
use PhpSlides\Exception;
use PhpSlides\Router\Route;
-use PhpSlides\Src\Loader\FileLoader;
-use PhpSlides\Src\Loader\ViewLoader;
-use PhpSlides\Src\Foundation\Application;
+use PhpSlides\Core\Loader\FileLoader;
+use PhpSlides\Core\Loader\ViewLoader;
+use PhpSlides\Core\Traits\FileHandler;
+use PhpSlides\Core\Foundation\Application;
/**
* Sets an environment variable '__DIR__' with the base path of the application.
@@ -217,7 +218,7 @@ function route(
function asset(string $filename, string $path_type = RELATIVE_PATH): string
{
$filename = preg_replace('/(::)|::/', '/', $filename);
- $filename = strtolower(trim($filename, '\/\/'));
+ $filename = trim($filename, '\/\/');
switch (php_sapi_name()) {
case 'cli-server':
@@ -269,7 +270,7 @@ function import(string $file)
throw new Exception("File does not exist: $file");
}
- $file_type = Route::file_type($file);
+ $file_type = FileHandler::file_type($file);
$contents = base64_encode(file_get_contents($file));
$data = "data:$file_type;base64,$contents";
@@ -331,7 +332,7 @@ function payload(
function Props(?string $name = null)
{
if ($name === null) {
- $allProperties = \PhpSlides\Props::all();
+ $allProperties = \PhpSlides\Core\Props::all();
$filteredProperties = [];
foreach ($allProperties as $key => $value) {
@@ -352,7 +353,7 @@ function Props(?string $name = null)
$name = "_$name";
}
- return (new \PhpSlides\Src\Props())->$name;
+ return (new \PhpSlides\Core\Props())->$name;
}
function ExceptionHandler(Throwable $exception)
diff --git a/src/Http/Api.php b/src/Http/Api.php
index b566d3c..326b581 100644
--- a/src/Http/Api.php
+++ b/src/Http/Api.php
@@ -1,10 +1,11 @@
define;
// checks if $define is set, then assign $define methods to $url & $controller parameters
$url =
- $define !== null
- ? rtrim($define['url'], '/') . '/' . trim($url, '/')
- : trim($url, '/');
- $url = trim($url, '/');
+ $define !== null
+ ? trim($define['url'], '/') . '/' . trim($url, '/')
+ : trim($url, '/');
- $uri = strtolower(self::$BASE_URL . self::$version . '/' . $url);
+ $uri = $this->base_url . self::$version . '/' . $url;
self::$regRoute[] = $uri;
$route = [
- 'url' => $uri,
- 'guards' => $this->guards ?? null,
- 'r_method' => $req_method,
- 'controller' =>
- $define['controller'] ??
- (is_array($controller) ? $controller[0] : $controller),
+ 'url' => $uri,
+ 'guards' => $this->guards ?? null,
+ 'r_method' => $req_method,
+ 'controller' =>
+ $define['controller'] ??
+ (is_array($controller) ? $controller[0] : $controller),
];
- if ($define !== null && $controller !== null) {
+ if ($define !== null && $controller !== null)
+ {
$route['c_method'] = trim($controller, '@');
}
- if (is_array($controller)) {
+ if (is_array($controller))
+ {
$route['c_method'] = $controller[1];
}
@@ -133,12 +144,32 @@ public function route(
* @param ?string ...$guards String parameters of registered guards.
* @return self
*/
- public function withGuard(?string ...$guards): self
+ public function withGuard (?string ...$guards): self
{
$this->guards = empty($guards) ? null : $guards;
return $this;
}
+ public function prefix (?string $url = '/api/'): self
+ {
+ $this->base_url = $url;
+ return $this;
+ }
+
+ public function caseSensitive (): self
+ {
+ $route = is_array(self::$regRoute) ? self::$regRoute[0] : self::$regRoute;
+ $GLOBALS['__registered_api_routes'][$route]['caseSensitive'] = true;
+ return $this;
+ }
+
+ public function handleInvalidParameterType (Closure $closure): self
+ {
+ $route = is_array(self::$regRoute) ? self::$regRoute[0] : self::$regRoute;
+ $GLOBALS['__registered_api_routes'][$route]['handleInvalidParameterType'] = $closure;
+ return $this;
+ }
+
/**
* Defines a base URL and controller for subsequent route mappings.
*
@@ -146,11 +177,11 @@ public function withGuard(?string ...$guards): self
* @param string $controller The controller handling the routes.
* @return self
*/
- public function define(string $url, string $controller): self
+ public function define (string $url, string $controller): self
{
$this->define = [
- 'url' => $url,
- 'controller' => $controller,
+ 'url' => $url,
+ 'controller' => $controller,
];
return $this;
@@ -162,32 +193,33 @@ public function define(string $url, string $controller): self
* @param array An associative array where the key is the route and the value is an array with the HTTP method and controller method.
* @return self
*/
- public function map(array $rest_url): self
+ public function map (array $rest_url): self
{
$define = $this->define;
- if ($define !== null) {
+ if ($define !== null)
+ {
/**
* Get the map value, keys as the route url
*/
$routes = array_keys($rest_url);
- $base = strtolower(
- self::$BASE_URL .
- self::$version .
- '/' .
- trim($define['url'], '/') .
- '/',
- );
+ $base =
+ $this->base_url .
+ self::$version .
+ '/' .
+ trim($define['url'], '/') .
+ '/';
/**
* Map route url array to the full base url
*/
$full_url = array_map(
- fn($route) => $base . ltrim($route, '/'),
- $routes,
+ fn ($route) => $base . ltrim($route, '/'),
+ $routes,
);
- $rest_url = array_map(function ($uri) {
+ $rest_url = array_map(function ($uri)
+ {
$uri[] = $this->guards ?? null;
return $uri;
}, $rest_url);
@@ -213,12 +245,18 @@ public function map(array $rest_url): self
*
* @return self
*/
- public static function v1(): self
+ public static function v1 (): self
{
return self::__callStatic('v1', 0);
}
- public static function v1_0(): self
+ /**
+ * Define an API route for version 1.0
+ * Also in use for defining urls
+ *
+ * @return self
+ */
+ public static function v1_0 (): self
{
return self::__callStatic('v1_0', 0);
}
diff --git a/src/Http/ApiController.php b/src/Http/ApiController.php
index 96beee9..e70f44e 100644
--- a/src/Http/ApiController.php
+++ b/src/Http/ApiController.php
@@ -1,6 +1,6 @@
param = $urlParam;
}
@@ -43,10 +43,9 @@ public function __construct (?array $urlParam = null)
* @param ?string $key If specified, retrieves the value of the given parameter key.
* @return mixed The URL parameters or a specific parameter value.
*/
- public function urlParam (?string $key = null)
+ public function urlParam(?string $key = null)
{
- if (!$key)
- {
+ if (!$key) {
return (object) $this->validate($this->param);
}
return $this->validate($this->param[$key]);
@@ -61,31 +60,26 @@ public function urlParam (?string $key = null)
* @param ?string $name If specified, returns a specific query parameter by name.
* @return mixed parsed query parameters or a specific parameter value.
*/
- public function urlQuery (?string $name = null)
+ public function urlQuery(?string $name = null)
{
- if (php_sapi_name() == 'cli-server')
- {
+ if (php_sapi_name() == 'cli-server') {
$parsed = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
- }
- else
- {
+ } else {
$parsed = parse_url(
- $_REQUEST['uri'] ?? $_SERVER['REQUEST_URI'],
- PHP_URL_QUERY,
+ $_REQUEST['uri'] ?? $_SERVER['REQUEST_URI'],
+ PHP_URL_QUERY,
);
}
$cl = new stdClass();
- if (!$parsed)
- {
+ if (!$parsed) {
return $cl;
}
$parsed = mb_split('&', urldecode($parsed));
$i = 0;
- while ($i < count($parsed))
- {
+ while ($i < count($parsed)) {
$p = mb_split('=', $parsed[$i]);
$key = $p[0];
$value = $p[1] ? $this->validate($p[1]) : null;
@@ -94,8 +88,7 @@ public function urlQuery (?string $name = null)
$i++;
}
- if (!$name)
- {
+ if (!$name) {
return $cl;
}
return $cl->$name;
@@ -110,20 +103,16 @@ public function urlQuery (?string $name = null)
* @param ?string $name The header name to retrieve. If omitted, returns all headers.
* @return mixed The header, or a specific header value if `$name` is provided.
*/
- public function header (?string $name = null)
+ public function header(?string $name = null)
{
$headers = getallheaders() ?: apache_request_headers();
- if (!$name)
- {
+ if (!$name) {
return $this->validate($headers);
}
- if (isset($headers[$name]))
- {
+ if (isset($headers[$name])) {
return $this->validate($headers[$name]);
- }
- else
- {
+ } else {
return null;
}
}
@@ -136,7 +125,7 @@ public function header (?string $name = null)
*
* @return stdClass The authentication credentials.
*/
- public function auth (): stdClass
+ public function auth(): stdClass
{
$cl = new stdClass();
$cl->basic = self::BasicAuthCredentials();
@@ -151,7 +140,7 @@ public function auth (): stdClass
* @param string $key The name of the header containing the API key. Default is 'Api-Key'.
* @return bool Returns true if the API key is valid, false otherwise.
*/
- public function apiKey (string $key = 'Api-Key')
+ public function apiKey(string $key = 'Api-Key')
{
return $this->validate(self::RequestApiKey($key));
}
@@ -165,17 +154,15 @@ public function apiKey (string $key = 'Api-Key')
* @param ?string $name The name of the body parameter to retrieve.
* @return mixed The body data or null if parsing fails.
*/
- public function body (?string $name = null)
+ public function body(?string $name = null)
{
$data = json_decode(file_get_contents('php://input'), true);
- if ($data === null || json_last_error() !== JSON_ERROR_NONE)
- {
+ if ($data === null || json_last_error() !== JSON_ERROR_NONE) {
return null;
}
- if ($name !== null)
- {
+ if ($name !== null) {
return $this->validate($data[$name]);
}
return $this->validate($data);
@@ -190,14 +177,12 @@ public function body (?string $name = null)
* @param ?string $key The key of the GET parameter.
* @return mixed The parameter value, or null if not set.
*/
- public function get (?string $key = null)
+ public function get(?string $key = null)
{
- if (!$key)
- {
+ if (!$key) {
return $this->validate($_GET);
}
- if (!isset($_GET[$key]))
- {
+ if (!isset($_GET[$key])) {
return null;
}
return $this->validate($_GET[$key]);
@@ -212,14 +197,12 @@ public function get (?string $key = null)
* @param ?string $key The key of the POST parameter.
* @return mixed The parameter value, or null if not set.
*/
- public function post (?string $key = null)
+ public function post(?string $key = null)
{
- if (!$key)
- {
+ if (!$key) {
return $this->validate($_POST);
}
- if (!isset($_POST[$key]))
- {
+ if (!isset($_POST[$key])) {
return null;
}
@@ -236,14 +219,12 @@ public function post (?string $key = null)
* @param ?string $key The key of the request parameter.
* @return mixed The parameter value, or null if not set.
*/
- public function request (?string $key = null)
+ public function request(?string $key = null)
{
- if (!$key)
- {
+ if (!$key) {
return $this->validate($_REQUEST);
}
- if (!isset($_REQUEST[$key]))
- {
+ if (!isset($_REQUEST[$key])) {
return null;
}
@@ -260,18 +241,15 @@ public function request (?string $key = null)
* @param ?string $name The name of the file input.
* @return ?object File data, or null if not set.
*/
- public function files (?string $name = null): ?object
+ public function files(?string $name = null): ?object
{
- if (!$name)
- {
+ if (!$name) {
return (object) $_FILES;
}
- if (!isset($_FILES[$name]))
- {
+ if (!isset($_FILES[$name])) {
return null;
}
- if ($_FILES[$name]['error'] !== UPLOAD_ERR_OK)
- {
+ if ($_FILES[$name]['error'] !== UPLOAD_ERR_OK) {
return null;
}
@@ -287,10 +265,9 @@ public function files (?string $name = null): ?object
* @param ?string $key The key of the cookie.
* @return mixed The cookie value, or null if not set.
*/
- public function cookie (?string $key = null)
+ public function cookie(?string $key = null)
{
- if (!$key)
- {
+ if (!$key) {
return (object) $this->validate($_COOKIE);
}
return isset($_COOKIE[$key]) ? $this->validate($_COOKIE[$key]) : null;
@@ -305,14 +282,13 @@ public function cookie (?string $key = null)
* @param ?string $key The key of the session value.
* @return mixed The session value, or null if not set.
*/
- public function session (?string $key = null)
+ public function session(?string $key = null)
{
// Start the session if it's not already started
session_status() < 2 && session_start();
// If no key is provided, return all session data as an object
- if (!$key)
- {
+ if (!$key) {
return (object) $this->validate($_SESSION);
}
@@ -327,7 +303,7 @@ public function session (?string $key = null)
*
* @return string The HTTP method of the request.
*/
- public function method (): string
+ public function method(): string
{
return $_SERVER['REQUEST_METHOD'];
}
@@ -337,7 +313,7 @@ public function method (): string
*
* @return string The URI.
*/
- public function uri (): string
+ public function uri(): string
{
return self::$request_uri;
}
@@ -347,7 +323,7 @@ public function uri (): string
*
* @return object The parsed URL components.
*/
- public function url (): object
+ public function url(): object
{
$uri = $this->uri();
$parsed = parse_url($uri);
@@ -365,11 +341,10 @@ public function url (): object
*
* @return string The client's IP address.
*/
- public function ip (): string
+ public function ip(): string
{
// Check for forwarded IP addresses from proxies or load balancers
- if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
- {
+ if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
return $_SERVER['REMOTE_ADDR'];
@@ -382,7 +357,7 @@ public function ip (): string
*
* @return string The user agent.
*/
- public function userAgent (): string
+ public function userAgent(): string
{
return $_SERVER['HTTP_USER_AGENT'];
}
@@ -394,10 +369,10 @@ public function userAgent (): string
*
* @return bool Returns true if the request is an AJAX request, otherwise false.
*/
- public function isAjax (): bool
+ public function isAjax(): bool
{
return strtolower($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') ===
- 'xmlhttprequest';
+ 'xmlhttprequest';
}
/**
@@ -405,11 +380,11 @@ public function isAjax (): bool
*
* @return string|null The referrer URL, or null if not set.
*/
- public function referrer (): ?string
+ public function referrer(): ?string
{
return $_SERVER['HTTP_REFERER'] !== null
- ? $_SERVER['HTTP_REFERER']
- : null;
+ ? $_SERVER['HTTP_REFERER']
+ : null;
}
/**
@@ -417,7 +392,7 @@ public function referrer (): ?string
*
* @return string The server protocol.
*/
- public function protocol (): string
+ public function protocol(): string
{
return $_SERVER['SERVER_PROTOCOL'];
}
@@ -427,7 +402,7 @@ public function protocol (): string
*
* @return array The combined input data.
*/
- public function all (): array
+ public function all(): array
{
$data = array_merge($_GET, $_POST, $this->body() ?? []);
return $this->validate($data);
@@ -440,10 +415,9 @@ public function all (): array
* @param string $key The key of the server parameter.
* @return mixed The server parameter value, or null if not set.
*/
- public function server (?string $key = null)
+ public function server(?string $key = null)
{
- if (!$key)
- {
+ if (!$key) {
return $this->validate($_SERVER);
}
return isset($_SERVER[$key]) ? $this->validate($_SERVER[$key]) : null;
@@ -455,7 +429,7 @@ public function server (?string $key = null)
* @param string $method The HTTP method to check.
* @return bool True if the request method matches, false otherwise.
*/
- public function isMethod (string $method): bool
+ public function isMethod(string $method): bool
{
return strtoupper($this->method()) === strtoupper($method);
}
@@ -465,10 +439,10 @@ public function isMethod (string $method): bool
*
* @return bool True if the request is HTTPS, false otherwise.
*/
- public function isHttps (): bool
+ public function isHttps(): bool
{
return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
- $_SERVER['SERVER_PORT'] == 443;
+ $_SERVER['SERVER_PORT'] == 443;
}
/**
@@ -476,7 +450,7 @@ public function isHttps (): bool
*
* @return int The request time as a Unix timestamp.
*/
- public function requestTime (): int
+ public function requestTime(): int
{
return (int) $_SERVER['REQUEST_TIME'];
}
@@ -488,10 +462,10 @@ public function requestTime (): int
*
* @return string|null The content type, or null if not set.
*/
- public function contentType (): ?string
+ public function contentType(): ?string
{
return $this->header('Content-Type') ??
- ($_SERVER['CONTENT_TYPE'] ?? null);
+ ($_SERVER['CONTENT_TYPE'] ?? null);
}
/**
@@ -501,15 +475,17 @@ public function contentType (): ?string
*
* @return int|null The content length, or null if not set.
*/
- public function contentLength (): ?int
+ public function contentLength(): ?int
{
return isset($_SERVER['CONTENT_LENGTH'])
- ? (int) $_SERVER['CONTENT_LENGTH']
- : null;
+ ? (int) $_SERVER['CONTENT_LENGTH']
+ : null;
}
- public function csrf ()
+ public function csrf()
{
- return $this->header('X-CSRF-TOKEN') ?: $this->header('X-Csrf-Token');
+ return $this->header('X-CSRF-TOKEN') ?:
+ $this->header('X-Csrf-Token') ?:
+ $this->header('x-csrf-token');
}
}
diff --git a/src/Interface/ApplicationInterface.php b/src/Interface/ApplicationInterface.php
index 4277a61..aac9bf1 100644
--- a/src/Interface/ApplicationInterface.php
+++ b/src/Interface/ApplicationInterface.php
@@ -1,6 +1,6 @@
result[] = $result;
return $this;
- } else {
+ }
+ else
+ {
throw new Exception("File does not exist: $file");
}
}
@@ -47,9 +50,10 @@ public function load($file): self
* @param string $file The file path to load.
* @return self The instance for chaining.
*/
- public function safeLoad($file): self
+ public function safeLoad ($file): self
{
- if (file_exists($file)) {
+ if (file_exists($file))
+ {
$result = include $file;
$this->result[] = $result;
}
@@ -64,9 +68,10 @@ public function safeLoad($file): self
*
* @return mixed The content of the loaded file(s), either as a single result or an array.
*/
- public function getLoad()
+ public function getLoad ()
{
- if (count($this->result ?? []) === 1) {
+ if (count($this->result ?? []) === 1)
+ {
return $this->result[0];
}
return $this->result;
@@ -83,16 +88,19 @@ public function getLoad()
* @throws Exception if the specified file does not exist.
* @return self The instance for chaining.
*/
- public function parseLoad(string $file): self
+ public function parseLoad (string $file): self
{
- if (file_exists($file)) {
+ if (file_exists($file))
+ {
ob_start();
include $file;
$output = ob_get_clean();
$this->result[] =
- $output !== false && strlen($output ?? '') > 0 ? $output : '';
+ $output !== false && strlen($output ?? '') > 0 ? $output : '';
return $this;
- } else {
+ }
+ else
+ {
throw new Exception("File does not exist: $file");
}
}
@@ -106,14 +114,15 @@ public function parseLoad(string $file): self
* @param string $file The file path to parse.
* @return self The instance for chaining.
*/
- public function parseSafeLoad(string $file): self
+ public function parseSafeLoad (string $file): self
{
- if (file_exists($file)) {
+ if (file_exists($file))
+ {
ob_start();
include $file;
$output = ob_get_clean();
$this->result[] =
- $output !== false && strlen($output ?? '') > 0 ? $output : '';
+ $output !== false && strlen($output ?? '') > 0 ? $output : '';
}
return $this;
}
diff --git a/src/Loader/HotReload.php b/src/Loader/HotReload.php
index 6da0e23..62e5299 100644
--- a/src/Loader/HotReload.php
+++ b/src/Loader/HotReload.php
@@ -1,10 +1,10 @@
format($file_contents, ...$props);
- try {
+ try
+ {
// Write formatted contents to the generated file and parse it.
$file = fopen($gen_file, 'w');
fwrite($file, $file_contents);
@@ -86,9 +91,11 @@ public function safeLoad(string $viewFile, mixed ...$props): self
$this->result[] = $parsedLoad->getLoad();
unset($GLOBALS['__gen_file_path']);
- } finally {
+ }
+ finally
+ {
// Remove generated file and reset global file path.
- unlink($gen_file);
+ if (is_file($gen_file)) unlink($gen_file);
$GLOBALS['__gen_file_path'] = $viewFile;
}
}
@@ -104,9 +111,10 @@ public function safeLoad(string $viewFile, mixed ...$props): self
* @return mixed The content of the loaded view file(s), either as a single
* result or an array.
*/
- public function getLoad()
+ public function getLoad ()
{
- if (count($this->result ?? []) === 1) {
+ if (count($this->result ?? []) === 1)
+ {
return $this->result[0];
}
return $this->result;
@@ -119,7 +127,7 @@ public function getLoad()
* @param mixed ...$props Properties to apply within the view file.
* @return string The formatted view file content.
*/
- private function format(string $contents, mixed ...$props)
+ private function format (string $contents, mixed ...$props)
{
return (new ViewFormatter($contents))->resolve(...$props);
}
diff --git a/src/Logger/DBLogger.php b/src/Logger/DBLogger.php
index b685c48..da009d5 100644
--- a/src/Logger/DBLogger.php
+++ b/src/Logger/DBLogger.php
@@ -1,9 +1,9 @@
null,
- 'TYPE' => null,
- 'LENGTH' => null,
- 'UNSIGNED' => null,
- 'ZEROFILL' => null,
- 'CHARACTER' => null,
- 'COLLATION' => null,
- 'NULL' => null,
- 'DEFAULT' => null,
- 'AUTO_INCREMENT' => null,
- 'UNIQUE' => null,
- 'PRIMARY' => null,
- 'INDEX' => null,
- 'CHECK' => null,
- 'FOREIGN' => null,
- 'REFERENCES' => null,
- 'DELETE' => null,
- 'UPDATE' => null,
- 'COMMENT' => null,
- 'VISIBLE' => null,
- 'STORAGE' => null,
- 'GENERATED' => null,
- 'VIRTUAL' => null,
- 'PERSISTENT' => null,
- 'OTHERS' => null,
+ 'COLUMN_NAME' => null,
+ 'TYPE' => null,
+ 'LENGTH' => null,
+ 'UNSIGNED' => null,
+ 'ZEROFILL' => null,
+ 'CHARACTER' => null,
+ 'COLLATION' => null,
+ 'NULL' => null,
+ 'DEFAULT' => null,
+ 'AUTO_INCREMENT' => null,
+ 'UNIQUE' => null,
+ 'PRIMARY' => null,
+ 'INDEX' => null,
+ 'CHECK' => null,
+ 'FOREIGN' => null,
+ 'REFERENCES' => null,
+ 'DELETE' => null,
+ 'UPDATE' => null,
+ 'COMMENT' => null,
+ 'VISIBLE' => null,
+ 'STORAGE' => null,
+ 'GENERATED' => null,
+ 'VIRTUAL' => null,
+ 'PERSISTENT' => null,
+ 'OTHERS' => null,
];
/**
@@ -70,17 +70,19 @@ class SqlParser extends SqlFormat
*
* @return string The formatted SQL constraint for the column.
*/
- public function parse(
- string $column_name,
- string $path,
- array $constraint,
- ?string $table_name,
+ public function parse (
+ string $column_name,
+ string $path,
+ array $constraint,
+ ?string $table_name,
) {
$code = file($path);
$this->column_types['COLUMN_NAME'] = $column_name;
- foreach ($code as $value) {
- if (str_starts_with(trim($value), '#')) {
+ foreach ($code as $value)
+ {
+ if (str_starts_with(trim($value), '#'))
+ {
continue;
}
@@ -91,12 +93,15 @@ public function parse(
$value = str_replace('__table__', $table_name, $value);
$value = str_replace('__column__', $column_name, $value);
- if (array_key_exists($type, $this->column_types)) {
+ if (array_key_exists($type, $this->column_types))
+ {
$this->column_types[$type] = $value;
- } else {
+ }
+ else
+ {
self::log(
- 'WARNING',
- "`$type` key does not exist in `$column_name` column type",
+ 'WARNING',
+ "`$type` key does not exist in `$column_name` column type",
);
}
}
diff --git a/src/Props.php b/src/Props.php
index 098f938..4334a9e 100644
--- a/src/Props.php
+++ b/src/Props.php
@@ -1,6 +1,6 @@
An associative array containing all the properties and their values.
*/
- public static function all(): array
+ public static function all (): array
{
return static::$properties;
}
-}
+}
\ No newline at end of file
diff --git a/src/Traits/FileHandler.php b/src/Traits/FileHandler.php
index 61b9a06..c6d3fce 100644
--- a/src/Traits/FileHandler.php
+++ b/src/Traits/FileHandler.php
@@ -1,9 +1,9 @@
match(
- self::$route['r_method'] ?? '*',
- self::$route['url'] ?? '',
+ self::$route['r_method'] ?? '*',
+ self::$route['url'] ?? '',
);
- if (self::$map_info) {
+ if (self::$map_info)
+ {
$this->__api_guards(self::$route['guards'] ?? null);
print_r($this->__routeSelection());
@@ -32,7 +33,7 @@ protected function __route(): void
}
}
- protected function __routeSelection(?Request $request = null)
+ protected function __routeSelection (?Request $request = null)
{
$info = self::$map_info;
$route = self::$route ?? self::$apiMap;
@@ -40,16 +41,18 @@ protected function __routeSelection(?Request $request = null)
$method = $_SERVER['REQUEST_METHOD'];
$controller = $route['controller'] ?? '';
- if (!class_exists($controller)) {
+ if (!class_exists($controller))
+ {
throw new Exception(
- "Api controller class `$controller` does not exist.",
+ "Api controller class `$controller` does not exist.",
);
}
$params = $info['params'] ?? null;
- if (!class_exists($controller)) {
+ if (!class_exists($controller))
+ {
throw new Exception(
- "Api controller class does not exist: `$controller`",
+ "Api controller class does not exist: `$controller`",
);
}
$cc = new $controller();
@@ -57,12 +60,14 @@ protected function __routeSelection(?Request $request = null)
$r_method = '';
$method = strtoupper($_SERVER['REQUEST_METHOD']);
- if (isset($route['c_method'])) {
+ if (isset($route['c_method']))
+ {
$r_method = $route['c_method'];
goto EXECUTE;
}
- switch ($method) {
+ switch ($method)
+ {
case 'GET':
global $r_method;
$r_method = $params === null ? 'index' : 'show';
@@ -89,7 +94,8 @@ protected function __routeSelection(?Request $request = null)
}
EXECUTE:
- if ($request === null) {
+ if ($request === null)
+ {
$request = new Request($params);
}
@@ -99,37 +105,44 @@ protected function __routeSelection(?Request $request = null)
return $response;
}
- protected function __api_guards(?array $guards): bool
+ protected function __api_guards (?array $guards): bool
{
Exception::$IS_API = true;
header('Content-type: application/json');
- if (!$guards) {
+ if (!$guards)
+ {
return true;
}
$params = self::$map_info['params'] ?? null;
$request = new Request($params);
- for ($i = 0; $i < count((array) $guards); $i++) {
+ for ($i = 0; $i < count((array) $guards); $i++)
+ {
$registered_guards = (new FileLoader())
- ->load(__DIR__ . '/../../Config/guards.php')
- ->getLoad();
+ ->load(__DIR__ . '/../../Config/guards.php')
+ ->getLoad();
- if (array_key_exists($guards[$i], $registered_guards)) {
+ if (array_key_exists($guards[$i], $registered_guards))
+ {
$guard = $registered_guards[$guards[$i]];
- } else {
+ }
+ else
+ {
throw new Exception(
- 'No Registered AuthGuard as `' . $guards[$i] . '`',
+ 'No Registered AuthGuard as `' . $guards[$i] . '`',
);
}
- if (!class_exists($guard)) {
+ if (!class_exists($guard))
+ {
throw new Exception("AuthGuard class does not exist: `{$guard}`");
}
$cl = new $guard($request);
- if ($cl->authorize() !== true) {
+ if ($cl->authorize() !== true)
+ {
self::log();
exit();
}
@@ -137,28 +150,30 @@ protected function __api_guards(?array $guards): bool
return true;
}
- protected function __api_map(?Request $request = null): void
+ protected function __api_map (?Request $request = null): void
{
$map = self::$apiMap;
$base_url = $map['base_url'] ?? '';
$controller = $map['controller'] ?? '';
- foreach ($map as $route => $method) {
+ foreach ($map as $route => $method)
+ {
$r_method = $method[0] ?? 'GET';
$c_method = $method[1] ?? '';
$guards = $method[2] ?? null;
$url = $base_url . trim($route, '/');
self::$apiMap = [
- 'controller' => $controller,
- 'c_method' => trim($c_method, '@'),
- 'url' => $base_url,
+ 'controller' => $controller,
+ 'c_method' => trim($c_method, '@'),
+ 'url' => $base_url,
];
$match = new MapRoute();
self::$map_info = $match->match($r_method, $url);
- if (self::$map_info) {
+ if (self::$map_info)
+ {
$this->__api_guards($guards);
print_r($this->__routeSelection());
diff --git a/src/Traits/Resources/Resources.php b/src/Traits/Resources/Resources.php
index 82dbdfe..2c1708c 100644
--- a/src/Traits/Resources/Resources.php
+++ b/src/Traits/Resources/Resources.php
@@ -1,6 +1,6 @@
match($method, $route);
+
+ if (self::$map_info) {
+ extract(self::$map_info);
+ (new static())->__guards(self::$guards ?? null);
+
+ print_r(
+ call_user_func($callback, new Request($params), function (
+ $m,
+ $func = null,
+ ) use ($method) {
+ if (strpos($m, '|')) {
+ $array_m = explode('|', $m);
+ $array_m = array_map(fn($m) => trim($m), $array_m);
+ }
+
+ if ($m !== $method && !in_array($method, $array_m ?? [])) {
+ http_response_code(405);
+
+ if ($func) {
+ print_r($func($method));
+ exit();
+ }
+ print_r('Method Not Allowed');
+ exit();
+ }
+ }),
+ );
+ }
}
protected static function __any(?Request $request = null): void
@@ -296,7 +328,7 @@ protected static function __redirect(): void
$new_url = preg_replace("/(^\/)|(\/$)/", '', $new_url);
}
- if (strtolower($reqUri) === strtolower($route)) {
+ if ($reqUri === $route) {
http_response_code($code);
self::log();
diff --git a/src/Utils/Routes/Exception/InvalidTypesException.php b/src/Utils/Routes/Exception/InvalidTypesException.php
index c624067..e9a7767 100644
--- a/src/Utils/Routes/Exception/InvalidTypesException.php
+++ b/src/Utils/Routes/Exception/InvalidTypesException.php
@@ -1,118 +1,130 @@
strtoupper($t), $type);
- /**
- * Catches invalid strict types and throws an exception if any are found.
- *
- * @param array|string $type The type(s) to check against the recognized URL parameter types.
- * @param ?Closure $message Optional closure to generate a custom exception message.
- *
- * @throws self If any of the provided types are not recognized as URL parameter types.
- */
- public static function catchInvalidStrictTypes (array|string $type, ?Closure $message = null): void
- {
- if (is_array($type))
- {
- foreach ($type as $t)
- {
- if (!in_array($t, self::$types))
- {
- if (!$message)
- {
- throw new self("{{$t}} is not recognized as a URL parameter type");
- }
- else
- {
- throw new self($message((string) $t));
- }
- }
- }
- }
- else
- {
- if (!in_array($type, self::$types))
- {
- if (!$message)
- {
- throw new self("{{$type}} is not recognized as a URL parameter type");
- }
- else
- {
- throw new self($message((string) $type));
- }
- }
- }
- }
+ foreach ($type as $t) {
+ if (
+ !in_array($t, self::$types) &&
+ !self::matchStrictType((string) $t)
+ ) {
+ $t = preg_replace('/<[^<>]*>/', '', $t);
+ if (!$message) {
+ throw new self(
+ "{{$t}} is not recognized as a URL parameter type",
+ );
+ } else {
+ throw new self($message((string) $t));
+ }
+ }
+ }
+ } else {
+ $type = strtoupper($type);
+ if (
+ !in_array($type, self::$types) &&
+ !self::matchStrictType((string) $type)
+ ) {
+ $type = preg_replace('/<[^<>]*>/', '', $type);
- /**
- * Handles invalid parameter types by setting the HTTP response code and either
- * printing a custom error message or throwing an InvalidTypesException.
- *
- * @param array $typeRequested The types that were expected.
- * @param string $typeGotten The type that was actually received.
- * @param string|null $message Optional custom error message.
- * @param int $code The HTTP response code to set (default is 400).
- *
- * @return InvalidTypesException
- */
- public static function catchInvalidParameterTypes (array $typeRequested, string $typeGotten, ?string $message = null, int $code = 400): InvalidTypesException
- {
- http_response_code($code);
+ if (!$message) {
+ throw new self(
+ "{{$type}} is not recognized as a URL parameter type",
+ );
+ } else {
+ throw new self($message((string) $type));
+ }
+ }
+ }
+ }
- if (Application::$handleInvalidParameterType)
- {
- print_r((Application::$handleInvalidParameterType)($typeGotten));
- exit();
- }
- else
- {
- if (!$message)
- {
- $requested = implode(', ', $$typeRequested);
- return new self(
- "Invalid request parameter type. {{$requested}} requested, but got {{$typeGotten}}",
- );
- }
- else
- {
- return new self($message);
- }
- }
- }
-}
\ No newline at end of file
+ /**
+ * Handles invalid parameter types by setting the HTTP response code and either
+ * printing a custom error message or throwing an InvalidTypesException.
+ *
+ * @param array $typeRequested The types that were expected.
+ * @param string $typeGotten The type that was actually received.
+ * @param string|null $message Optional custom error message.
+ * @param int $code The HTTP response code to set (default is 400).
+ *
+ * @return InvalidTypesException
+ */
+ public static function catchInvalidParameterTypes(
+ array $typeRequested,
+ string $typeGotten,
+ ?string $message = null,
+ int $code = 400,
+ ): InvalidTypesException {
+ http_response_code($code);
+
+ if (Application::$handleInvalidParameterType) {
+ print_r((Application::$handleInvalidParameterType)($typeGotten));
+ exit();
+ } else {
+ if (!$message) {
+ $requested = implode(', ', $typeRequested);
+ $requested = preg_replace('/<[^<>]*>/', '', $requested);
+
+ return new self(
+ htmlspecialchars(
+ "Invalid request parameter type: Expected {{$requested}}, but received {{$typeGotten}}.",
+ ),
+ );
+ } else {
+ return new self(htmlspecialchars($message));
+ }
+ }
+ }
+
+ private static function matchStrictType(string $type)
+ {
+ return preg_match('/ARRAY<(.+)>/', (string) $type) ||
+ preg_match('/INT<(.+)>/', (string) $type) ||
+ preg_match('/ENUM<(.+)>/', (string) $type) ||
+ preg_match('/STRING<(.+)>/', (string) $type) ||
+ preg_match('/INTEGER<(.+)>/', (string) $type);
+ }
+}
diff --git a/src/Utils/Routes/StrictTypes.php b/src/Utils/Routes/StrictTypes.php
index a6e9216..3127113 100644
--- a/src/Utils/Routes/StrictTypes.php
+++ b/src/Utils/Routes/StrictTypes.php
@@ -1,15 +1,16 @@
strtoupper($t), $haystack);
+ $types = array_map(fn($t) => strtoupper($t), $haystack);
$typeOfNeedle = self::typeOfString($needle);
- if (self::matchType($needle, $types))
- {
- return match ($typeOfNeedle)
- {
- 'INT' => (int) $needle,
- 'BOOL' => (bool) $needle,
- 'FLOAT' => (float) $needle,
- 'ARRAY' => json_decode($needle, true),
- default => $needle,
+ if (self::matchType($needle, $types)) {
+ return match ($typeOfNeedle) {
+ 'INT' => (int) $needle,
+ 'BOOL' => filter_var($needle, FILTER_VALIDATE_BOOLEAN),
+ 'FLOAT' => (float) $needle,
+ 'ARRAY' => json_decode($needle, true),
+ default => $needle,
};
}
- throw InvalidTypesException::catchInvalidParameterTypes($types, $typeOfNeedle);
+ InvalidTypesException::catchInvalidStrictTypes($haystack);
+ throw InvalidTypesException::catchInvalidParameterTypes(
+ $types,
+ $typeOfNeedle,
+ );
}
-
/**
* Matches the type of the given needle against the specified haystack type.
*
@@ -88,8 +86,10 @@ protected static function matchStrictType (
* @return bool Returns true if the needle matches the haystack type, otherwise false.
* @throws InvalidTypesException If the needle does not match the haystack type.
*/
- private static function matches (string $needle, string $haystack): bool
+ private static function matches(string $needle, string $haystack): bool
{
+ $haystack = preg_replace('/INTEGER<(.+)>/', 'INT<$1>', $haystack);
+
$typeOfNeedle = self::typeOfString((string) $needle);
$typeOfNeedle2 = $typeOfNeedle;
$needle2 = $needle;
@@ -98,41 +98,125 @@ private static function matches (string $needle, string $haystack): bool
* MATCH ARRAY RECURSIVELY
*/
if (
- preg_match('/ARRAY<(.+)>/', $haystack, $matches) &&
- $typeOfNeedle === 'ARRAY'
- )
- {
+ preg_match('/ARRAY<(.+)>/', $haystack, $matches) &&
+ $typeOfNeedle === 'ARRAY'
+ ) {
$needle = json_decode($needle, true);
- $eachArrayTypes = explode(',', $matches[1]);
+ $eachArrayTypes = preg_split('/,(?![^<]*>)/', $matches[1]);
- foreach ($eachArrayTypes as $key => $eachArrayType)
- {
- $needle2 = is_array($needle[$key])
- ? json_encode($needle[$key])
- : (string) $needle[$key];
+ if (!is_array($needle)) {
+ $requested = implode(', ', $eachArrayTypes);
+ throw InvalidTypesException::catchInvalidParameterTypes(
+ $eachArrayTypes,
+ $typeOfNeedle,
+ );
+ }
- $eachTypes = preg_split('/\|(?![^<]*>)/', trim($eachArrayType));
+ foreach ($eachArrayTypes as $key => $eachArrayType) {
+ $eachTypes = preg_split(
+ '/\|(?![^<]*>)/',
+ trim(strtoupper($eachArrayType)),
+ );
+
+ if (!isset($needle[$key])) {
+ throw InvalidTypesException::catchInvalidParameterTypes(
+ $eachTypes,
+ 'NULL',
+ "Array index $key not found in the request parameter",
+ );
+ }
+
+ $needle2 = is_array($needle[$key])
+ ? json_encode($needle[$key])
+ : (string) $needle[$key];
$typeOfNeedle2 = self::typeOfString($needle2);
- if (!self::matchType($needle2, $eachTypes))
- {
+ if (!self::matchType($needle2, $eachTypes)) {
$requested = implode(', ', $eachTypes);
InvalidTypesException::catchInvalidStrictTypes($eachTypes);
throw InvalidTypesException::catchInvalidParameterTypes(
- $eachTypes,
- $typeOfNeedle2,
- "Invalid request parameter type. {{$requested}} requested on array index $key, but got {{$typeOfNeedle2}}",
+ $eachTypes,
+ $typeOfNeedle2,
+ "Invalid request parameter type: Expected {{$requested}} at array index {{$key}}, but received {{$typeOfNeedle2}}.",
);
}
}
return true;
}
+ /**
+ * MATCH INT
+ */
+ if (
+ preg_match('/INT<(\d+)(?:,\s*(\d+))?>/', $haystack, $matches) &&
+ $typeOfNeedle === 'INT'
+ ) {
+ $min = (int) $matches[1];
+ $max = (int) $matches[2] ?? null;
+ $needle = (int) $needle;
+
+ if (
+ (!$max && $needle < $min) ||
+ ($max && ($needle < $min || $needle > $max))
+ ) {
+ $requested = !$max ? "INT min($min)" : "INT min($min), max($max)";
+ throw InvalidTypesException::catchInvalidParameterTypes(
+ [$requested],
+ (string) $needle,
+ );
+ }
+ return true;
+ }
+
+ /**
+ * MATCH STRING LENGTH
+ */
+ if (
+ preg_match('/STRING<(\d+)(?:,\s*(\d+))?>/', $haystack, $matches) &&
+ $typeOfNeedle === 'STRING'
+ ) {
+ $min = (int) $matches[1];
+ $max = (int) $matches[2] ?? null;
+ $needle = (int) strlen($needle);
+
+ if (
+ (!$max && $needle < $min) ||
+ ($max && ($needle < $min || $needle > $max))
+ ) {
+ $requested = !$max
+ ? "STRING min($min)"
+ : "STRING min($min), max($max)";
+ throw InvalidTypesException::catchInvalidParameterTypes(
+ [$requested],
+ (string) $needle,
+ );
+ }
+ return true;
+ }
+
+ /**
+ * MATCH ENUM TYPE
+ */
+ if (preg_match('/ENUM<(.+)>/', $haystack, $matches)) {
+ $needle = strtoupper($needle);
+ $enum = array_map(fn($e) => trim($e), explode('|', $matches[1]));
+
+ if (!in_array($needle, $enum)) {
+ $requested = implode(', ', $enum);
+
+ throw InvalidTypesException::catchInvalidParameterTypes(
+ $enum,
+ $needle,
+ "Invalid request parameter type: Expected an enum of type {{$requested}}, but received {{$needle}}.",
+ );
+ }
+ return true;
+ }
+
InvalidTypesException::catchInvalidStrictTypes($haystack);
return false;
}
-
/**
* Determines the type of a given string.
*
@@ -140,9 +224,7 @@ private static function matches (string $needle, string $haystack): bool
* The possible return values are:
* - 'FLOAT' if the string represents a floating-point number.
* - 'INT' if the string represents an integer.
- * - 'BOOL' if the string represents a boolean value ('true' or 'false').
- * - 'ALPHA' if the string contains only alphabetic characters.
- * - 'ALNUM' if the string contains only alphanumeric characters.
+ * - 'BOOL' if the string represents a boolean value.
* - 'JSON' if the string is a valid JSON object.
* - 'ARRAY' if the string is a valid JSON array.
* - 'STRING' if the string does not match any of the above types.
@@ -150,45 +232,28 @@ private static function matches (string $needle, string $haystack): bool
* @param string $string The input string to be analyzed.
* @return string The type of the input string.
*/
- protected static function typeOfString (string $string): string
+ protected static function typeOfString(string $string): string
{
- $jd = json_decode($string, false);
+ $decoded = json_decode($string, false);
- if (is_numeric($string))
- {
- if (strpos($string, '.') !== false)
- {
- return 'FLOAT';
- }
- else
- {
- return 'INT';
- }
- }
- elseif (is_bool($string) || $string === 'true' || $string === 'false')
- {
+ if (is_numeric($string)) {
+ return strpos($string, '.') !== false ? 'FLOAT' : 'INT';
+ } elseif (
+ filter_var(
+ $string,
+ FILTER_VALIDATE_BOOLEAN,
+ FILTER_NULL_ON_FAILURE,
+ ) !== null
+ ) {
return 'BOOL';
- }
- elseif (ctype_alpha($string))
- {
- return 'ALPHA';
- }
- elseif (ctype_alnum($string))
- {
- return 'ALNUM';
- }
- elseif (json_last_error() === JSON_ERROR_NONE)
- {
- return match (gettype($jd))
- {
- 'object' => 'JSON',
- 'array' => 'ARRAY',
- default => 'STRING',
+ } elseif (json_last_error() === JSON_ERROR_NONE) {
+ return match (gettype($decoded)) {
+ 'object' => 'JSON',
+ 'array' => 'ARRAY',
+ default => 'STRING',
};
}
- else
- {
- return 'STRING';
- }
+
+ return 'STRING';
}
-}
\ No newline at end of file
+}
diff --git a/src/Utils/Validate.php b/src/Utils/Validate.php
index ed5e6f2..9b1ac3f 100644
--- a/src/Utils/Validate.php
+++ b/src/Utils/Validate.php
@@ -1,6 +1,6 @@
validate($item); // If item is array, call validate on it
}
return $this->realValidate($item); // Otherwise, validate the individual item
@@ -44,10 +47,11 @@ protected function validate(
*
* @return bool|float|int|string|null The validated and sanitized value, converted back to its original type.
*/
- private function realValidate(
- bool|float|int|string|null $value,
+ private function realValidate (
+ bool|float|int|string|null $value,
): bool|float|int|string|null {
- if (!$value) {
+ if (!$value)
+ {
return null;
}
@@ -56,24 +60,24 @@ private function realValidate(
// Sanitize the string to prevent potential HTML injection issues
$sanitizedValue = htmlspecialchars(
- trim($validatedValue),
- ENT_QUOTES,
- 'UTF-8',
+ trim($validatedValue),
+ ENT_QUOTES,
+ 'UTF-8',
);
$type = gettype($value);
// Convert the sanitized string back to its original type based on the initial value's type
$convertedValue =
- is_bool($value) || $type === 'boolean'
- ? (bool) $sanitizedValue
- : (is_numeric($value) || is_int($value) || $type === 'integer'
- ? (is_double($value) ||
- is_float($value) ||
- $type === 'double' ||
- strpos((string) $value, '.') !== false
- ? (float) $sanitizedValue
- : (int) $sanitizedValue)
- : $sanitizedValue);
+ is_bool($value) || $type === 'boolean'
+ ? (bool) $sanitizedValue
+ : (is_numeric($value) || is_int($value) || $type === 'integer'
+ ? (is_double($value) ||
+ is_float($value) ||
+ $type === 'double' ||
+ strpos((string) $value, '.') !== false
+ ? (float) $sanitizedValue
+ : (int) $sanitizedValue)
+ : $sanitizedValue);
return $convertedValue;
}
diff --git a/src/Web/JWT.php b/src/Web/JWT.php
index 5a64a5f..34046b3 100644
--- a/src/Web/JWT.php
+++ b/src/Web/JWT.php
@@ -1,11 +1,11 @@
contentType());
}
- function testRequestTime()
+ function testRequestTime ()
{
print_r($this->requestTime());
}
- function testContentLength()
+ function testContentLength ()
{
print_r($this->contentLength());
}
- function testIsHttps()
+ function testIsHttps ()
{
var_dump($this->isHttps());
}
- function testCsrf()
+ function testCsrf ()
{
print_r($this->csrf());
}
- function testProtocol()
+ function testProtocol ()
{
print_r($this->protocol());
}
- function testIp()
+ function testIp ()
{
print_r($this->ip());
}
- function testUrlParam()
+ function testUrlParam ()
{
print_r($this->urlParam());
}
- function testUrlQuery()
+ function testUrlQuery ()
{
print_r($this->urlQuery());
}
- function testHeader()
+ function testHeader ()
{
print_r($this->header());
}
- function testAuth()
+ function testAuth ()
{
print_r($this->auth());
}
- function testApiKey()
+ function testApiKey ()
{
print_r($this->apiKey());
}
- function testBody()
+ function testBody ()
{
print_r($this->body());
}
- function testGet()
+ function testGet ()
{
print_r($this->get());
}
- function testPost()
+ function testPost ()
{
print_r($this->post());
}
- function testRequest()
+ function testRequest ()
{
print_r($this->request());
}
- function testFiles()
+ function testFiles ()
{
print_r($this->files());
}
- function testCookie()
+ function testCookie ()
{
print_r($this->cookie());
}
- function testSession()
+ function testSession ()
{
print_r($this->session());
}
- function testMethod()
+ function testMethod ()
{
print_r($this->method());
}
- function testUri()
+ function testUri ()
{
print_r($this->uri());
}
- function testUrl()
+ function testUrl ()
{
print_r($this->url());
}
- function testUserAgent()
+ function testUserAgent ()
{
print_r($this->userAgent());
}
- function testIsAjax()
+ function testIsAjax ()
{
var_dump($this->isAjax());
}
- function testReferrer()
+ function testReferrer ()
{
print_r($this->referrer());
}
- function testServer()
+ function testServer ()
{
print_r($this->server());
}
- function testIsMethod()
+ function testIsMethod ()
{
var_dump($this->isMethod('GET'));
}
- function testAll()
+ function testAll ()
{
print_r($this->all());
}
@@ -177,4 +177,4 @@ function testAll()
// $req->testReferrer();
// $req->testServer();
// $req->testIsMethod();
-// $req->testAll();
+// $req->testAll();
\ No newline at end of file
diff --git a/tests/manualTests/Router/RouteTest.php b/tests/manualTests/Router/RouteTest.php
index 2c97c45..77fe4bc 100644
--- a/tests/manualTests/Router/RouteTest.php
+++ b/tests/manualTests/Router/RouteTest.php
@@ -1,8 +1,8 @@
, string>|alnum}")
- ->action(function (Request $req)
- {
- echo '
';
- return $req->urlParam();
- })
- ->route('/posts/{id: int}', function (Request $req, Closure $accept)
- {
- $accept('POST');
- });
+Route::map(
+ GET,
+ "$dir/User/{id: int<6, 10>|string<3,3>|bool|array|bool>, string>}/{status: enum}",
+)
+ ->action(function (Request $req) {
+ echo '
';
+ return $req->url();
+ })
+ ->route('/posts/{post_id: int}', function (Request $req, Closure $accept) {
+ $accept(GET, fn($method) => "`$method` method is not allowed");
-Render::WebRoute();
\ No newline at end of file
+ return 'ddd';
+ })
+ /*->handleInvalidParameterType(function ($type) {
+ return $type;
+ })*/
+ ->caseSensitive();
+
+Render::WebRoute();
diff --git a/tests/manualTests/Web/JwtTest.php b/tests/manualTests/Web/JwtTest.php
index f570b87..909b6f2 100644
--- a/tests/manualTests/Web/JwtTest.php
+++ b/tests/manualTests/Web/JwtTest.php
@@ -1,6 +1,7 @@
'555'], expires: time() + 3600);
+$payload = payload(data: ['user_id' => '555'], expires: '+7 days');
/**
* Testing JwtService encode method
diff --git a/tests/manualTests/src/configs/jwt.php b/tests/src/configs/jwt.php
similarity index 100%
rename from tests/manualTests/src/configs/jwt.php
rename to tests/src/configs/jwt.php