You've already forked Php-Template
feat/cli-framework (#12)
All checks were successful
🧪✨ Tests Workflow / 🛡️ 🔒 Library Audit (push) Successful in 1m37s
🧪✨ Tests Workflow / 📝 ✨ Code Lint (push) Successful in 1m32s
🧪✨ Tests Workflow / 🧪 ✨ Database Migrations (push) Successful in 1m54s
🧪✨ Tests Workflow / 🛡️ 🔒 License Check (push) Successful in 1m46s
🧪✨ Tests Workflow / 🐙 🔍 Code Sniffer (push) Successful in 1m49s
🧪✨ Tests Workflow / 🧪 ✅ Unit Tests (push) Successful in 1m18s
All checks were successful
🧪✨ Tests Workflow / 🛡️ 🔒 Library Audit (push) Successful in 1m37s
🧪✨ Tests Workflow / 📝 ✨ Code Lint (push) Successful in 1m32s
🧪✨ Tests Workflow / 🧪 ✨ Database Migrations (push) Successful in 1m54s
🧪✨ Tests Workflow / 🛡️ 🔒 License Check (push) Successful in 1m46s
🧪✨ Tests Workflow / 🐙 🔍 Code Sniffer (push) Successful in 1m49s
🧪✨ Tests Workflow / 🧪 ✅ Unit Tests (push) Successful in 1m18s
Reviewed-on: #12 Co-authored-by: Ron Rise <ron@siteworxpro.com> Co-committed-by: Ron Rise <ron@siteworxpro.com>
This commit was merged in pull request #12.
This commit is contained in:
11
cli.php
Executable file
11
cli.php
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/local/bin/php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Siteworxpro\App\Cli\App;
|
||||||
|
|
||||||
|
$cliApp = new App();
|
||||||
|
exit($cliApp->run());
|
||||||
@@ -18,7 +18,8 @@
|
|||||||
"siteworxpro/config": "^1.1.1",
|
"siteworxpro/config": "^1.1.1",
|
||||||
"predis/predis": "^v3.2.0",
|
"predis/predis": "^v3.2.0",
|
||||||
"siteworxpro/http-status": "0.0.2",
|
"siteworxpro/http-status": "0.0.2",
|
||||||
"lcobucci/jwt": "^5.6"
|
"lcobucci/jwt": "^5.6",
|
||||||
|
"adhocore/cli": "^1.9"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^12.4",
|
"phpunit/phpunit": "^12.4",
|
||||||
|
|||||||
75
composer.lock
generated
75
composer.lock
generated
@@ -4,8 +4,81 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "d9509da999bae9517bf79ee251ccdd32",
|
"content-hash": "f7dc2e6131715ed6eec2d9f851949b80",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "adhocore/cli",
|
||||||
|
"version": "v1.9.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/adhocore/php-cli.git",
|
||||||
|
"reference": "474dc3d7ab139796be98b104d891476e3916b6f4"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/adhocore/php-cli/zipball/474dc3d7ab139796be98b104d891476e3916b6f4",
|
||||||
|
"reference": "474dc3d7ab139796be98b104d891476e3916b6f4",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Ahc\\Cli\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jitendra Adhikari",
|
||||||
|
"email": "jiten.adhikary@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Command line interface library for PHP",
|
||||||
|
"keywords": [
|
||||||
|
"argument-parser",
|
||||||
|
"argv-parser",
|
||||||
|
"cli",
|
||||||
|
"cli-action",
|
||||||
|
"cli-app",
|
||||||
|
"cli-color",
|
||||||
|
"cli-option",
|
||||||
|
"cli-writer",
|
||||||
|
"command",
|
||||||
|
"console",
|
||||||
|
"console-app",
|
||||||
|
"php-cli",
|
||||||
|
"php8",
|
||||||
|
"stream-input",
|
||||||
|
"stream-output"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/adhocore/php-cli/issues",
|
||||||
|
"source": "https://github.com/adhocore/php-cli/tree/v1.9.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://paypal.me/ji10",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/adhocore",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-05-11T13:23:54+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ services:
|
|||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
entrypoint: "/bin/sh -c 'while true; do sleep 30; done;'"
|
entrypoint: "/bin/sh -c 'while true; do sleep 30; done;'"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
traefik:
|
||||||
|
condition: service_healthy
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
postgres:
|
postgres:
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Siteworxpro\App\Server;
|
use Siteworxpro\App\Api;
|
||||||
|
|
||||||
require __DIR__ . '/vendor/autoload.php';
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Instantiate the ExternalServer class
|
// Instantiate the ExternalServer class
|
||||||
$server = new Server();
|
$server = new Api();
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
$server->startServer();
|
$server->startServer();
|
||||||
|
|||||||
@@ -4,25 +4,18 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Siteworxpro\App;
|
namespace Siteworxpro\App;
|
||||||
|
|
||||||
use Illuminate\Container\Container;
|
|
||||||
use Illuminate\Database\Capsule\Manager;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
use League\Route\Http\Exception\MethodNotAllowedException;
|
use League\Route\Http\Exception\MethodNotAllowedException;
|
||||||
use League\Route\Http\Exception\NotFoundException;
|
use League\Route\Http\Exception\NotFoundException;
|
||||||
use League\Route\Router;
|
use League\Route\Router;
|
||||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||||
use Siteworx\Config\Config as SWConfig;
|
|
||||||
use Siteworxpro\App\Controllers\HealthcheckController;
|
use Siteworxpro\App\Controllers\HealthcheckController;
|
||||||
use Siteworxpro\App\Controllers\IndexController;
|
use Siteworxpro\App\Controllers\IndexController;
|
||||||
use Siteworxpro\App\Http\JsonResponseFactory;
|
use Siteworxpro\App\Http\JsonResponseFactory;
|
||||||
use Siteworxpro\App\Http\Middleware\CorsMiddleware;
|
use Siteworxpro\App\Http\Middleware\CorsMiddleware;
|
||||||
use Siteworxpro\App\Http\Middleware\JwtMiddleware;
|
use Siteworxpro\App\Http\Middleware\JwtMiddleware;
|
||||||
use Siteworxpro\App\Http\Middleware\ScopeMiddleware;
|
use Siteworxpro\App\Http\Middleware\ScopeMiddleware;
|
||||||
use Siteworxpro\App\Services\Facade;
|
|
||||||
use Siteworxpro\App\Services\Facades\Config;
|
use Siteworxpro\App\Services\Facades\Config;
|
||||||
use Siteworxpro\App\Services\Facades\Logger;
|
use Siteworxpro\App\Services\Facades\Logger;
|
||||||
use Siteworxpro\App\Services\ServiceProviders\LoggerServiceProvider;
|
|
||||||
use Siteworxpro\App\Services\ServiceProviders\RedisServiceProvider;
|
|
||||||
use Siteworxpro\HttpStatus\CodesEnum;
|
use Siteworxpro\HttpStatus\CodesEnum;
|
||||||
use Spiral\RoadRunner\Http\PSR7Worker;
|
use Spiral\RoadRunner\Http\PSR7Worker;
|
||||||
use Spiral\RoadRunner\Worker;
|
use Spiral\RoadRunner\Worker;
|
||||||
@@ -36,7 +29,7 @@ use Spiral\RoadRunner\Worker;
|
|||||||
*
|
*
|
||||||
* @package Siteworxpro\App
|
* @package Siteworxpro\App
|
||||||
*/
|
*/
|
||||||
class Server
|
class Api
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Router The router instance for handling routes.
|
* @var Router The router instance for handling routes.
|
||||||
@@ -48,87 +41,13 @@ class Server
|
|||||||
*/
|
*/
|
||||||
protected PSR7Worker $worker;
|
protected PSR7Worker $worker;
|
||||||
|
|
||||||
public static array $serviceProviders = [
|
|
||||||
LoggerServiceProvider::class,
|
|
||||||
RedisServiceProvider::class
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server constructor.
|
|
||||||
*
|
|
||||||
* Initializes the server by booting the PSR-7 worker and router.
|
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->boot();
|
Kernel::boot();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstraps the server by initializing the PSR-7 worker and router.
|
|
||||||
*
|
|
||||||
* This method sets up the PSR-7 worker and router instances, and registers
|
|
||||||
* the routes for the server. It should be called in the constructor of
|
|
||||||
* subclasses to ensure proper initialization.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @throws \ReflectionException
|
|
||||||
*/
|
|
||||||
private function boot(): void
|
|
||||||
{
|
|
||||||
$container = new Container();
|
|
||||||
Facade::setFacadeContainer($container);
|
|
||||||
|
|
||||||
// Bind the container to the Config facade first so that it can be used by service providers
|
|
||||||
$container->bind(SWConfig::class, function () {
|
|
||||||
return SWConfig::load(__DIR__ . '/../config.php');
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (self::$serviceProviders as $serviceProvider) {
|
|
||||||
if (class_exists($serviceProvider)) {
|
|
||||||
$provider = new $serviceProvider($container);
|
|
||||||
if ($provider instanceof ServiceProvider) {
|
|
||||||
$provider->register();
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException(sprintf(
|
|
||||||
'Service provider %s is not an instance of ServiceProvider.',
|
|
||||||
$serviceProvider
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException(sprintf('Service provider %s not found.', $serviceProvider));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->worker = new PSR7Worker(
|
|
||||||
Worker::create(),
|
|
||||||
new Psr17Factory(),
|
|
||||||
new Psr17Factory(),
|
|
||||||
new Psr17Factory()
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->router = new Router();
|
|
||||||
|
|
||||||
$this->registerRoutes();
|
$this->registerRoutes();
|
||||||
$this->bootModelCapsule();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstraps the model capsule for database connections.
|
|
||||||
*
|
|
||||||
* This method sets up the database connection using the Eloquent ORM.
|
|
||||||
* It retrieves the database configuration from the Config facade and
|
|
||||||
* initializes the Eloquent capsule manager.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function bootModelCapsule(): void
|
|
||||||
{
|
|
||||||
$capsule = new Manager();
|
|
||||||
$capsule->addConnection(Config::get('db'));
|
|
||||||
$capsule->setAsGlobal();
|
|
||||||
$capsule->bootEloquent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,8 +58,16 @@ class Server
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function registerRoutes(): void
|
public function registerRoutes(): void
|
||||||
{
|
{
|
||||||
|
$this->worker = new PSR7Worker(
|
||||||
|
Worker::create(),
|
||||||
|
new Psr17Factory(),
|
||||||
|
new Psr17Factory(),
|
||||||
|
new Psr17Factory()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->router = new Router();
|
||||||
$this->router->get('/', IndexController::class . '::get');
|
$this->router->get('/', IndexController::class . '::get');
|
||||||
$this->router->get('/healthz', HealthcheckController::class . '::get');
|
$this->router->get('/healthz', HealthcheckController::class . '::get');
|
||||||
|
|
||||||
@@ -197,7 +124,9 @@ class Server
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->worker->respond(JsonResponseFactory::createJsonResponse($json, CodesEnum::INTERNAL_SERVER_ERROR));
|
$this->worker->respond(
|
||||||
|
JsonResponseFactory::createJsonResponse($json, CodesEnum::INTERNAL_SERVER_ERROR)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
41
src/Cli/App.php
Normal file
41
src/Cli/App.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\App\Cli;
|
||||||
|
|
||||||
|
use Ahc\Cli\Application;
|
||||||
|
use Siteworxpro\App\Cli\Commands\DemoCommand;
|
||||||
|
use Siteworxpro\App\Kernel;
|
||||||
|
use Siteworxpro\App\Services\Facades\Config;
|
||||||
|
|
||||||
|
class App
|
||||||
|
{
|
||||||
|
private Application $app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
Kernel::boot();
|
||||||
|
$this->app = new Application('Php-Template', Config::get('app.version') ?? 'dev-master');
|
||||||
|
|
||||||
|
$this->app->add(new DemoCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(): int
|
||||||
|
{
|
||||||
|
$this->app->logo(
|
||||||
|
<<<EOF
|
||||||
|
▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄ ▄▄▄▄▄▄▄ ▀▀█ ▄
|
||||||
|
█ ▀█ █ █ █ ▀█ █ ▄▄▄ ▄▄▄▄▄ ▄▄▄▄ █ ▄▄▄ ▄▄█▄▄ ▄▄▄
|
||||||
|
█▄▄▄█▀ █▄▄▄▄█ █▄▄▄█▀ █ █▀ █ █ █ █ █▀ ▀█ █ ▀ █ █ █▀ █
|
||||||
|
█ █ █ █ ▀▀▀ █ █▀▀▀▀ █ █ █ █ █ █ ▄▀▀▀█ █ █▀▀▀▀
|
||||||
|
█ █ █ █ █ ▀█▄▄▀ █ █ █ ██▄█▀ ▀▄▄ ▀▄▄▀█ ▀▄▄ ▀█▄▄▀
|
||||||
|
█
|
||||||
|
EOF
|
||||||
|
);
|
||||||
|
return $this->app->handle($_SERVER['argv']);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/Cli/Commands/CommandInterface.php
Normal file
15
src/Cli/Commands/CommandInterface.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\App\Cli\Commands;
|
||||||
|
|
||||||
|
interface CommandInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function execute(): int;
|
||||||
|
}
|
||||||
47
src/Cli/Commands/DemoCommand.php
Normal file
47
src/Cli/Commands/DemoCommand.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\App\Cli\Commands;
|
||||||
|
|
||||||
|
use Ahc\Cli\Input\Command;
|
||||||
|
|
||||||
|
class DemoCommand extends Command implements CommandInterface
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('api:demo', 'A demo command to showcase the CLI functionality.');
|
||||||
|
|
||||||
|
$this->argument('[name]', 'Your name')
|
||||||
|
->option('-g, --greet', 'Include a greeting message');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(): int
|
||||||
|
{
|
||||||
|
$pb = $this->progress(100);
|
||||||
|
|
||||||
|
for ($i = 0; $i < 100; $i += 10) {
|
||||||
|
usleep(100000); // Simulate work
|
||||||
|
$pb->advance(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pb->finish();
|
||||||
|
|
||||||
|
$this->writer()->boldBlue("Demo Command Executed!\n");
|
||||||
|
|
||||||
|
if ($this->values()['name']) {
|
||||||
|
$name = $this->values()['name'];
|
||||||
|
$greet = $this->values()['greet'] ?? false;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($greet) {
|
||||||
|
$this->writer()->green("Hello, $name! Welcome to the CLI demo.\n");
|
||||||
|
} else {
|
||||||
|
$this->writer()->yellow("Name provided: {$name}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,48 +18,35 @@ use Lcobucci\JWT\Validation\Constraint\SignedWith;
|
|||||||
use Lcobucci\JWT\Validation\Constraint\StrictValidAt;
|
use Lcobucci\JWT\Validation\Constraint\StrictValidAt;
|
||||||
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
||||||
use League\Route\Dispatcher;
|
use League\Route\Dispatcher;
|
||||||
use League\Route\Route;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Server\MiddlewareInterface;
|
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
use Siteworxpro\App\Annotations\Guards\Jwt;
|
use Siteworxpro\App\Annotations\Guards\Jwt;
|
||||||
|
use Siteworxpro\App\Controllers\Controller;
|
||||||
use Siteworxpro\App\Http\JsonResponseFactory;
|
use Siteworxpro\App\Http\JsonResponseFactory;
|
||||||
use Siteworxpro\App\Services\Facades\Config;
|
use Siteworxpro\App\Services\Facades\Config;
|
||||||
use Siteworxpro\HttpStatus\CodesEnum;
|
use Siteworxpro\HttpStatus\CodesEnum;
|
||||||
|
|
||||||
class JwtMiddleware implements MiddlewareInterface
|
class JwtMiddleware extends Middleware
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @throws \JsonException
|
* @throws \JsonException
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function process(ServerRequestInterface $request, RequestHandlerInterface|Dispatcher $handler): ResponseInterface
|
public function process(
|
||||||
{
|
ServerRequestInterface $request,
|
||||||
|
RequestHandlerInterface|Dispatcher $handler
|
||||||
|
): ResponseInterface {
|
||||||
|
|
||||||
if (!$handler instanceof Dispatcher) {
|
$callable = $this->extractRouteCallable($request, $handler);
|
||||||
|
if ($callable === null) {
|
||||||
return $handler->handle($request);
|
return $handler->handle($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var Route | null $lastSegment */
|
/** @var Controller $class */
|
||||||
$lastSegment = array_last($handler->getMiddlewareStack());
|
[$class, $method] = $callable;
|
||||||
|
|
||||||
if ($lastSegment === null) {
|
if (class_exists($class::class)) {
|
||||||
return $handler->handle($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
$callable = $lastSegment->getCallable();
|
|
||||||
$class = null;
|
|
||||||
$method = null;
|
|
||||||
|
|
||||||
if (is_array($callable) && count($callable) === 2) {
|
|
||||||
[$class, $method] = $callable;
|
|
||||||
} elseif (is_string($callable)) {
|
|
||||||
// Handle the case where the callable is a string (e.g., 'ClassName::methodName')
|
|
||||||
[$class, $method] = explode('::', $callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (class_exists($class)) {
|
|
||||||
$reflectionClass = new \ReflectionClass($class);
|
$reflectionClass = new \ReflectionClass($class);
|
||||||
|
|
||||||
if ($reflectionClass->hasMethod($method)) {
|
if ($reflectionClass->hasMethod($method)) {
|
||||||
@@ -150,4 +137,4 @@ class JwtMiddleware implements MiddlewareInterface
|
|||||||
|
|
||||||
return new SignedWith(new Hmac256(), $key);
|
return new SignedWith(new Hmac256(), $key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/Http/Middleware/Middleware.php
Normal file
41
src/Http/Middleware/Middleware.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\App\Http\Middleware;
|
||||||
|
|
||||||
|
use League\Route\Dispatcher;
|
||||||
|
use League\Route\Route;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
|
||||||
|
abstract class Middleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function extractRouteCallable($request, RequestHandlerInterface | Dispatcher $handler): array|null
|
||||||
|
{
|
||||||
|
if (!$handler instanceof Dispatcher) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Route | null $lastSegment */
|
||||||
|
$lastSegment = array_last($handler->getMiddlewareStack());
|
||||||
|
|
||||||
|
if ($lastSegment === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$callable = $lastSegment->getCallable();
|
||||||
|
$class = null;
|
||||||
|
$method = null;
|
||||||
|
|
||||||
|
if (is_array($callable) && count($callable) === 2) {
|
||||||
|
[$class, $method] = $callable;
|
||||||
|
} elseif (is_string($callable)) {
|
||||||
|
// Handle the case where the callable is a string (e.g., 'ClassName::methodName')
|
||||||
|
[$class, $method] = explode('::', $callable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$class, $method];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,45 +5,32 @@ declare(strict_types=1);
|
|||||||
namespace Siteworxpro\App\Http\Middleware;
|
namespace Siteworxpro\App\Http\Middleware;
|
||||||
|
|
||||||
use League\Route\Dispatcher;
|
use League\Route\Dispatcher;
|
||||||
use League\Route\Route;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Server\MiddlewareInterface;
|
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
use Siteworxpro\App\Annotations\Guards\Scope;
|
use Siteworxpro\App\Annotations\Guards\Scope;
|
||||||
|
use Siteworxpro\App\Controllers\Controller;
|
||||||
use Siteworxpro\App\Http\JsonResponseFactory;
|
use Siteworxpro\App\Http\JsonResponseFactory;
|
||||||
use Siteworxpro\HttpStatus\CodesEnum;
|
use Siteworxpro\HttpStatus\CodesEnum;
|
||||||
|
|
||||||
class ScopeMiddleware implements MiddlewareInterface
|
class ScopeMiddleware extends Middleware
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @throws \JsonException
|
* @throws \JsonException
|
||||||
*/
|
*/
|
||||||
public function process(ServerRequestInterface $request, RequestHandlerInterface | Dispatcher $handler): ResponseInterface
|
public function process(
|
||||||
{
|
ServerRequestInterface $request,
|
||||||
if (!$handler instanceof Dispatcher) {
|
RequestHandlerInterface | Dispatcher $handler
|
||||||
|
): ResponseInterface {
|
||||||
|
$callable = $this->extractRouteCallable($request, $handler);
|
||||||
|
if ($callable === null) {
|
||||||
return $handler->handle($request);
|
return $handler->handle($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var Route | null $lastSegment */
|
/** @var Controller $class */
|
||||||
$lastSegment = array_last($handler->getMiddlewareStack());
|
[$class, $method] = $callable;
|
||||||
|
|
||||||
if ($lastSegment === null) {
|
if (class_exists($class::class)) {
|
||||||
return $handler->handle($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
$callable = $lastSegment->getCallable();
|
|
||||||
$class = null;
|
|
||||||
$method = null;
|
|
||||||
|
|
||||||
if (is_array($callable) && count($callable) === 2) {
|
|
||||||
[$class, $method] = $callable;
|
|
||||||
} elseif (is_string($callable)) {
|
|
||||||
// Handle the case where the callable is a string (e.g., 'ClassName::methodName')
|
|
||||||
[$class, $method] = explode('::', $callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (class_exists($class)) {
|
|
||||||
$reflectionClass = new \ReflectionClass($class);
|
$reflectionClass = new \ReflectionClass($class);
|
||||||
if ($reflectionClass->hasMethod($method)) {
|
if ($reflectionClass->hasMethod($method)) {
|
||||||
$reflectionMethod = $reflectionClass->getMethod($method);
|
$reflectionMethod = $reflectionClass->getMethod($method);
|
||||||
@@ -56,10 +43,16 @@ class ScopeMiddleware implements MiddlewareInterface
|
|||||||
|
|
||||||
$userScopes = $request->getAttribute('scopes', []);
|
$userScopes = $request->getAttribute('scopes', []);
|
||||||
|
|
||||||
if (array_any($requiredScopes, fn($requiredScope) => !in_array($requiredScope, $userScopes, true))) {
|
if (
|
||||||
|
array_any(
|
||||||
|
$requiredScopes,
|
||||||
|
fn($requiredScope) => !in_array($requiredScope, $userScopes, true)
|
||||||
|
)
|
||||||
|
) {
|
||||||
return JsonResponseFactory::createJsonResponse([
|
return JsonResponseFactory::createJsonResponse([
|
||||||
'error' => 'insufficient_scope',
|
'error' => 'insufficient_scope',
|
||||||
'error_description' => 'The request requires higher privileges than provided by the access token.'
|
'error_description' =>
|
||||||
|
'The request requires higher privileges than provided by the access token.'
|
||||||
], CodesEnum::FORBIDDEN);
|
], CodesEnum::FORBIDDEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,4 +61,4 @@ class ScopeMiddleware implements MiddlewareInterface
|
|||||||
|
|
||||||
return $handler->handle($request);
|
return $handler->handle($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/Kernel.php
Normal file
76
src/Kernel.php
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Siteworxpro\App;
|
||||||
|
|
||||||
|
use Illuminate\Container\Container;
|
||||||
|
use Illuminate\Database\Capsule\Manager;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Siteworx\Config\Config as SWConfig;
|
||||||
|
use Siteworxpro\App\Services\Facade;
|
||||||
|
use Siteworxpro\App\Services\Facades\Config;
|
||||||
|
use Siteworxpro\App\Services\ServiceProviders\LoggerServiceProvider;
|
||||||
|
use Siteworxpro\App\Services\ServiceProviders\RedisServiceProvider;
|
||||||
|
|
||||||
|
class Kernel
|
||||||
|
{
|
||||||
|
private static array $serviceProviders = [
|
||||||
|
LoggerServiceProvider::class,
|
||||||
|
RedisServiceProvider::class
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstraps the server by initializing the PSR-7 worker and router.
|
||||||
|
*
|
||||||
|
* This method sets up the PSR-7 worker and router instances, and registers
|
||||||
|
* the routes for the server. It should be called in the constructor of
|
||||||
|
* subclasses to ensure proper initialization.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public static function boot(): void
|
||||||
|
{
|
||||||
|
$container = new Container();
|
||||||
|
Facade::setFacadeContainer($container);
|
||||||
|
|
||||||
|
// Bind the container to the Config facade first so that it can be used by service providers
|
||||||
|
$container->bind(SWConfig::class, function () {
|
||||||
|
return SWConfig::load(__DIR__ . '/../config.php');
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (self::$serviceProviders as $serviceProvider) {
|
||||||
|
if (class_exists($serviceProvider)) {
|
||||||
|
$provider = new $serviceProvider($container);
|
||||||
|
if ($provider instanceof ServiceProvider) {
|
||||||
|
$provider->register();
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException(sprintf(
|
||||||
|
'Service provider %s is not an instance of ServiceProvider.',
|
||||||
|
$serviceProvider
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException(sprintf('Service provider %s not found.', $serviceProvider));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::bootModelCapsule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstraps the model capsule for database connections.
|
||||||
|
*
|
||||||
|
* This method sets up the database connection using the Eloquent ORM.
|
||||||
|
* It retrieves the database configuration from the Config facade and
|
||||||
|
* initializes the Eloquent capsule manager.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function bootModelCapsule(): void
|
||||||
|
{
|
||||||
|
$capsule = new Manager();
|
||||||
|
$capsule->addConnection(Config::get('db'));
|
||||||
|
$capsule->setAsGlobal();
|
||||||
|
$capsule->bootEloquent();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user