From e974f9bb9f9a53b5c3430ea9662faf02c4766a51 Mon Sep 17 00:00:00 2001 From: Alex-DA Date: Tue, 13 Dec 2022 11:22:43 +0100 Subject: [PATCH] add microkernel for api --- .../Module/Api/Request/RequestDTOFactory.php | 46 +++++ .../Api/Request/RequestDTOInterface.php | 6 + core/src/Module/Api/Response/JsonResponse.php | 9 + .../Module/Api/Response/JsonResponse400.php | 18 ++ .../Module/Api/Response/JsonResponse401.php | 17 ++ .../Module/Api/Response/JsonResponse403.php | 17 ++ .../Module/Api/Response/JsonResponse404.php | 17 ++ .../Errors/UserNotAuthenticatedException.php | 8 + .../Doctrine/MongoDB/TraitCreatedAt.php | 27 +++ core/src/Module/Routing/Method.php | 9 + core/src/Module/Routing/Route.php | 15 ++ core/src/Module/Routing/RoutesInterface.php | 10 ++ core/src/Module/Symfony/BaseKernel.php | 165 ++++++++++++++++++ core/src/Module/Symfony/Route.php | 20 +++ 14 files changed, 384 insertions(+) create mode 100644 core/src/Module/Api/Request/RequestDTOFactory.php create mode 100644 core/src/Module/Api/Request/RequestDTOInterface.php create mode 100644 core/src/Module/Api/Response/JsonResponse.php create mode 100644 core/src/Module/Api/Response/JsonResponse400.php create mode 100644 core/src/Module/Api/Response/JsonResponse401.php create mode 100644 core/src/Module/Api/Response/JsonResponse403.php create mode 100644 core/src/Module/Api/Response/JsonResponse404.php create mode 100644 core/src/Module/Auth/Errors/UserNotAuthenticatedException.php create mode 100644 core/src/Module/Doctrine/MongoDB/TraitCreatedAt.php create mode 100644 core/src/Module/Routing/Method.php create mode 100644 core/src/Module/Routing/Route.php create mode 100644 core/src/Module/Routing/RoutesInterface.php create mode 100644 core/src/Module/Symfony/BaseKernel.php create mode 100644 core/src/Module/Symfony/Route.php diff --git a/core/src/Module/Api/Request/RequestDTOFactory.php b/core/src/Module/Api/Request/RequestDTOFactory.php new file mode 100644 index 0000000..5ba02a0 --- /dev/null +++ b/core/src/Module/Api/Request/RequestDTOFactory.php @@ -0,0 +1,46 @@ +requestStack->getCurrentRequest(); + $requestFromJson = $this->deserializeJsonToRequestDTO( + (string) $request?->getContent(), + $dtoName, + ); + + return $requestFromJson; + } + + protected function deserializeJsonToRequestDTO( + string $jsonData, + string $classNameRequest, + ): RequestDTOInterface { + $encoders = [new JsonEncoder()]; + $normalizers = [new ObjectNormalizer()]; + $serializer = new Serializer($normalizers, $encoders); + + // Serializer throw an error on empty JSON + if (empty($jsonData)) { + $jsonData = "[]"; + } + + /** @var RequestDTOInterface $jsonRequest */ + $jsonRequest = $serializer->deserialize( + $jsonData, + $classNameRequest, + "json", + ); + + return $jsonRequest; + } +} diff --git a/core/src/Module/Api/Request/RequestDTOInterface.php b/core/src/Module/Api/Request/RequestDTOInterface.php new file mode 100644 index 0000000..43ef830 --- /dev/null +++ b/core/src/Module/Api/Request/RequestDTOInterface.php @@ -0,0 +1,6 @@ + "Bad Request", + "errors" => $errors, + ], + 400, + ); + } +} diff --git a/core/src/Module/Api/Response/JsonResponse401.php b/core/src/Module/Api/Response/JsonResponse401.php new file mode 100644 index 0000000..42791d7 --- /dev/null +++ b/core/src/Module/Api/Response/JsonResponse401.php @@ -0,0 +1,17 @@ + "Auth Required", + ], + 401, + ); + } +} diff --git a/core/src/Module/Api/Response/JsonResponse403.php b/core/src/Module/Api/Response/JsonResponse403.php new file mode 100644 index 0000000..7589719 --- /dev/null +++ b/core/src/Module/Api/Response/JsonResponse403.php @@ -0,0 +1,17 @@ + "Forbidden", + ], + 403, + ); + } +} diff --git a/core/src/Module/Api/Response/JsonResponse404.php b/core/src/Module/Api/Response/JsonResponse404.php new file mode 100644 index 0000000..3ac6074 --- /dev/null +++ b/core/src/Module/Api/Response/JsonResponse404.php @@ -0,0 +1,17 @@ + "Not Found", + ], + 404, + ); + } +} diff --git a/core/src/Module/Auth/Errors/UserNotAuthenticatedException.php b/core/src/Module/Auth/Errors/UserNotAuthenticatedException.php new file mode 100644 index 0000000..2c95f3c --- /dev/null +++ b/core/src/Module/Auth/Errors/UserNotAuthenticatedException.php @@ -0,0 +1,8 @@ +created_at; + } + + #[PrePersist] + public function prePersistCreatedAt(LifecycleEventArgs $eventArgs): void { + $this->created_at = new CarbonImmutable(); + } +} diff --git a/core/src/Module/Routing/Method.php b/core/src/Module/Routing/Method.php new file mode 100644 index 0000000..6d5ef18 --- /dev/null +++ b/core/src/Module/Routing/Method.php @@ -0,0 +1,9 @@ +routes)) { + return $this->routes; + } + + $registerRoutes = $this->getRouters(); + + foreach ($registerRoutes as $classWithRoutes) { + /** @var RoutesInterface $routesContainer */ + $routesContainer = new $classWithRoutes(); + $routes = $routesContainer->getRoutes(); + array_push($this->routes, ...$routes); + + unset($routesContainer, $routes); + } + + return $this->routes; + } + + /** + * @psalm-suppress UndefinedClass + */ + protected function configureContainer( + ContainerConfigurator $container, + ): void { + $this->configureSymfonyContainer($container); + + $registerModules = $this->getModules(); + + foreach ($registerModules as $moduleProvider) { + $module = new $moduleProvider(); + $module->register($container->services()); + unset($module); + } + + $this->registerControllerActions($container); + $this->registerRequestDTOs($container); + } + + protected function registerControllerActions( + ContainerConfigurator $container, + ): void { + foreach ($this->getRoutersModule() as $route) { + $container + ->services() + ->set($route->controllerAction) + ->autowire() + ->tag("controller.service_arguments"); + + unset($route); + } + } + + protected function registerRequestDTOs( + ContainerConfigurator $container, + ): void { + $container + ->services() + ->set(RequestDTOFactory::class) + ->autowire(); + + foreach ($this->getRoutersModule() as $route) { + if (empty($route->requestDTO)) { + continue; + } + + $container + ->services() + ->set($route->requestDTO) + ->factory(service(RequestDTOFactory::class)) + ->args([$route->requestDTO]); + + unset($route); + } + } + + protected function configureRoutes(RoutingConfigurator $routes): void { + $this->configureSymfonyRoutes($routes); + + foreach ($this->getRoutersModule() as $route) { + $routes + ->add($route->name, $route->path) + ->controller($route->controllerAction) + ->methods($route->methods); + + unset($route); + } + } + + /** + * @psalm-suppress UnresolvableInclude + */ + protected function configureSymfonyContainer( + ContainerConfigurator $container, + ): void { + $rootFolder = $this->getRootFolder(); + + $container->import("../config/{packages}/*.yaml"); + $container->import( + "../config/{packages}/" . $this->environment . "/*.yaml", + ); + + if (is_file($rootFolder . "/config/services.yaml")) { + $container->import("../config/services.yaml"); + $container->import( + "../config/{services}_" . $this->environment . ".yaml", + ); + } elseif (is_file($path = $rootFolder . "/config/services.php")) { + // @phpstan-ignore-next-line + require $path($container->withPath($path), $this); + } + } + + /** + * @psalm-suppress UnresolvableInclude + */ + protected function configureSymfonyRoutes(RoutingConfigurator $routes): void { + $rootFolder = $this->getRootFolder(); + + $routes->import("../config/{routes}/" . $this->environment . "/*.yaml"); + $routes->import("../config/{routes}/*.yaml"); + + if (is_file($rootFolder . "/config/routes.yaml")) { + $routes->import("../config/routes.yaml"); + } elseif (is_file($path = $rootFolder . "/config/routes.php")) { + // @phpstan-ignore-next-line + require $path($routes->withPath($path), $this); + } + } +} diff --git a/core/src/Module/Symfony/Route.php b/core/src/Module/Symfony/Route.php new file mode 100644 index 0000000..428b8c2 --- /dev/null +++ b/core/src/Module/Symfony/Route.php @@ -0,0 +1,20 @@ +routes = $routes; + } + + abstract public function register(): void; +}