From 42f33d9f13d4746dcd19521d1efcf727d6181cb3 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Mon, 12 May 2025 15:06:47 +0000 Subject: [PATCH 1/3] - Added AdapterProxy autoload in ORM --- meta/definitions/authorize.php | 14 ++++++-------- meta/definitions/event.php | 4 ++-- meta/definitions/orm.php | 10 +++++++--- meta/definitions/software.php | 10 ++-------- src/Application.php | 3 +++ src/ApplicationStrategy.php | 7 +++++-- src/ControllerTrait.php | 16 +++++++++------- src/Factory/HttpFactory.php | 2 +- src/Factory/HttpFactoryInterface.php | 22 ++++++++++++++++++++++ src/Kernel.php | 5 ++++- src/Lean.php | 25 +++++++++++++++---------- 11 files changed, 76 insertions(+), 42 deletions(-) create mode 100644 src/Factory/HttpFactoryInterface.php diff --git a/meta/definitions/authorize.php b/meta/definitions/authorize.php index cb2a1df..6332712 100644 --- a/meta/definitions/authorize.php +++ b/meta/definitions/authorize.php @@ -1,7 +1,5 @@ create(Authenticate::class)->constructor(get(Entity\UserInterface::class), get(Session::class), get(Cookie::class), get('authentication.method')), @@ -29,17 +27,17 @@ return [ 'authentication.method' => null, 'authorize.error' => function($c) { - return function(array $errorData) { - return HttpFactory::createJsonResponse($errorData + [ + return function(array $errorData) use ($c) { + return $c->get(\Lean\Factory\HttpFactoryInterface::class)::createJsonResponse($errorData + [ 'api.error' => "Authorization failed", - 'api.datetime' => (new \DateTime)->format(\DateTime::ISO8601), + 'api.datetime' => (new \DateTime)->format(\DateTime::ATOM), ], 403); }; }, 'authentication.error' => function($c, Picea $picea) { - return function($message) use ($picea) { - return HttpFactory::createHtmlResponse($picea->renderHtml('lean/error/500', [ + return function($message) use ($picea, $c) { + return $c->get(\Lean\Factory\HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml('lean/error/500', [ 'title' => "Authentication failed", 'subtitle' => "", 'message' => $message, diff --git a/meta/definitions/event.php b/meta/definitions/event.php index 455890a..7cb85dc 100644 --- a/meta/definitions/event.php +++ b/meta/definitions/event.php @@ -64,8 +64,8 @@ return [ } } - if ( $securityHandler->isLocked($class, $method) && $container->has(Taxus::class) && $container->has(SecurityHandler::class) ) { - if ( $forbidden = $container->get(SecurityHandler::class)->taxus($class, $method, $object->user ?? null) ) { + if ( $securityHandler->isLocked($class, $method) && $container->has(Taxus::class)) { + if ( $forbidden = $securityHandler->taxus($class, $method, $object->user ?? null) ) { $routing->response = $forbidden; return; diff --git a/meta/definitions/orm.php b/meta/definitions/orm.php index 5fcec93..d272f3b 100644 --- a/meta/definitions/orm.php +++ b/meta/definitions/orm.php @@ -11,8 +11,12 @@ return [ ]), AdapterProxy::class => function (Psr\Container\ContainerInterface $c) { - return new AdapterProxy( - $c->get(ConnectionAdapter::class), - ); + $proxy = new AdapterProxy(); + + $autoload = $c->get(\Lean\Lean::class)->getConnectionAdapters(); + + $proxy->push($autoload); + + return $proxy; }, ]; diff --git a/meta/definitions/software.php b/meta/definitions/software.php index 31f329f..aaff563 100644 --- a/meta/definitions/software.php +++ b/meta/definitions/software.php @@ -66,20 +66,14 @@ return [ 'routes' => [], 'cronard' => [], - - 'taxus' => [ - 'is_dev' => [ ' dev' => "Is a developper of this application or has the same rights" ], - 'is_admin' => [ 'admin' => "Can manage almost everything in this application."], - 'is_moderator' => [ 'moderator' => "Can moderate this application."], - 'is_user' => [ 'user' => "Is an authenticated user."], - 'is_anonymous' => [ 'anonymous' => "Is an anonymous user."], - ], ], 'lean.autoload' => add([ Lean::class, ]), + \Lean\Factory\HttpFactoryInterface::class => autowire(\Lean\Factory\HttpFactory::class), + Lean::class => autowire(Lean::class), JavascriptMiddleware::class => create(JavascriptMiddleware::class), diff --git a/src/Application.php b/src/Application.php index 424c727..6fca8a4 100644 --- a/src/Application.php +++ b/src/Application.php @@ -22,6 +22,8 @@ class Application public array $entities; + public array $connectionAdapters; + public array $events; public array $tellJson; @@ -68,6 +70,7 @@ class Application if (is_array($ulmus = $this->data['ulmus'] ?? false)) { if ($ulmus['entities'] ?? false) { $this->entities = $ulmus['entities']; + $this->connectionAdapters = $ulmus['adapters'] ?? []; } } diff --git a/src/ApplicationStrategy.php b/src/ApplicationStrategy.php index 0cd517a..2d3263f 100644 --- a/src/ApplicationStrategy.php +++ b/src/ApplicationStrategy.php @@ -5,6 +5,7 @@ namespace Lean; use League\Route\Strategy; use League\Route\Http\Exception\NotFoundException; +use Lean\Factory\HttpFactoryInterface; use Picea\Asset\Asset; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; @@ -25,15 +26,17 @@ class ApplicationStrategy extends Strategy\ApplicationStrategy { public function __construct( protected Picea $picea, protected ContainerInterface $di, + protected HttpFactoryInterface $httpFactory, ) {} public function getNotFoundDecorator(NotFoundException $exception): MiddlewareInterface { - return new class($this->picea, $this->di) implements MiddlewareInterface { + return new class($this->picea, $this->di, $this->httpFactory) implements MiddlewareInterface { public function __construct( protected Picea $picea, protected ContainerInterface $di, + protected HttpFactoryInterface $httpFactory, ) { } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface @@ -58,7 +61,7 @@ class ApplicationStrategy extends Strategy\ApplicationStrategy { } } - return new \Laminas\Diactoros\Response\HtmlResponse($this->picea->renderHtml("lean/error/404", [], $this), 404); + return $this->httpFactory->createHtmlResponse($this->picea->renderHtml("lean/error/404", [], $this), 404); } }; } diff --git a/src/ControllerTrait.php b/src/ControllerTrait.php index 341edeb..6a7feb5 100644 --- a/src/ControllerTrait.php +++ b/src/ControllerTrait.php @@ -147,13 +147,15 @@ trait ControllerTrait { #[Ignore] public function renderCLI(ServerRequestInterface $request, mixed $data) : ResponseInterface { - if ($data instanceof \JsonSerializable ) { - return $this->renderJson( - $data - ); - } - elseif ( is_array($data) ) { - var_export($data); + if (! $data instanceof \Stringable) { + if ($data instanceof \JsonSerializable) { + return $this->renderJson( + $data + ); + } + elseif (is_iterable($data) || is_object($data)) { + return $this->renderText(var_export($data, true)); + } } return $this->renderText( diff --git a/src/Factory/HttpFactory.php b/src/Factory/HttpFactory.php index afd32c6..1ab5214 100644 --- a/src/Factory/HttpFactory.php +++ b/src/Factory/HttpFactory.php @@ -7,7 +7,7 @@ use Lean\Response\{ DownloadResponse, ImageResponse, FileDownloadResponse, PdfRe use Laminas\Diactoros\Response; use Psr\Http\Message\ResponseInterface; -class HttpFactory +class HttpFactory implements HttpFactoryInterface { public static function createResponse(string $url, int $code = 302, array $headers = []) : ResponseInterface { diff --git a/src/Factory/HttpFactoryInterface.php b/src/Factory/HttpFactoryInterface.php new file mode 100644 index 0000000..4ef594b --- /dev/null +++ b/src/Factory/HttpFactoryInterface.php @@ -0,0 +1,22 @@ +container->has('ulmus.caching') and ( Ulmus::$cache = $this->container->get('ulmus.caching') ); + # $this->container->has(AdapterProxy::class) and ( $ ) return $this; } diff --git a/src/Lean.php b/src/Lean.php index 6bd50ba..32fc06b 100644 --- a/src/Lean.php +++ b/src/Lean.php @@ -77,37 +77,42 @@ class Lean public function getRoutable() : array { - return array_merge(...array_map(fn($app) => $app->routes ?? [], $this->applications)); + return array_merge(...array_map(fn(Application $app) => $app->routes ?? [], $this->applications)); } public function getCronard() : array { - return array_merge(...array_map(fn($app) => $app->cronard ?? [], $this->applications)); + return array_merge(...array_map(fn(Application $app) => $app->cronard ?? [], $this->applications)); } public function getCLI() : array { - return array_merge(...array_map(fn($app) => $app->cli ?? [], $this->applications)); + return array_merge(...array_map(fn(Application $app) => $app->cli ?? [], $this->applications)); } public function getEvents() : array { - return array_merge(...array_map(fn($app) => $app->events ?? [], $this->applications)); + return array_merge(...array_map(fn(Application $app) => $app->events ?? [], $this->applications)); } public function getTaxusPrivileges() : array { - return array_merge(...array_map(fn($app) => $app->taxus ?? [], $this->applications)); + return array_merge(...array_map(fn(Application $app) => $app->taxus ?? [], $this->applications)); } public function getEntities() : array { - return array_merge(...array_map(fn($app) => $app->entities ?? [], $this->applications)); + return array_merge(...array_map(fn(Application $app) => $app->entities ?? [], $this->applications)); + } + + public function getConnectionAdapters() : array + { + return array_merge(...array_map(fn(Application $app) => $app->connectionAdapters ?? [], $this->applications)); } public function getViewPaths() : array { - $list = array_merge(...array_map(fn($app) => $app->views ?? [], $this->applications)); + $list = array_merge(...array_map(fn(Application $app) => $app->views ?? [], $this->applications)); $this->verifyPathList($list); @@ -118,7 +123,7 @@ class Lean public function getAssetPaths() : array { - $list = array_merge(...array_map(fn($app) => $app->piceaAssets ?? [], $this->applications)); + $list = array_merge(...array_map(fn(Application $app) => $app->piceaAssets ?? [], $this->applications)); $this->verifyPathList($list); @@ -140,11 +145,11 @@ class Lean { switch($reader) { case "php": - $list = array_merge(...array_map(fn($app) => $app->tellPhp ?? [], $this->applications)); + $list = array_merge(...array_map(fn(Application $app) => $app->tellPhp ?? [], $this->applications)); break; case "json": - $list = array_merge(...array_map(fn($app) => $app->tellJson ?? [], $this->applications)); + $list = array_merge(...array_map(fn(Application $app) => $app->tellJson ?? [], $this->applications)); break; } From 156defddc9789b56d5f070dab2ca21e7ac31478d Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Mon, 19 May 2025 17:29:52 +0000 Subject: [PATCH 2/3] - WIP on Lean's event definition --- meta/definitions/event.php | 17 ++++++++++++----- src/ControllerTrait.php | 4 ++-- src/Event/RoutingMapRoutes.php | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/meta/definitions/event.php b/meta/definitions/event.php index 7cb85dc..5cfa378 100644 --- a/meta/definitions/event.php +++ b/meta/definitions/event.php @@ -1,8 +1,6 @@ autowire(Event\EventManager::class), @@ -25,6 +26,7 @@ return [ Event\EventDefinition::class => function($c) { $extension = $c->has(\Picea\Extension\UrlExtension::class) ? $c->get(\Picea\Extension\UrlExtension::class) : null; + $user = $c->get(UserInterface::class); return new Event\EventDefinition([ new class($extension) implements RoutingCompileRoutes { @@ -40,7 +42,12 @@ return [ } }, - new class() implements RoutingMapRoutes { + new class($user) implements RoutingMapRoutes { + + public function __construct( + protected UserInterface $user + ) {} + public function execute(Routing $routing, ContainerInterface $container, ServerRequestInterface & $request, Route $attribute) : void { $class = $attribute->class; @@ -54,7 +61,7 @@ return [ $securityHandler = $container->get(SecurityHandler::class); if ( $redirect = $securityHandler->verify($class, $method) ) { - if ( empty($object->user) || ! $object->user->logged ) { + if (! $this->user->loggedIn() ) { if ($container->has(Session::class)) { $container->get(Session::class)->set('redirectedFrom', (string)$request->getUri()); } @@ -65,7 +72,7 @@ return [ } if ( $securityHandler->isLocked($class, $method) && $container->has(Taxus::class)) { - if ( $forbidden = $securityHandler->taxus($class, $method, $object->user ?? null) ) { + if ( $forbidden = $securityHandler->taxus($class, $method, $this->user) ) { $routing->response = $forbidden; return; diff --git a/src/ControllerTrait.php b/src/ControllerTrait.php index 6a7feb5..265267d 100644 --- a/src/ControllerTrait.php +++ b/src/ControllerTrait.php @@ -20,8 +20,8 @@ use function file_get_contents; #[Route(method: [ "GET", "POST" ])] trait ControllerTrait { - #[Inject] - public \Notes\Breadcrumb\Breadcrumb $breadcrumb; + ##[Inject] + # public \Notes\Breadcrumb\Breadcrumb $breadcrumb; #[Inject] public Session $session; diff --git a/src/Event/RoutingMapRoutes.php b/src/Event/RoutingMapRoutes.php index e448574..eda90cf 100644 --- a/src/Event/RoutingMapRoutes.php +++ b/src/Event/RoutingMapRoutes.php @@ -6,6 +6,7 @@ use Lean\Routing; use Notes\Route\Attribute\Method\Route; use Psr\Container\ContainerInterface; use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface }; +use Ulmus\User\Entity\UserInterface; interface RoutingMapRoutes { public function execute(Routing $routing, ContainerInterface $container, ServerRequestInterface & $request, Route $attribute) : void; From 7a48d707e0bf5c80a46a50a77796f1dbee2e0859 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Mon, 26 May 2025 18:19:43 +0000 Subject: [PATCH 3/3] - Reworked ApplicationStrategy to allows better overridding of it's classes --- meta/definitions/http.php | 3 + src/ApplicationStrategy.php | 56 ++++------------- src/ApplicationStrategy/NotFoundDecorator.php | 62 +++++++++++++++++++ .../NotFoundDecoratorInterface.php | 10 +++ src/ApplicationStrategy/ThrowableHandler.php | 22 +++++++ .../ThrowableHandlerInterface.php | 10 +++ 6 files changed, 118 insertions(+), 45 deletions(-) create mode 100644 src/ApplicationStrategy/NotFoundDecorator.php create mode 100644 src/ApplicationStrategy/NotFoundDecoratorInterface.php create mode 100644 src/ApplicationStrategy/ThrowableHandler.php create mode 100644 src/ApplicationStrategy/ThrowableHandlerInterface.php diff --git a/meta/definitions/http.php b/meta/definitions/http.php index 9c6db73..1ae4f7d 100644 --- a/meta/definitions/http.php +++ b/meta/definitions/http.php @@ -1,5 +1,6 @@ create(SapiEmitter::class), + ThrowableHandlerInterface::class => autowire(ThrowableHandler::class), + NotFoundDecoratorInterface::class => autowire(NotFoundDecorator::class), ]; diff --git a/src/ApplicationStrategy.php b/src/ApplicationStrategy.php index 2d3263f..7c55b3b 100644 --- a/src/ApplicationStrategy.php +++ b/src/ApplicationStrategy.php @@ -3,66 +3,32 @@ namespace Lean; use League\Route\Strategy; - use League\Route\Http\Exception\NotFoundException; +use Lean\ApplicationStrategy\NotFoundDecoratorInterface; +use Lean\ApplicationStrategy\ThrowableHandlerInterface; use Lean\Factory\HttpFactoryInterface; -use Picea\Asset\Asset; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; -use Picea\Picea; use Psr\Http\Server\RequestHandlerInterface; use function DI\get; class ApplicationStrategy extends Strategy\ApplicationStrategy { - public const ASSET_TRIGGER_UPDATE = [ - "js", "mjs", "manifest", "webmanifest", "css", "png", "ico", - "jpg", "jpeg", "gif", "webp", "woff", "woff2", "eot", "svg", - "ttf" - ]; - public function __construct( - protected Picea $picea, - protected ContainerInterface $di, - protected HttpFactoryInterface $httpFactory, - ) {} + ContainerInterface $di, + ) { + $this->setContainer($di); + } public function getNotFoundDecorator(NotFoundException $exception): MiddlewareInterface { - return new class($this->picea, $this->di, $this->httpFactory) implements MiddlewareInterface { + return $this->getContainer()->get(NotFoundDecoratorInterface::class); + } - public function __construct( - protected Picea $picea, - protected ContainerInterface $di, - protected HttpFactoryInterface $httpFactory, - ) { } - - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface - { - if (php_sapi_name() !== 'cli' and ! defined('STDIN')) { - return $this->throw404($request); - } - - return $handler->handle($request);; - } - - public function throw404(ServerRequestInterface $request) : ResponseInterface - { - if ( getenv('DEBUG') && $this->di->has(\Picea\Asset\Asset::class) ) { - $params = $request->getServerParams(); - - $scpName = basename(explode('?', $params['REQUEST_URI'] ?? "", 2)[0]); - list(, $ext) = array_pad(explode('.', $scpName), 2, null); - - if ($ext && in_array($ext, ApplicationStrategy::ASSET_TRIGGER_UPDATE)) { - $this->di->get(\Picea\Asset\Asset::class)->launchInstall(); - } - } - - return $this->httpFactory->createHtmlResponse($this->picea->renderHtml("lean/error/404", [], $this), 404); - } - }; + public function getThrowableHandler(): MiddlewareInterface + { + return $this->getContainer()->get(ThrowableHandlerInterface::class); } } \ No newline at end of file diff --git a/src/ApplicationStrategy/NotFoundDecorator.php b/src/ApplicationStrategy/NotFoundDecorator.php new file mode 100644 index 0000000..706dd70 --- /dev/null +++ b/src/ApplicationStrategy/NotFoundDecorator.php @@ -0,0 +1,62 @@ +throw404($request); + } + + return $handler->handle($request);; + } + + public function throw404(ServerRequestInterface $request) : ResponseInterface + { + return $this->checkAssetTrigger($request) ?: $this->httpFactory->createHtmlResponse($this->picea->renderHtml("lean/error/404", [], $this), 404); + } + + protected function checkAssetTrigger(ServerRequestInterface $request) : false|ResponseInterface + { + if (getenv('DEBUG') && $this->container->has(\Picea\Asset\Asset::class)) { + $params = $request->getServerParams(); + + $scpName = basename(explode('?', $params['REQUEST_URI'] ?? "", 2)[0]); + list(, $ext) = array_pad(explode('.', $scpName), 2, null); + + if ($ext && in_array($ext, static::ASSET_TRIGGER_UPDATE)) { + $this->container->get(\Picea\Asset\Asset::class)->launchInstall(); + + return $this->httpFactory->createTextResponse("Asset updated"); + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/ApplicationStrategy/NotFoundDecoratorInterface.php b/src/ApplicationStrategy/NotFoundDecoratorInterface.php new file mode 100644 index 0000000..530c657 --- /dev/null +++ b/src/ApplicationStrategy/NotFoundDecoratorInterface.php @@ -0,0 +1,10 @@ +handle($request); + } catch (Throwable $e) { + throw $e; + } + } +} \ No newline at end of file diff --git a/src/ApplicationStrategy/ThrowableHandlerInterface.php b/src/ApplicationStrategy/ThrowableHandlerInterface.php new file mode 100644 index 0000000..1ebdc54 --- /dev/null +++ b/src/ApplicationStrategy/ThrowableHandlerInterface.php @@ -0,0 +1,10 @@ +