diff --git a/src/Admin/src/ConfigProvider.php b/src/Admin/src/ConfigProvider.php index 12d9a01..21deafd 100644 --- a/src/Admin/src/ConfigProvider.php +++ b/src/Admin/src/ConfigProvider.php @@ -22,6 +22,7 @@ use Api\Admin\Service\AdminService; use Api\Admin\Service\AdminServiceInterface; use Api\App\ConfigProvider as AppConfigProvider; +use Api\App\Factory\HandlerDelegatorFactory; use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Dot\DependencyInjection\Factory\AttributedRepositoryFactory; use Dot\DependencyInjection\Factory\AttributedServiceFactory; @@ -43,25 +44,28 @@ public function getDependencies(): array { return [ 'delegators' => [ - Application::class => [ - RoutesDelegator::class, - ], + Application::class => [RoutesDelegator::class], + AdminAccountHandler::class => [HandlerDelegatorFactory::class], + AdminCollectionHandler::class => [HandlerDelegatorFactory::class], + AdminHandler::class => [HandlerDelegatorFactory::class], + AdminRoleCollectionHandler::class => [HandlerDelegatorFactory::class], + AdminRoleHandler::class => [HandlerDelegatorFactory::class], ], 'factories' => [ - AdminHandler::class => AttributedServiceFactory::class, - AdminCollectionHandler::class => AttributedServiceFactory::class, AdminAccountHandler::class => AttributedServiceFactory::class, - AdminRoleHandler::class => AttributedServiceFactory::class, - AdminRoleCollectionHandler::class => AttributedServiceFactory::class, - AdminService::class => AttributedServiceFactory::class, - AdminRoleService::class => AttributedServiceFactory::class, + AdminCollectionHandler::class => AttributedServiceFactory::class, AdminCreateCommand::class => AdminCreateCommandFactory::class, + AdminHandler::class => AttributedServiceFactory::class, AdminRepository::class => AttributedRepositoryFactory::class, + AdminRoleCollectionHandler::class => AttributedServiceFactory::class, + AdminRoleHandler::class => AttributedServiceFactory::class, AdminRoleRepository::class => AttributedRepositoryFactory::class, + AdminRoleService::class => AttributedServiceFactory::class, + AdminService::class => AttributedServiceFactory::class, ], 'aliases' => [ - AdminServiceInterface::class => AdminService::class, AdminRoleServiceInterface::class => AdminRoleService::class, + AdminServiceInterface::class => AdminService::class, ], ]; } diff --git a/src/Admin/src/Handler/AdminAccountHandler.php b/src/Admin/src/Handler/AdminAccountHandler.php index fd8f76f..74bb3af 100644 --- a/src/Admin/src/Handler/AdminAccountHandler.php +++ b/src/Admin/src/Handler/AdminAccountHandler.php @@ -10,26 +10,17 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\ConflictException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AdminAccountHandler implements RequestHandlerInterface +class AdminAccountHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, AdminServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected AdminServiceInterface $adminService, ) { } diff --git a/src/Admin/src/Handler/AdminCollectionHandler.php b/src/Admin/src/Handler/AdminCollectionHandler.php index 8d8b487..81f3b2d 100644 --- a/src/Admin/src/Handler/AdminCollectionHandler.php +++ b/src/Admin/src/Handler/AdminCollectionHandler.php @@ -6,26 +6,17 @@ use Api\Admin\Service\AdminServiceInterface; use Api\App\Exception\BadRequestException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AdminCollectionHandler implements RequestHandlerInterface +class AdminCollectionHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, AdminServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected AdminServiceInterface $adminService, ) { } diff --git a/src/Admin/src/Handler/AdminHandler.php b/src/Admin/src/Handler/AdminHandler.php index 2a57133..822afb8 100644 --- a/src/Admin/src/Handler/AdminHandler.php +++ b/src/Admin/src/Handler/AdminHandler.php @@ -10,26 +10,17 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\ConflictException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AdminHandler implements RequestHandlerInterface +class AdminHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, AdminServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected AdminServiceInterface $adminService, ) { } diff --git a/src/Admin/src/Handler/AdminRoleCollectionHandler.php b/src/Admin/src/Handler/AdminRoleCollectionHandler.php index d4e5536..d230e3e 100644 --- a/src/Admin/src/Handler/AdminRoleCollectionHandler.php +++ b/src/Admin/src/Handler/AdminRoleCollectionHandler.php @@ -6,26 +6,17 @@ use Api\Admin\Service\AdminRoleServiceInterface; use Api\App\Exception\BadRequestException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AdminRoleCollectionHandler implements RequestHandlerInterface +class AdminRoleCollectionHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, AdminRoleServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected AdminRoleServiceInterface $roleService, ) { } diff --git a/src/Admin/src/Handler/AdminRoleHandler.php b/src/Admin/src/Handler/AdminRoleHandler.php index 18b377a..0a73c90 100644 --- a/src/Admin/src/Handler/AdminRoleHandler.php +++ b/src/Admin/src/Handler/AdminRoleHandler.php @@ -6,26 +6,17 @@ use Api\Admin\Service\AdminRoleServiceInterface; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AdminRoleHandler implements RequestHandlerInterface +class AdminRoleHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, AdminRoleServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected AdminRoleServiceInterface $roleService, ) { } diff --git a/src/App/src/ConfigProvider.php b/src/App/src/ConfigProvider.php index 07ca4c6..7b8fb5b 100644 --- a/src/App/src/ConfigProvider.php +++ b/src/App/src/ConfigProvider.php @@ -9,10 +9,10 @@ use Api\App\Entity\EntityListenerResolver; use Api\App\Factory\AuthenticationMiddlewareFactory; use Api\App\Factory\EntityListenerResolverFactory; +use Api\App\Factory\HandlerDelegatorFactory; use Api\App\Factory\RouteListCommandFactory; use Api\App\Factory\TokenGenerateCommandFactory; use Api\App\Handler\ErrorReportHandler; -use Api\App\Handler\HomeHandler; use Api\App\Middleware\AuthenticationMiddleware; use Api\App\Middleware\AuthorizationMiddleware; use Api\App\Middleware\ContentNegotiationMiddleware; @@ -57,9 +57,8 @@ public function getDependencies(): array { return [ 'delegators' => [ - Application::class => [ - RoutesDelegator::class, - ], + Application::class => [RoutesDelegator::class], + ErrorReportHandler::class => [HandlerDelegatorFactory::class], ], 'factories' => [ 'doctrine.entity_manager.orm_default' => EntityManagerFactory::class, @@ -69,24 +68,23 @@ public function getDependencies(): array AuthorizationMiddleware::class => AttributedServiceFactory::class, ContentNegotiationMiddleware::class => AttributedServiceFactory::class, DeprecationMiddleware::class => AttributedServiceFactory::class, + EntityListenerResolver::class => EntityListenerResolverFactory::class, Environment::class => TwigEnvironmentFactory::class, - TwigExtension::class => TwigExtensionFactory::class, - TwigRenderer::class => TwigRendererFactory::class, - HomeHandler::class => AttributedServiceFactory::class, ErrorReportHandler::class => AttributedServiceFactory::class, + ErrorReportService::class => AttributedServiceFactory::class, ErrorResponseMiddleware::class => AttributedServiceFactory::class, RouteListCommand::class => RouteListCommandFactory::class, TokenGenerateCommand::class => TokenGenerateCommandFactory::class, - ErrorReportService::class => AttributedServiceFactory::class, - EntityListenerResolver::class => EntityListenerResolverFactory::class, + TwigExtension::class => TwigExtensionFactory::class, + TwigRenderer::class => TwigRendererFactory::class, ], 'aliases' => [ Authentication\AuthenticationInterface::class => Authentication\OAuth2\OAuth2Adapter::class, - MailService::class => 'dot-mail.service.default', EntityManager::class => 'doctrine.entity_manager.orm_default', EntityManagerInterface::class => 'doctrine.entity_manager.orm_default', - TemplateRendererInterface::class => TwigRenderer::class, ErrorReportServiceInterface::class => ErrorReportService::class, + MailService::class => 'dot-mail.service.default', + TemplateRendererInterface::class => TwigRenderer::class, ], ]; } diff --git a/src/App/src/Entity/AbstractEntity.php b/src/App/src/Entity/AbstractEntity.php index d38d053..d70a01d 100644 --- a/src/App/src/Entity/AbstractEntity.php +++ b/src/App/src/Entity/AbstractEntity.php @@ -14,7 +14,7 @@ use function ucfirst; #[ORM\MappedSuperclass] -abstract class AbstractEntity implements ArraySerializableInterface +abstract class AbstractEntity implements ArraySerializableInterface, EntityInterface { #[ORM\Id] #[ORM\Column(name: 'uuid', type: "uuid_binary", unique: true)] diff --git a/src/App/src/Entity/EntityInterface.php b/src/App/src/Entity/EntityInterface.php new file mode 100644 index 0000000..c519b99 --- /dev/null +++ b/src/App/src/Entity/EntityInterface.php @@ -0,0 +1,9 @@ +has(HalResponseFactory::class)) { + throw new RuntimeException(sprintf(Message::SERVICE_NOT_FOUND, HalResponseFactory::class)); + } + if (! $container->has(ResourceGenerator::class)) { + throw new RuntimeException(sprintf(Message::SERVICE_NOT_FOUND, ResourceGenerator::class)); + } + + $handler = $callback(); + assert($handler instanceof AbstractHandler); + + return $handler + ->setResponseFactory($container->get(HalResponseFactory::class)) + ->setResourceGenerator($container->get(ResourceGenerator::class)); + } +} diff --git a/src/App/src/Handler/AbstractHandler.php b/src/App/src/Handler/AbstractHandler.php new file mode 100644 index 0000000..3c3ba5b --- /dev/null +++ b/src/App/src/Handler/AbstractHandler.php @@ -0,0 +1,145 @@ +getMethod()); + if (! method_exists($this, $method)) { + throw new MethodNotAllowedException(Message::METHOD_NOT_ALLOWED); + } + + return $this->$method($request); + } catch (ConflictException $exception) { + return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_CONFLICT); + } catch (ForbiddenException $exception) { + return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_FORBIDDEN); + } catch (ExpiredException $exception) { + return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_GONE); + } catch (OutOfBoundsException | NotFoundException $exception) { + return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_NOT_FOUND); + } catch (UnauthorizedException $exception) { + return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_UNAUTHORIZED); + } catch (MethodNotAllowedException $exception) { + return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED); + } catch (BadRequestException $exception) { + return $this->errorResponse($exception->getMessages(), StatusCodeInterface::STATUS_BAD_REQUEST); + } catch (MailException | RuntimeException | Exception $exception) { + return $this->errorResponse($exception->getMessage()); + } + } + + public function setResponseFactory(HalResponseFactory $responseFactory): self + { + $this->responseFactory = $responseFactory; + + return $this; + } + + public function setResourceGenerator(ResourceGenerator $resourceGenerator): self + { + $this->resourceGenerator = $resourceGenerator; + + return $this; + } + + public function emptyResponse(int $status = StatusCodeInterface::STATUS_NO_CONTENT): ResponseInterface + { + return new EmptyResponse($status, ['Content-Type' => 'text/plain']); + } + + public function jsonResponse( + array|string $messages = [], + int $status = StatusCodeInterface::STATUS_OK + ): ResponseInterface { + return new JsonResponse($messages, $status); + } + + public function createResponse( + ServerRequestInterface $request, + CollectionInterface|EntityInterface $instance + ): ResponseInterface { + assert($this->responseFactory instanceof HalResponseFactory); + assert($this->resourceGenerator instanceof ResourceGenerator); + + return $this->responseFactory->createResponse( + $request, + $this->resourceGenerator->fromObject($instance, $request) + ); + } + + public function createdResponse(ServerRequestInterface $request, EntityInterface $instance): ResponseInterface + { + $response = $this->createResponse($request, $instance); + + return $response->withStatus(StatusCodeInterface::STATUS_CREATED); + } + + public function noContentResponse(): ResponseInterface + { + return $this->emptyResponse(); + } + + public function notFoundResponse(): ResponseInterface + { + return $this->emptyResponse(StatusCodeInterface::STATUS_NOT_FOUND); + } + + public function errorResponse( + array|string $messages = [], + int $status = StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR + ): ResponseInterface { + return $this->jsonResponse([ + 'error' => [ + 'messages' => is_array($messages) ? $messages : [$messages], + ], + ], $status); + } + + public function infoResponse( + array|string $messages = [], + int $status = StatusCodeInterface::STATUS_OK + ): ResponseInterface { + return $this->jsonResponse([ + 'info' => [ + 'messages' => is_array($messages) ? $messages : [$messages], + ], + ], $status); + } +} diff --git a/src/App/src/Handler/ErrorReportHandler.php b/src/App/src/Handler/ErrorReportHandler.php index a687139..b65ff41 100644 --- a/src/App/src/Handler/ErrorReportHandler.php +++ b/src/App/src/Handler/ErrorReportHandler.php @@ -11,25 +11,16 @@ use Api\App\Service\ErrorReportServiceInterface; use Dot\DependencyInjection\Attribute\Inject; use Fig\Http\Message\StatusCodeInterface; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; -class ErrorReportHandler implements RequestHandlerInterface +class ErrorReportHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, ErrorReportServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected ErrorReportServiceInterface $errorReportService, ) { } diff --git a/src/App/src/Handler/HandlerTrait.php b/src/App/src/Handler/HandlerTrait.php deleted file mode 100644 index 7e1b5f4..0000000 --- a/src/App/src/Handler/HandlerTrait.php +++ /dev/null @@ -1,62 +0,0 @@ -getMethod()); - if (! method_exists($this, $method)) { - throw new MethodNotAllowedException( - sprintf('Method %s is not implemented for the requested resource.', $method) - ); - } - - return $this->$method($request); - } catch (ConflictException $exception) { - return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_CONFLICT); - } catch (ForbiddenException $exception) { - return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_FORBIDDEN); - } catch (ExpiredException $exception) { - return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_GONE); - } catch (OutOfBoundsException | NotFoundException $exception) { - return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_NOT_FOUND); - } catch (UnauthorizedException $exception) { - return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_UNAUTHORIZED); - } catch (MethodNotAllowedException $exception) { - return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED); - } catch (BadRequestException $exception) { - return $this->errorResponse($exception->getMessages(), StatusCodeInterface::STATUS_BAD_REQUEST); - } catch (MailException | RuntimeException | Exception $exception) { - return $this->errorResponse($exception->getMessage()); - } - } -} diff --git a/src/App/src/Handler/HomeHandler.php b/src/App/src/Handler/HomeHandler.php index ace153a..3567376 100644 --- a/src/App/src/Handler/HomeHandler.php +++ b/src/App/src/Handler/HomeHandler.php @@ -5,31 +5,15 @@ namespace Api\App\Handler; use Api\App\Attribute\ResourceDeprecation; -use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Server\RequestHandlerInterface; #[ResourceDeprecation( sunset: '2038-01-01', link: 'https://docs.dotkernel.org/api-documentation/v5/core-features/versioning', deprecationReason: 'Resource deprecation example.', )] -class HomeHandler implements RequestHandlerInterface +class HomeHandler extends AbstractHandler { - use HandlerTrait; - - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, - )] - public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, - ) { - } - public function get(): ResponseInterface { return $this->jsonResponse(['message' => 'DotKernel API version 5']); diff --git a/src/App/src/Handler/NotFoundHandler.php b/src/App/src/Handler/NotFoundHandler.php index cd4ff15..c108ad7 100644 --- a/src/App/src/Handler/NotFoundHandler.php +++ b/src/App/src/Handler/NotFoundHandler.php @@ -6,12 +6,9 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class NotFoundHandler implements RequestHandlerInterface +class NotFoundHandler extends AbstractHandler { - use HandlerTrait; - public function handle(ServerRequestInterface $request): ResponseInterface { return $this->notFoundResponse(); diff --git a/src/App/src/Handler/ResponseTrait.php b/src/App/src/Handler/ResponseTrait.php deleted file mode 100644 index 09c7d72..0000000 --- a/src/App/src/Handler/ResponseTrait.php +++ /dev/null @@ -1,90 +0,0 @@ - 'text/plain']); - } - - public function jsonResponse( - array|string $messages = [], - int $status = StatusCodeInterface::STATUS_OK - ): ResponseInterface { - return new JsonResponse($messages, $status); - } - - public function createResponse(ServerRequestInterface $request, mixed $instance): ResponseInterface - { - return $this->responseFactory->createResponse( - $request, - $this->resourceGenerator->fromObject($instance, $request) - ); - } - - public function createdResponse(ServerRequestInterface $request, mixed $instance): ResponseInterface - { - $response = $this->createResponse($request, $instance); - - return $response->withStatus(StatusCodeInterface::STATUS_CREATED); - } - - public function noContentResponse(): ResponseInterface - { - return $this->emptyResponse(); - } - - public function notFoundResponse(): ResponseInterface - { - return $this->emptyResponse(StatusCodeInterface::STATUS_NOT_FOUND); - } - - public function errorResponse( - array|string $messages = [], - int $status = StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR - ): ResponseInterface { - return $this->jsonResponse([ - 'error' => [ - 'messages' => is_array($messages) ? $messages : [$messages], - ], - ], $status); - } - - public function infoResponse( - array|string $messages = [], - int $status = StatusCodeInterface::STATUS_OK - ): ResponseInterface { - return $this->jsonResponse([ - 'info' => [ - 'messages' => is_array($messages) ? $messages : [$messages], - ], - ], $status); - } - - public function notAcceptableResponse(string $message): ResponseInterface - { - return $this->errorResponse($message, StatusCodeInterface::STATUS_NOT_ACCEPTABLE); - } - - public function unsupportedMediaTypeResponse(string $message): ResponseInterface - { - return $this->errorResponse($message, StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE); - } -} diff --git a/src/App/src/Message.php b/src/App/src/Message.php index 68a6734..5e5f67e 100644 --- a/src/App/src/Message.php +++ b/src/App/src/Message.php @@ -24,6 +24,7 @@ class Message public const MAIL_SENT_RESET_PASSWORD = 'If the provided email identifies an account in our system, ' . 'you will receive an email with further instructions on resetting your account\'s password.'; public const MAIL_SENT_USER_ACTIVATION = 'User activation mail has been successfully sent to \'%s\''; + public const METHOD_NOT_ALLOWED = 'The request method is not supported for the requested resource.'; public const MISSING_CONFIG = 'Missing configuration value: \'%s\'.'; public const RESET_PASSWORD_EXPIRED = 'Password reset request for hash: \'%s\' is invalid (expired).'; public const RESET_PASSWORD_NOT_FOUND = 'Could not find password reset request identified by hash: \'%s\''; @@ -35,6 +36,7 @@ class Message public const RESTRICTION_IMAGE = 'File must be an image (jpg, png).'; public const RESTRICTION_ROLES = 'User accounts must have at least one role.'; public const ROLE_NOT_FOUND = 'Role not found.'; + public const SERVICE_NOT_FOUND = 'Service %s not found in container.'; public const USER_ACTIVATED = 'This account has been activated.'; public const USER_ALREADY_ACTIVATED = 'This account is already active.'; public const USER_NOT_ACTIVATED = 'User account must be activated first.'; diff --git a/src/App/src/Middleware/ContentNegotiationMiddleware.php b/src/App/src/Middleware/ContentNegotiationMiddleware.php index 7d51390..f12325f 100644 --- a/src/App/src/Middleware/ContentNegotiationMiddleware.php +++ b/src/App/src/Middleware/ContentNegotiationMiddleware.php @@ -4,8 +4,9 @@ namespace Api\App\Middleware; -use Api\App\Handler\ResponseTrait; use Dot\DependencyInjection\Attribute\Inject; +use Fig\Http\Message\StatusCodeInterface; +use Laminas\Diactoros\Response\JsonResponse; use Mezzio\Router\RouteResult; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -22,15 +23,13 @@ use function strtok; use function trim; -class ContentNegotiationMiddleware implements MiddlewareInterface +readonly class ContentNegotiationMiddleware implements MiddlewareInterface { - use ResponseTrait; - #[Inject( "config.content-negotiation", )] public function __construct( - private readonly array $config, + private array $config, ) { } @@ -133,4 +132,14 @@ public function validateResponseContentType(?string $contentType, array $accept) return in_array($contentType, $accept, true); } + + public function notAcceptableResponse(string $message): ResponseInterface + { + return new JsonResponse(['messages' => [$message]], StatusCodeInterface::STATUS_NOT_ACCEPTABLE); + } + + public function unsupportedMediaTypeResponse(string $message): ResponseInterface + { + return new JsonResponse(['messages' => [$message]], StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE); + } } diff --git a/src/App/src/Middleware/DeprecationMiddleware.php b/src/App/src/Middleware/DeprecationMiddleware.php index 914df50..4dd8923 100644 --- a/src/App/src/Middleware/DeprecationMiddleware.php +++ b/src/App/src/Middleware/DeprecationMiddleware.php @@ -7,7 +7,6 @@ use Api\App\Attribute\MethodDeprecation; use Api\App\Attribute\ResourceDeprecation; use Api\App\Exception\DeprecationConflictException; -use Api\App\Handler\ResponseTrait; use Api\App\Message; use Dot\DependencyInjection\Attribute\Inject; use Laminas\Stratigility\MiddlewarePipe; @@ -35,8 +34,6 @@ class DeprecationMiddleware implements MiddlewareInterface { - use ResponseTrait; - public const RESOURCE_DEPRECATION_ATTRIBUTE = ResourceDeprecation::class; public const METHOD_DEPRECATION_ATTRIBUTE = MethodDeprecation::class; @@ -45,9 +42,12 @@ class DeprecationMiddleware implements MiddlewareInterface self::METHOD_DEPRECATION_ATTRIBUTE, ]; - #[Inject("config.application.versioning")] - public function __construct(protected readonly array $config) - { + #[Inject( + "config.application.versioning", + )] + public function __construct( + protected readonly array $config, + ) { } /** diff --git a/src/User/src/ConfigProvider.php b/src/User/src/ConfigProvider.php index 976326b..e1d6a55 100644 --- a/src/User/src/ConfigProvider.php +++ b/src/User/src/ConfigProvider.php @@ -5,6 +5,7 @@ namespace Api\User; use Api\App\ConfigProvider as AppConfigProvider; +use Api\App\Factory\HandlerDelegatorFactory; use Api\User\Collection\UserCollection; use Api\User\Collection\UserRoleCollection; use Api\User\Entity\User; @@ -55,31 +56,40 @@ public function getDependencies(): array { return [ 'delegators' => [ - Application::class => [ - RoutesDelegator::class, - ], + Application::class => [RoutesDelegator::class], + AccountActivateHandler::class => [HandlerDelegatorFactory::class], + AccountAvatarHandler::class => [HandlerDelegatorFactory::class], + AccountHandler::class => [HandlerDelegatorFactory::class], + AccountRecoveryHandler::class => [HandlerDelegatorFactory::class], + AccountResetPasswordHandler::class => [HandlerDelegatorFactory::class], + UserActivateHandler::class => [HandlerDelegatorFactory::class], + UserAvatarHandler::class => [HandlerDelegatorFactory::class], + UserCollectionHandler::class => [HandlerDelegatorFactory::class], + UserHandler::class => [HandlerDelegatorFactory::class], + UserRoleCollectionHandler::class => [HandlerDelegatorFactory::class], + UserRoleHandler::class => [HandlerDelegatorFactory::class], ], 'factories' => [ AccountActivateHandler::class => AttributedServiceFactory::class, AccountAvatarHandler::class => AttributedServiceFactory::class, AccountHandler::class => AttributedServiceFactory::class, - AccountResetPasswordHandler::class => AttributedServiceFactory::class, AccountRecoveryHandler::class => AttributedServiceFactory::class, + AccountResetPasswordHandler::class => AttributedServiceFactory::class, UserActivateHandler::class => AttributedServiceFactory::class, - UserAvatarHandler::class => AttributedServiceFactory::class, UserAvatarEventListener::class => AttributedServiceFactory::class, - UserHandler::class => AttributedServiceFactory::class, + UserAvatarHandler::class => AttributedServiceFactory::class, UserCollectionHandler::class => AttributedServiceFactory::class, - UserRoleHandler::class => AttributedServiceFactory::class, + UserHandler::class => AttributedServiceFactory::class, UserRoleCollectionHandler::class => AttributedServiceFactory::class, + UserRoleHandler::class => AttributedServiceFactory::class, UserService::class => AttributedServiceFactory::class, UserRoleService::class => AttributedServiceFactory::class, UserAvatarService::class => AttributedServiceFactory::class, - UserRepository::class => AttributedRepositoryFactory::class, + UserAvatarRepository::class => AttributedRepositoryFactory::class, UserDetailRepository::class => AttributedRepositoryFactory::class, + UserRepository::class => AttributedRepositoryFactory::class, UserResetPasswordRepository::class => AttributedRepositoryFactory::class, UserRoleRepository::class => AttributedRepositoryFactory::class, - UserAvatarRepository::class => AttributedRepositoryFactory::class, ], 'aliases' => [ UserAvatarServiceInterface::class => UserAvatarService::class, diff --git a/src/User/src/Handler/AccountActivateHandler.php b/src/User/src/Handler/AccountActivateHandler.php index cdd1275..bc5f514 100644 --- a/src/User/src/Handler/AccountActivateHandler.php +++ b/src/User/src/Handler/AccountActivateHandler.php @@ -7,33 +7,24 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\ConflictException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\User\InputFilter\ActivateAccountInputFilter; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; use Dot\Mail\Exception\MailException; use Fig\Http\Message\StatusCodeInterface; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; use function sprintf; -class AccountActivateHandler implements RequestHandlerInterface +class AccountActivateHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/AccountAvatarHandler.php b/src/User/src/Handler/AccountAvatarHandler.php index 1bfa700..dd54efb 100644 --- a/src/User/src/Handler/AccountAvatarHandler.php +++ b/src/User/src/Handler/AccountAvatarHandler.php @@ -6,30 +6,21 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\User\Entity\User; use Api\User\InputFilter\UpdateAvatarInputFilter; use Api\User\Service\UserAvatarServiceInterface; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AccountAvatarHandler implements RequestHandlerInterface +class AccountAvatarHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserAvatarServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserAvatarServiceInterface $userAvatarService, ) { } diff --git a/src/User/src/Handler/AccountHandler.php b/src/User/src/Handler/AccountHandler.php index 89567b9..935a2d0 100644 --- a/src/User/src/Handler/AccountHandler.php +++ b/src/User/src/Handler/AccountHandler.php @@ -7,32 +7,23 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\ConflictException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\User\Entity\User; use Api\User\InputFilter\CreateUserInputFilter; use Api\User\InputFilter\UpdateUserInputFilter; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; use Dot\Mail\Exception\MailException; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; -class AccountHandler implements RequestHandlerInterface +class AccountHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/AccountRecoveryHandler.php b/src/User/src/Handler/AccountRecoveryHandler.php index fef7d3c..6722501 100644 --- a/src/User/src/Handler/AccountRecoveryHandler.php +++ b/src/User/src/Handler/AccountRecoveryHandler.php @@ -6,30 +6,21 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\User\InputFilter\RecoverIdentityInputFilter; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; use Dot\Mail\Exception\MailException; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class AccountRecoveryHandler implements RequestHandlerInterface +class AccountRecoveryHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/AccountResetPasswordHandler.php b/src/User/src/Handler/AccountResetPasswordHandler.php index f3af021..d389fe9 100644 --- a/src/User/src/Handler/AccountResetPasswordHandler.php +++ b/src/User/src/Handler/AccountResetPasswordHandler.php @@ -8,7 +8,7 @@ use Api\App\Exception\ConflictException; use Api\App\Exception\ExpiredException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\User\Entity\User; use Api\User\InputFilter\ResetPasswordInputFilter; @@ -17,26 +17,17 @@ use Dot\DependencyInjection\Attribute\Inject; use Dot\Mail\Exception\MailException; use Fig\Http\Message\StatusCodeInterface; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; use function sprintf; -class AccountResetPasswordHandler implements RequestHandlerInterface +class AccountResetPasswordHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/UserActivateHandler.php b/src/User/src/Handler/UserActivateHandler.php index 27e67f1..8b6e546 100644 --- a/src/User/src/Handler/UserActivateHandler.php +++ b/src/User/src/Handler/UserActivateHandler.php @@ -6,29 +6,20 @@ use Api\App\Exception\ConflictException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; use Dot\Mail\Exception\MailException; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class UserActivateHandler implements RequestHandlerInterface +class UserActivateHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/UserAvatarHandler.php b/src/User/src/Handler/UserAvatarHandler.php index 0c2cb1e..75879de 100644 --- a/src/User/src/Handler/UserAvatarHandler.php +++ b/src/User/src/Handler/UserAvatarHandler.php @@ -6,31 +6,22 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\User\InputFilter\UpdateAvatarInputFilter; use Api\User\Service\UserAvatarServiceInterface; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class UserAvatarHandler implements RequestHandlerInterface +class UserAvatarHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, UserAvatarServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, protected UserAvatarServiceInterface $userAvatarService, ) { diff --git a/src/User/src/Handler/UserCollectionHandler.php b/src/User/src/Handler/UserCollectionHandler.php index dfa94f4..50f0869 100644 --- a/src/User/src/Handler/UserCollectionHandler.php +++ b/src/User/src/Handler/UserCollectionHandler.php @@ -5,27 +5,18 @@ namespace Api\User\Handler; use Api\App\Exception\BadRequestException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class UserCollectionHandler implements RequestHandlerInterface +class UserCollectionHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/UserHandler.php b/src/User/src/Handler/UserHandler.php index 490dcb4..5a9124b 100644 --- a/src/User/src/Handler/UserHandler.php +++ b/src/User/src/Handler/UserHandler.php @@ -7,31 +7,22 @@ use Api\App\Exception\BadRequestException; use Api\App\Exception\ConflictException; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\User\InputFilter\CreateUserInputFilter; use Api\User\InputFilter\UpdateUserInputFilter; use Api\User\Service\UserServiceInterface; use Dot\DependencyInjection\Attribute\Inject; use Dot\Mail\Exception\MailException; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; -class UserHandler implements RequestHandlerInterface +class UserHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserServiceInterface $userService, ) { } diff --git a/src/User/src/Handler/UserRoleCollectionHandler.php b/src/User/src/Handler/UserRoleCollectionHandler.php index 10df222..91f60bf 100644 --- a/src/User/src/Handler/UserRoleCollectionHandler.php +++ b/src/User/src/Handler/UserRoleCollectionHandler.php @@ -5,27 +5,18 @@ namespace Api\User\Handler; use Api\App\Exception\BadRequestException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\User\Service\UserRoleServiceInterface; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class UserRoleCollectionHandler implements RequestHandlerInterface +class UserRoleCollectionHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserRoleServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserRoleServiceInterface $roleService, ) { } diff --git a/src/User/src/Handler/UserRoleHandler.php b/src/User/src/Handler/UserRoleHandler.php index d7599b9..66417dc 100644 --- a/src/User/src/Handler/UserRoleHandler.php +++ b/src/User/src/Handler/UserRoleHandler.php @@ -5,27 +5,18 @@ namespace Api\User\Handler; use Api\App\Exception\NotFoundException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\User\Service\UserRoleServiceInterface; use Dot\DependencyInjection\Attribute\Inject; -use Mezzio\Hal\HalResponseFactory; -use Mezzio\Hal\ResourceGenerator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -class UserRoleHandler implements RequestHandlerInterface +class UserRoleHandler extends AbstractHandler { - use HandlerTrait; - #[Inject( - HalResponseFactory::class, - ResourceGenerator::class, UserRoleServiceInterface::class, )] public function __construct( - protected HalResponseFactory $responseFactory, - protected ResourceGenerator $resourceGenerator, protected UserRoleServiceInterface $roleService, ) { } diff --git a/test/Unit/App/Middleware/DeprecationMiddlewareTest.php b/test/Unit/App/Middleware/DeprecationMiddlewareTest.php index e293dfa..77a8bf4 100644 --- a/test/Unit/App/Middleware/DeprecationMiddlewareTest.php +++ b/test/Unit/App/Middleware/DeprecationMiddlewareTest.php @@ -7,7 +7,7 @@ use Api\App\Attribute\MethodDeprecation; use Api\App\Attribute\ResourceDeprecation; use Api\App\Exception\DeprecationConflictException; -use Api\App\Handler\HandlerTrait; +use Api\App\Handler\AbstractHandler; use Api\App\Message; use Api\App\Middleware\DeprecationMiddleware as Subject; use Fig\Http\Message\RequestMethodInterface; @@ -213,9 +213,7 @@ public function process( */ public function testDeprecationMethodUsesRequestMethod(): void { - $handler = new class implements RequestHandlerInterface { - use HandlerTrait; - + $handler = new class extends AbstractHandler { #[MethodDeprecation( sunset: '2038-01-01', link: 'get-test-link',