diff --git a/README.md b/README.md index 40bab8016958f90876a45dce68fac4454d7d1314..69499896270150ef8293127b56b7b81624fdb2a6 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ advantage of the asynchronous environment. #[Singleton(collection: SingletonCollection::HttpResponder)] readonly class Homepage implements HttpResponderInterface { - public function respond(Request $request, Response $response): TwigTemplate + public function respond(ServerRequestInterface $request, ResponseInterface $response): TwigTemplate { - return new TwigTemplate('website/homepage.twig'); + return new TwigTemplate($request, $response, 'website/homepage.twig'); } } ``` diff --git a/docs/pages/docs/changelog/index.md b/docs/pages/docs/changelog/index.md index 69c6deafb7f5c243cd6297f599f89748cf512a74..25423c3aec061340b5622ac96d14c590d5c7fd69 100644 --- a/docs/pages/docs/changelog/index.md +++ b/docs/pages/docs/changelog/index.md @@ -81,5 +81,5 @@ title: Changelog ## v0.10.0 - Added {{docs/features/security/oauth2/index}} support. -- Added {{docs/features/http/psr-http-messages}} wrapper. +- Added PSR Http Messages wrapper. - Added `EntityManagerWeakReference` to {{docs/features/database/doctrine/index}} integration. diff --git a/docs/pages/docs/features/configuration/index.md b/docs/pages/docs/features/configuration/index.md index f76d7da90f138427b80f1d0a6d1b27f75c60b9c5..54dbbd2a025fe77ec10c52a053af6b8dcbbbae1f 100644 --- a/docs/pages/docs/features/configuration/index.md +++ b/docs/pages/docs/features/configuration/index.md @@ -283,8 +283,8 @@ use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -310,12 +310,15 @@ final readonly class Manifest extends HttpResponder ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } - public function respond(Request $request, Response $response): ?HttpResponderInterface + public function respond( + ServerRequestInterface $request, + ResponseInterface $response, + ): ResponseInterface { - $response->header('content-type', ContentType::ApplicationJson->value); - $response->end($this->manifest); - - return null; + return $response + ->withHeader('content-type', ContentType::ApplicationJson->value) + ->withBody($this->createStream($this->manifest)) + ; } } ``` diff --git a/docs/pages/docs/features/database/doctrine/entities.md b/docs/pages/docs/features/database/doctrine/entities.md index d927fb5e8ef313fa0135730adabd097473b220ad..ee6c758c1141d292629018912912b8ecd78ca697 100644 --- a/docs/pages/docs/features/database/doctrine/entities.md +++ b/docs/pages/docs/features/database/doctrine/entities.md @@ -55,6 +55,8 @@ use Distantmagic\Resonance\HttpResponder\HttpController; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -64,7 +66,9 @@ use Distantmagic\Resonance\TwigTemplate; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class BlogPostShow extends HttpController { - public function handle( + public function createResponse( + ServerRequestInterface $request, + ResponseInterface $response, #[DoctrineEntityRouteParameter( from: 'blog_post_slug', intent: CrudAction::Read, @@ -72,9 +76,14 @@ final readonly class BlogPostShow extends HttpController )] BlogPost $blogPost, ): HttpInterceptableInterface { - return new TwigTemplate('turbo/website/blog_post.twig', [ - 'blog_post' => $blogPost, - ]); + return new TwigTemplate( + $request, + $response, + 'turbo/website/blog_post.twig', + [ + 'blog_post' => $blogPost, + ], + ); } } ``` diff --git a/docs/pages/docs/features/database/doctrine/entity-managers.md b/docs/pages/docs/features/database/doctrine/entity-managers.md index 4e2ea6ce5de740c85ea494b8ef8883e5a1c81ed2..f25c5c154f5a88e375870f22ef3b7ed69e5846cb 100644 --- a/docs/pages/docs/features/database/doctrine/entity-managers.md +++ b/docs/pages/docs/features/database/doctrine/entity-managers.md @@ -90,8 +90,8 @@ use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -105,15 +105,23 @@ final readonly class Blog extends HttpResponder private DoctrineEntityManagerRepository $doctrineEntityManagerRepository, ) {} - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond( + ServerRequestInterface $request, + ResponseInterface $response, + ): HttpInterceptableInterface { $entityManager = $this->doctrineEntityManagerRepository->getEntityManager($request); $blogPostsRepository = $entityManager->getRepository(BlogPost::class); - return new TwigTemplate('turbo/website/blog.twig', [ - 'blog_posts' => $blogPostsRepository->findAll(), - ]); + return new TwigTemplate( + $request, + $response, + 'turbo/website/blog.twig', + [ + 'blog_posts' => $blogPostsRepository->findAll(), + ] + ); } } ``` @@ -147,6 +155,8 @@ use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -156,15 +166,22 @@ use Doctrine\ORM\EntityRepository; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class Blog extends HttpController { - public function handle( + public function createResponse( + ServerRequestInterface $request, + ResponseInterface $response, #[DoctrineEntityManager] EntityManager $entityManager, #[DoctrineEntityRepository(BlogPost::class)] EntityRepository $blogPosts, ): HttpInterceptableInterface { - return new TwigTemplate('website/blog.twig', [ - 'blog_posts' => $blogPosts->findAll(), - ]); + return new TwigTemplate( + $request, + $response, + 'website/blog.twig', + [ + 'blog_posts' => $blogPosts->findAll(), + ] + ); } } ``` diff --git a/docs/pages/docs/features/graphql/developing-schema.md b/docs/pages/docs/features/graphql/developing-schema.md index 72c7faf8c23226643dae447a0554414e128e8f33..33c5efdfd293359d172d13bad696c24667e54fab 100644 --- a/docs/pages/docs/features/graphql/developing-schema.md +++ b/docs/pages/docs/features/graphql/developing-schema.md @@ -27,6 +27,7 @@ GraphQL handler. namespace App\HttpResponder; +use App\HttpRouteSymbol; use Distantmagic\Resonance\Attribute\RespondsToHttp; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\HttpResponder; @@ -34,9 +35,8 @@ use Distantmagic\Resonance\HttpResponder\GraphQL as ResonanceGraphQL; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; -use App\HttpRouteSymbol; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -48,7 +48,7 @@ final readonly class GraphQL extends HttpResponder { public function __construct(private ResonanceGraphQL $graphql) {} - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return $this->graphql; } diff --git a/docs/pages/docs/features/http/controllers.md b/docs/pages/docs/features/http/controllers.md index 34797557119da4b1d9cfe7e4d3c8697fa69b0b28..e1d0d29609b28fb77ed4abb94cc90a3abba40e74 100644 --- a/docs/pages/docs/features/http/controllers.md +++ b/docs/pages/docs/features/http/controllers.md @@ -22,7 +22,8 @@ Controllers aim to automate these repetitive tasks as much as possible. ## Writing Controllers Unlike {{docs/features/http/responders}}, Controllers do not use the `respond` -method. Instead, they rely on the `handle` method to manage incoming requests. +method. Instead, they rely on the `createResponse` method to manage incoming +requests. The `respond` method is used internally for handling tasks like parameter binding, so you should not override it. @@ -52,8 +53,8 @@ Using the `RouteParameter` might require to create a Crud Gate. See more at the {{docs/features/security/authorization/index}} page. ::: -Remember that the framework resolves parameters assigned to the `handle` method -on runtime during the request lifecycle. +Remember that the framework resolves parameters assigned to the +`createResponse` method on runtime during the request lifecycle. The above is contrary to the constructor arguments, which the framework resolves during the application bootstrap phase thanks to the @@ -78,7 +79,7 @@ use Distantmagic\Resonance\HttpResponder\HttpController; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -88,13 +89,13 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class BlogPostShow extends HttpController { - public function handle( + public function createResponse( #[RouteParameter( from: 'blog_post_slug', intent: CrudAction::Read, )] BlogPost $blogPost, - Response $response, + ResponseInterface $response, ): HttpResponderInterface { // ... } @@ -142,8 +143,8 @@ final readonly class BlogPostBinder implements HttpRouteParameterBinderInterface ### Providing the Authenticated User (Session) If you need to fetch the authenticated user in your controller, you can add -a parameter with the `#[SessionAuthenticated]` attribute to the `handle` -method. +a parameter with the `#[SessionAuthenticated]` attribute to the +`createResponse` method. The controller fetches an authenticated user through {{docs/features/http/sessions}}. @@ -162,7 +163,6 @@ use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\UserInterface; -use Swoole\Http\Response; #[RespondsToHttp( method: RequestMethod::GET, @@ -172,7 +172,7 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class MyController extends HttpController { - public function handle( + public function createResponse( // If you make this parameter required, then the framework will // return 403 page when user is unauthenticated. #[SessionAuthenticated] @@ -201,8 +201,8 @@ use Distantmagic\Resonance\HttpControllerParameterResolution; use Distantmagic\Resonance\HttpControllerParameterResolutionStatus; use Distantmagic\Resonance\HttpControllerParameterResolver; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; /** * @template-extends HttpControllerParameterResolver<MyAttribute> @@ -212,8 +212,8 @@ use Swoole\Http\Response; readonly class RouteParameterResolver extends HttpControllerParameterResolver { public function resolve( - Request $request, - Response $response, + ServerRequestInterface $request, + ResponseInterface $response, HttpControllerParameter $httpControllerParameter, Attribute $attribute, ): HttpControllerParameterResolution { @@ -248,7 +248,7 @@ readonly class MyHttpController extends HttpController parent::__construct($httpControllerDependencies); } - public function handle() + public function createResponse() { // ... } diff --git a/docs/pages/docs/features/http/interceptors.md b/docs/pages/docs/features/http/interceptors.md index b85a39b4ee0696779de08c8b3db89824670eec3e..3179659fcabd443b9b22477a2bcb3de18c12f769 100644 --- a/docs/pages/docs/features/http/interceptors.md +++ b/docs/pages/docs/features/http/interceptors.md @@ -105,8 +105,8 @@ use Distantmagic\Resonance\HttpInterceptableInterface; use Distantmagic\Resonance\HttpInterceptor; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; /** * @template-extends HttpInterceptor<Hello> @@ -116,14 +116,14 @@ use Swoole\Http\Response; readonly class HelloInterceptor extends HttpInterceptor { public function intercept( - Request $request, - Response $response, + ServerRequestInterface $request, + ResponseInterface $response, object $intercepted, ): HttpInterceptableInterface|HttpResponderInterface { - $response->header('content-type', 'text/plain'); - $response->end('Hello, '.$intercepted->message.'!'); - - return null; + return $response + ->withHeader('content-type', 'text/plain') + ->withBody($this->createStream('Hello, '.$intercepted->message.'!')) + ; } } ``` @@ -143,8 +143,8 @@ use Distantmagic\Resonance\HttpInterceptableInterface; use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -154,7 +154,7 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class HelloResponder extends HttpResponder { - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { return new Hello('World'); } diff --git a/docs/pages/docs/features/http/middleware.md b/docs/pages/docs/features/http/middleware.md index 8fbbe351ff7164b81e0fd2a7f13dde27410d9dd8..b2845dedf5eae9b659ccedf92da26c4f9f22fa2e 100644 --- a/docs/pages/docs/features/http/middleware.md +++ b/docs/pages/docs/features/http/middleware.md @@ -92,13 +92,15 @@ use Distantmagic\Resonance\Attribute\ValidatesCSRFToken; #[ValidatesCSRFToken] final readonly class BlogPostDestroy extends HttpController { - public function handle( + public function createResponse( + ServerRequestInterface $request, + ResponseInterface $response, #[RouteParameter(from: 'blog_post_slug', intent: CrudAction::Delete)] BlogPost $blogPost, ): HttpInterceptableInterface { // ... - return new InternalRedirect(HttpRouteSymbol::Blog); + return new InternalRedirect($request, $response, HttpRouteSymbol::Blog); } } @@ -161,8 +163,8 @@ use Distantmagic\Resonance\HttpInterceptableInterface; use Distantmagic\Resonance\HttpMiddleware; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; /** * @template-extends HttpMiddleware<MyAttribute> @@ -175,8 +177,8 @@ use Swoole\Http\Response; readonly class CanMiddleware extends HttpMiddleware { public function preprocess( - Request $request, - Response $response, + ServerRequestInterface $request, + ResponseInterface $response, Attribute $attribute, HttpInterceptableInterface|HttpResponderInterface $next, ): HttpInterceptableInterface|HttpResponderInterface { diff --git a/docs/pages/docs/features/http/psr-http-messages.md b/docs/pages/docs/features/http/psr-http-messages.md deleted file mode 100644 index ed4d9f79b6c45ceb54eb95bc7ef03fee6543aee0..0000000000000000000000000000000000000000 --- a/docs/pages/docs/features/http/psr-http-messages.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -collections: - - documents -layout: dm:document -parent: docs/features/http/index -title: PSR HTTP Messages -description: > - Learn how to convert Swoole server requests to PSR server requests. ---- - -# PSR HTTP Messages - -If you need to convert Swoole's HTTP Request object to it's -[PSR counterpart](https://www.php-fig.org/psr/psr-7/) you can use the -converters. - -# Usage - -## Swoole Request -> PSR Server Request - -You should only convert requests if you need to use some third-party library -that relies on them. Primarily because PSR requests do not provide any -additional features, it's just for standardization. Conversion between request -formats hinders the performance. - -`PsrServerRequestConverter` can/should also be used as a singleton. - -```php -/** - * @var Distantmagic\Resonance\PsrServerRequestConverter $psrServerRequestRepository - * @var Swoole\Http\Request $request - * @var Psr\Http\Message\ServerRequestInterface $psrRequest - */ -$psrRequest = $psrServerRequestRepository->convertToServerRequest($request); -``` - -## PSR Response -> Swoole Response - -If you want to respond with PSR response, you need to wrap it in -`PsrResponder`: - -```php -use Distantmagic\Resonance\HttpResponder; -use Distantmagic\Resonance\HttpResponderInterface; -use Distantmagic\Resonance\HttpResponder\PsrResponder; -use Psr\Http\Message\ResponseInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; - -readonly class MyResponder extends HttpResponder -{ - public function respond(Request $request, Response $response): HttpResponderInterface - { - // (...) obtain psr response somehow - - /** - * @var ResponseInterface $psrResponse - */ - return new PsrResponder($psrResponse); - } -} -``` diff --git a/docs/pages/docs/features/http/responders.md b/docs/pages/docs/features/http/responders.md index d82305c90315ca19cc1cc88a9404de1a6862e88d..81c6cda206656365e322ddc1c7a23472ef665e6d 100644 --- a/docs/pages/docs/features/http/responders.md +++ b/docs/pages/docs/features/http/responders.md @@ -58,8 +58,8 @@ use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -69,11 +69,9 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class Homepage implements HttpResponderInterface { - public function respond(Request $request, Response $response): ?HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { - $response->end('Hello, world!'); - - return null; + return $response->withBody($this->createStream('Hello, world!')); } } ``` @@ -90,14 +88,14 @@ For example: use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\HttpResponder\Redirect; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; class MyResponder implements HttpResponderInterface { // (...) - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return new Redirect('/blog'); } @@ -110,18 +108,16 @@ You can even use anonymous classes: <?php use Distantmagic\Resonance\HttpResponderInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; class MyResponder implements HttpResponderInterface { public function respond(Request $request, Response $response): ?HttpResponderInterface { return new class implements HttpResponderInterface { - public function respond (Request $request, Response $response): null { - $response->end('Hello!'); - - return null; + public function respond (ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { + return $response->withBody($this->createStream('Hello!')); } }; } diff --git a/docs/pages/docs/features/http/serving-assets.md b/docs/pages/docs/features/http/serving-assets.md index 00b457117ef70e55da95c69538f69daee78b4dc1..b62649dd671121a1020b48ae9466aa14bbb3d345 100644 --- a/docs/pages/docs/features/http/serving-assets.md +++ b/docs/pages/docs/features/http/serving-assets.md @@ -47,8 +47,8 @@ use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\HttpRouteMatchRegistry; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -66,7 +66,7 @@ final readonly class Asset extends HttpResponder private HttpRouteMatchRegistry $routeMatchRegistry, ) {} - public function respond(Request $request, Response $response): ?HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface|ResponseInterface { return $this->assetFileRegistry->sendAsset( $response, diff --git a/docs/pages/docs/features/http/sessions.md b/docs/pages/docs/features/http/sessions.md index 7c42d17ffd523d806b891c28a98ce6c2f5b28742..9fe4a773aec89a902f3b76b2689c212457a007a7 100644 --- a/docs/pages/docs/features/http/sessions.md +++ b/docs/pages/docs/features/http/sessions.md @@ -77,10 +77,10 @@ The typical usage follows the 'start -> modify -> persist' pattern: * `$sessionManager->start()` also sets the session cookie in the response. * * @var Resonance\Session $session - * @var Swoole\Http\Request $request + * @var Psr\Http\Message\ServerRequestInterface $request * @var Swoole\Http\Response $response */ -$session = $sessionManager->start($request, $response); +$session = $sessionManager->start($request); /** * Anything that is serializable by igbinary can be used as a value. diff --git a/docs/pages/docs/features/openapi/exposing-schema/index.md b/docs/pages/docs/features/openapi/exposing-schema/index.md index fb121c0064a07476b0b355588a58fea74ab7484d..11b933b9169e3b4638c074b1515815c97dc1b9aa 100644 --- a/docs/pages/docs/features/openapi/exposing-schema/index.md +++ b/docs/pages/docs/features/openapi/exposing-schema/index.md @@ -34,8 +34,8 @@ use Distantmagic\Resonance\OpenAPISchemaBuilder; use Distantmagic\Resonance\OpenAPISchemaSymbol; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -51,7 +51,7 @@ readonly class OpenAPISchema implements HttpResponderInterface $this->schema = $openAPISchemaBuilder->toJsonResponse(OpenAPISchemaSymbol::All); } - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return $this->schema; } diff --git a/docs/pages/docs/features/security/authentication/index.md b/docs/pages/docs/features/security/authentication/index.md index 72a9eb23a90c8f324d296fb9ba7f7ecd208d5069..a8a0e053137682a3a0028ec6cde3a78f05ca2a79 100644 --- a/docs/pages/docs/features/security/authentication/index.md +++ b/docs/pages/docs/features/security/authentication/index.md @@ -56,7 +56,7 @@ final readonly class LoginValidation extends HttpController parent::__construct($controllerDependencies); } - public function handle(Request $request, Response $response): HttpInterceptableInterface { + public function createResponse(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { $user = /* obtain user somehow */; $this->sessionAuthentication->setAuthenticatedUser( @@ -65,7 +65,7 @@ final readonly class LoginValidation extends HttpController $user, ); - return new InternalRedirect(HttpRouteSymbol::Homepage); + return new InternalRedirect($request, $response, HttpRouteSymbol::Homepage); } } ``` @@ -112,7 +112,7 @@ final readonly class MyController extends HttpController /** * @param ?UserInterface $user null if not authenticated */ - public function handle( + public function createResponse( Request $request, #[SessionAuthenticated] ?UserInterface $user, @@ -133,13 +133,13 @@ use Distantmagic\Resonance\Attribute\ProvidesAuthenticatedUser; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\AuthenticatedUserStoreInterface; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; +use Psr\Http\Message\ServerRequestInterface; #[ProvidesAuthenticatedUser(1200)] #[Singleton(collection: SingletonCollection::AuthenticatedUserStore)] readonly class MyAuthentication implements AuthenticatedUserStoreInterface { - public function getAuthenticatedUser(Request $request): ?AuthenticatedUser + public function getAuthenticatedUser(ServerRequestInterface $request): ?AuthenticatedUser { // ... } @@ -158,7 +158,7 @@ use Distantmagic\Resonance\AuthenticatedUserStoreInterface; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\UserInterface; use League\OAuth2\Client\Provider\GenericProvider; -use Swoole\Http\Request; +use Psr\Http\Message\ServerRequestInterface; use function Swoole\Coroutine\Http\get; @@ -166,7 +166,7 @@ use function Swoole\Coroutine\Http\get; #[Singleton(collection: SingletonCollection::AuthenticatedUserStore)] readonly class MyAuthentication implements AuthenticatedUserStoreInterface { - public function getAuthenticatedUser(Request $request): ?AuthenticatedUser + public function getAuthenticatedUser(ServerRequestInterface $request): ?AuthenticatedUser { $userData = get('https://your-server.example.com/user', [], [ 'Authorization' => sprintf('Bearer %s', $request->cookie['access_token']), diff --git a/docs/pages/docs/features/security/authorization/index.md b/docs/pages/docs/features/security/authorization/index.md index 38ee0fbc0b076560e10bdea55aa6a304471e553e..09fab519ef40acbbf411fa671744d920cd0cb34c 100644 --- a/docs/pages/docs/features/security/authorization/index.md +++ b/docs/pages/docs/features/security/authorization/index.md @@ -105,14 +105,14 @@ You can use `Gatekeeper` in your code to check permissions. For example: use App\BlogPostInterface; use Distantmagic\Resonance\CrudAction; use Distantmagic\Resonance\Gatekeeper; -use Swoole\Http\Request; +use Psr\Http\Message\ServerRequestInterface; readonly class MyClass { public function __construct(private Gatekeeper $gatekeeper) {} public function showBlogPost( - Request $request, + ServerRequestInterface $request, BlogPostInterface $blogPost, ): string { diff --git a/docs/pages/docs/features/security/content-security-policy/index.md b/docs/pages/docs/features/security/content-security-policy/index.md index a9729dbfeac0a08b01aa79b537577f289757ff49..85e775a628ea8d35841d9e6e3aa64c4dc38b8d2b 100644 --- a/docs/pages/docs/features/security/content-security-policy/index.md +++ b/docs/pages/docs/features/security/content-security-policy/index.md @@ -59,7 +59,7 @@ To use nonces manually, you need to use the CSP Nonce Manager: ```php /** * @var \Distantmagic\Resonance\CSPNonceManager $cspNonceManager - * @var \Swoole\Http\Request $request + * @var \Psr\Http\Message\ServerRequestInterface $request */ $cspNonceManager->getRequestNonce($request); ``` diff --git a/docs/pages/docs/features/security/csrf-protection/index.md b/docs/pages/docs/features/security/csrf-protection/index.md index 393de1773ea0d7c0243d32dab66fc311ac453dec..83271a07903fd7a2a36c2b5b2124fe3a1be21bc4 100644 --- a/docs/pages/docs/features/security/csrf-protection/index.md +++ b/docs/pages/docs/features/security/csrf-protection/index.md @@ -103,14 +103,14 @@ response and the `respond` method will not be called. use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\Attribute\ValidatesCSRFToken; use Distantmagic\Resonance\HttpResponderInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[Singleton] #[ValidatesCSRFToken] final readonly class MyResponder implements HttpResponderInterface { - public function respond(Request $request, Response $response): void + public function respond(ServerRequestInterface $request, ResponseInterfaced $response): void { // CSRF token is valid... } @@ -124,24 +124,24 @@ final readonly class MyResponder implements HttpResponderInterface use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\CSRFManager; -use Distantmagic\Resonance\HttpResponderInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Distantmagic\Resonance\HttpResponder; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[Singleton] -final readonly class MyResponder implements HttpResponderInterface +final readonly class MyResponder extends HttpResponder { public function __construct(private CSRFManager $csrfManager) { } - public function respond(Request $request, Response $response): void + public function respond(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { - if (!$this->csrfManager->checkToken($request, $request->post)) { - $response->status(400); - $response->end('Bad Request: CSRF Token is invalid.'); - - return; + if (!$this->csrfManager->checkToken($request, $request->getParsedBody())) { + return $response + ->withStatus(400) + ->withBody($this->createStream('Bad Request: CSRF Token is invalid.')) + ; } // CSRF token is valid... diff --git a/docs/pages/docs/features/security/oauth2/authorization-code-grant/index.md b/docs/pages/docs/features/security/oauth2/authorization-code-grant/index.md index 8d98bd94aa4201b06e7880e342e942ef6df35b1f..4a22204ca39c1df1a3e84b93e72b861ca9fb720c 100644 --- a/docs/pages/docs/features/security/oauth2/authorization-code-grant/index.md +++ b/docs/pages/docs/features/security/oauth2/authorization-code-grant/index.md @@ -85,8 +85,8 @@ use Distantmagic\Resonance\HttpResponder\OAuth2\Authorization; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -98,7 +98,7 @@ final readonly class OAuth2AuthorizationServer extends HttpResponder { public function __construct(private Authorization $authorizationServer) {} - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return $this->authorizationServer; } diff --git a/docs/pages/docs/features/security/oauth2/configuration/index.md b/docs/pages/docs/features/security/oauth2/configuration/index.md index 52f5f61544c7992b1081b991504442dc8dc4d443..b9d70000f7c638c3555a35445fa2f8a0d523b92a 100644 --- a/docs/pages/docs/features/security/oauth2/configuration/index.md +++ b/docs/pages/docs/features/security/oauth2/configuration/index.md @@ -51,8 +51,8 @@ use Distantmagic\Resonance\HttpResponder\OAuth2\AccessToken; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -64,7 +64,7 @@ final readonly class OAuth2AccessToken extends HttpResponder { public function __construct(private AccessToken $accessTokenResponder) {} - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return $this->accessTokenResponder; } @@ -88,8 +88,8 @@ use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\PsrServerRequestConverter; use League\OAuth2\Server\AuthorizationServer as LeagueAuthorizationServer; use Nyholm\Psr7\Factory\Psr17Factory; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[Singleton] readonly class MyOAuth2Server extends HttpResponder @@ -100,7 +100,7 @@ readonly class MyOAuth2Server extends HttpResponder private Psr17Factory $psr17Factory, ) {} - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { /** * Convert Swoole http request to PSR Server request object diff --git a/docs/pages/docs/features/templating/php-templates/index.md b/docs/pages/docs/features/templating/php-templates/index.md index 6ea8cc669e0df95c63d4ddee9c45cd3dafa88db3..7762a3b684a72a72a63c91de2197c360ed1a995b 100644 --- a/docs/pages/docs/features/templating/php-templates/index.md +++ b/docs/pages/docs/features/templating/php-templates/index.md @@ -39,11 +39,11 @@ Template file: ```php <?php -use Distantmagic\Resonance\HttpResponderInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Distantmagic\Resonance\HttpResponder; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; -readonly class MyBlogPostTemplate implements HttpResponderInterface +readonly class MyBlogPostTemplate extends HttpResponder { public function __construct( private string $title, @@ -52,9 +52,9 @@ readonly class MyBlogPostTemplate implements HttpResponderInterface { } - public function respond(Request $request, Response $response): null + public function respond(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { - $response->end(<<<HTML + return $response->with($this->createStream(<<<HTML <html> <head></head> <body> @@ -62,9 +62,7 @@ readonly class MyBlogPostTemplate implements HttpResponderInterface <p>{$this->content}</p> </body> </html> - HTML); - - return null; + HTML)); } } ``` @@ -75,12 +73,12 @@ Responder: <?php use Distantmagic\Resonance\HttpResponderInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; readonly class MyResponder implements HttpResponderInterface { - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return new MyTemplate('title', 'content'); } @@ -103,17 +101,17 @@ kind of performance. ```php <?php -use Distantmagic\Resonance\HttpResponderInterface; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Distantmagic\Resonance\HttpResponder; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; -abstract readonly class MyBaseTemplate implements HttpResponderInterface +abstract readonly class MyBaseTemplate extends HttpResponder { abstract protected function renderBodyContent(Request $request, Response $response): string; - public function respond(Request $request, Response $response): null + public function respond(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { - $response->end(<<<HTML + return $response->withBody($this->createStream(<<<HTML <html> <head></head> <body> @@ -121,9 +119,7 @@ abstract readonly class MyBaseTemplate implements HttpResponderInterface {$this->renderBodyContent($request, $response)} </body> </html> - HTML); - - return null; + HTML)); } } ``` @@ -133,12 +129,12 @@ Then in other pages: ```php <?php -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; readonly class MyBlogPost extends MyBaseTemplate { - protected function renderBodyContent(Request $request, Response $response): string + protected function renderBodyContent(ServerRequestInterface $request, ResponseInterface $response): string { return 'Hello!'; } diff --git a/docs/pages/docs/features/templating/twig/rendering-templates.md b/docs/pages/docs/features/templating/twig/rendering-templates.md index 93d262f301337a6c8d75224f8e5288756e94c639..ab42b7fcbbb4c763b83fdd39b46d1bd518054a4a 100644 --- a/docs/pages/docs/features/templating/twig/rendering-templates.md +++ b/docs/pages/docs/features/templating/twig/rendering-templates.md @@ -27,8 +27,8 @@ use Distantmagic\Resonance\HttpInterceptableInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -38,9 +38,9 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class Twig extends HttpResponder { - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { - return new TwigTemplate('test.twig'); + return new TwigTemplate($request, $response, 'test.twig'); } } ``` diff --git a/docs/pages/docs/features/translations/index.md b/docs/pages/docs/features/translations/index.md index 8040af1aa248fdd91b8ebdf826017d015e259283..1e9dbe9cc99cfdc8f5f0bbc65ebaa11b12e44dbd 100644 --- a/docs/pages/docs/features/translations/index.md +++ b/docs/pages/docs/features/translations/index.md @@ -50,7 +50,7 @@ header). use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\TranslatorBridge; -use Swoole\Http\Request; +use Psr\Http\Message\ServerRequestInterface; #[Singleton] readonly class MyClass @@ -59,7 +59,7 @@ readonly class MyClass { } - public function doSomething(Request $request): string + public function doSomething(ServerRequestInterface $request): string { return $this->translator->trans( $request, diff --git a/docs/pages/docs/features/validation/http-controller-parameters/index.md b/docs/pages/docs/features/validation/http-controller-parameters/index.md index ab9c1deff5d94c2836440517ac564cbc636d7edb..11f7a0736ca36d77b60b6d8dbcb7e87e272e5bd4 100644 --- a/docs/pages/docs/features/validation/http-controller-parameters/index.md +++ b/docs/pages/docs/features/validation/http-controller-parameters/index.md @@ -33,7 +33,7 @@ going to inject the data model into the parameter: ```php // ... -public function handle( +public function createResponse( #[ValidatedRequest(MyValidator::class)] MyValidatedData $data, ) { @@ -82,8 +82,8 @@ use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Ds\Map; use Ds\Set; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -93,7 +93,7 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class BlogPostStore extends HttpController { - public function handle( + public function createResponse( #[ValidatedRequest(BlogPostFormValidator::class)] #[OnParameterResolution( status: HttpControllerParameterResolutionStatus::ValidationErrors, @@ -109,11 +109,11 @@ final readonly class BlogPostStore extends HttpController * @param Map<string,Set<string>> $errors */ public function handleValidationErrors( - Request $request, - Response $response, + ServerRequestInterface $request, + ResponseInterface $response, HttpControllerParameterResolution $resolution, ): HttpResponderInterface { - $response->status(400); + $response = $response->withStatus(400); /* render form with errors */ /* ... */ diff --git a/docs/pages/index.md b/docs/pages/index.md index cd0fc5e27b5d6f6c25ae227f379db64fba690a3a..f532ee2da56514a1da75f65d86a4ff3094174cbe 100644 --- a/docs/pages/index.md +++ b/docs/pages/index.md @@ -202,9 +202,12 @@ final readonly class EchoResponder extends WebSocketRPCResponder #[Singleton(collection: SingletonCollection::HttpResponder)] readonly class Homepage implements HttpResponderInterface { - public function respond(Request $request, Response $response): TwigTemplate + public function respond( + ServerRequestInterface $request, + ResponseInterface $response + ): TwigTemplate { - return new TwigTemplate('website/homepage.twig'); + return new TwigTemplate($request, $response, 'website/homepage.twig'); } }</code></pre> </li> diff --git a/docs/pages/tutorials/basic-graphql-schema/index.md b/docs/pages/tutorials/basic-graphql-schema/index.md index 71c9cfbf3efac632dca7a1acca11e676ec333981..d18508c02c61c83cc90682e25322fdf153c3ba2a 100644 --- a/docs/pages/tutorials/basic-graphql-schema/index.md +++ b/docs/pages/tutorials/basic-graphql-schema/index.md @@ -73,8 +73,8 @@ use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\SiteAction; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -86,7 +86,7 @@ final readonly class GraphQL extends HttpResponder { public function __construct(private ResonanceGraphQL $graphql) {} - public function respond(Request $request, Response $response): HttpResponderInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpResponderInterface { return $this->graphql; } diff --git a/docs/pages/tutorials/hello-world/index.md b/docs/pages/tutorials/hello-world/index.md index 696d334ea865beb6d8165b4772ae046351b2e7fc..ed4684866afc2c4c7c80b8be0bd13cb194cfbfb6 100644 --- a/docs/pages/tutorials/hello-world/index.md +++ b/docs/pages/tutorials/hello-world/index.md @@ -102,8 +102,8 @@ use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -113,9 +113,9 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class Homepage extends HttpResponder { - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { - return new TwigTemplate('homepage.twig'); + return new TwigTemplate($request, $response, 'homepage.twig'); } } ``` @@ -190,8 +190,8 @@ declare(strict_types=1); namespace Distantmagic\Resonance; use Distantmagic\Resonance\Attribute\ContentSecurityPolicy; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[ContentSecurityPolicy(ContentSecurityPolicyType::Html)] final readonly class TwigTemplate implements HttpInterceptableInterface @@ -201,7 +201,7 @@ final readonly class TwigTemplate implements HttpInterceptableInterface private array $templateData = [], ) {} - public function getTemplateData(Request $request, Response $response): array + public function getTemplateData(ServerRequestInterface $request, ResponseInterface $response): array { return $this->templateData + [ 'request' => $request, diff --git a/docs/pages/tutorials/how-to-create-llm-websocket-chat-with-llama-cpp/index.md b/docs/pages/tutorials/how-to-create-llm-websocket-chat-with-llama-cpp/index.md index db9fe2b2e2e6f6a3edbe2178ec43ab7003040801..811698d39274e468141e0e2750a336bba89d3ad1 100644 --- a/docs/pages/tutorials/how-to-create-llm-websocket-chat-with-llama-cpp/index.md +++ b/docs/pages/tutorials/how-to-create-llm-websocket-chat-with-llama-cpp/index.md @@ -98,8 +98,8 @@ use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\SiteAction; use Distantmagic\Resonance\TwigTemplate; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[Can(SiteAction::StartWebSocketRPCConnection)] #[RespondsToHttp( @@ -111,9 +111,9 @@ use Swoole\Http\Response; #[WantsFeature(Feature::WebSocket)] final readonly class LlmChat extends HttpResponder { - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { - return new TwigTemplate('turbo/llmchat/index.twig'); + return new TwigTemplate($request, $response, 'turbo/llmchat/index.twig'); } } ``` diff --git a/docs/pages/tutorials/session-based-authentication/index.md b/docs/pages/tutorials/session-based-authentication/index.md index 0b1f188adc9fe7a2b71b20b031bca181899fe812..7a127abafef1e40a98f124825921a61064d2e71f 100644 --- a/docs/pages/tutorials/session-based-authentication/index.md +++ b/docs/pages/tutorials/session-based-authentication/index.md @@ -159,7 +159,6 @@ use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\DoctrineEntityManagerRepository; use Distantmagic\Resonance\UserInterface; use Distantmagic\Resonance\UserRepositoryInterface; -use Swoole\Http\Request; #[Singleton(provides: UserRepositoryInterface::class)] readonly class UserRepository implements UserRepositoryInterface @@ -243,8 +242,8 @@ use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -254,9 +253,9 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class LoginForm extends HttpResponder { - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { - return new TwigTemplate('auth/login_form.twig'); + return new TwigTemplate($request, $response, 'auth/login_form.twig'); } } ``` @@ -430,8 +429,8 @@ use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; use Doctrine\ORM\EntityRepository; use Ds\Map; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -449,14 +448,14 @@ final readonly class LoginValidation extends HttpController parent::__construct($controllerDependencies); } - public function handle( - Request $request, - Response $response, + public function createResponse( + ServerRequestInterface $request, + ResponseInterface $response, #[ValidatedRequest(UsernamePasswordValidator::class)] UsernamePassword $usernamePassword, #[DoctrineEntityRepository(User::class)] EntityRepository $users, - ): null|HttpInterceptableInterface { + ): HttpInterceptableInterface|ResponseInterface { /** * @var null|User */ @@ -465,9 +464,7 @@ final readonly class LoginValidation extends HttpController ]); if (!$user || !password_verify($usernamePassword->password, $user->getPasswordHash())) { - $response->status(403); - - return; + return $response->withStatus(403); } $this->sessionAuthentication->setAuthenticatedUser( @@ -476,7 +473,7 @@ final readonly class LoginValidation extends HttpController $user->user, ); - return new InternalRedirect(HttpRouteSymbol::Homepage); + return new InternalRedirect($request, $response, HttpRouteSymbol::Homepage); } } ``` @@ -502,8 +499,8 @@ use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Distantmagic\Resonance\TwigTemplate; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, @@ -513,9 +510,9 @@ use Swoole\Http\Response; #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class LogoutForm extends HttpResponder { - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { - return new TwigTemplate('auth/logout_form.twig'); + return new TwigTemplate($request, $response, 'auth/logout_form.twig'); } } ``` @@ -552,8 +549,8 @@ use Distantmagic\Resonance\InternalRedirect; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SessionAuthentication; use Distantmagic\Resonance\SingletonCollection; -use Swoole\Http\Request; -use Swoole\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::POST, @@ -568,13 +565,15 @@ final readonly class LogoutValidation extends HttpResponder private SessionAuthentication $sessionAuthentication, ) {} - public function respond(Request $request, Response $response): HttpInterceptableInterface + public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface { $this->sessionAuthentication->clearAuthenticatedUser($request); - $response->header('clear-site-data', '*'); - - return new InternalRedirect(HttpRouteSymbol::Homepage); + return new InternalRedirect( + $request, + $response->header('clear-site-data', '*'); + HttpRouteSymbol::Homepage, + ); } } ``` diff --git a/src/HttpInterceptor.php b/src/HttpInterceptor.php index 25fa9d2d02bd74cc54c68373b8e64d964ac9e76b..d0aad021b042f22696f938ce4ecfe3945c356fd1 100644 --- a/src/HttpInterceptor.php +++ b/src/HttpInterceptor.php @@ -4,9 +4,18 @@ declare(strict_types=1); namespace Distantmagic\Resonance; +use Psr\Http\Message\StreamInterface; +use Stringable; + /** * @template TClass * * @template-implements HttpInterceptorInterface<TClass> */ -abstract readonly class HttpInterceptor implements HttpInterceptorInterface {} +abstract readonly class HttpInterceptor implements HttpInterceptorInterface +{ + public function createStream(string|Stringable $contents): StreamInterface + { + return new PsrStringStream($contents); + } +} diff --git a/src/HttpMiddleware/ValidatesCSRFTokenMiddleware.php b/src/HttpMiddleware/ValidatesCSRFTokenMiddleware.php index 0e853a8ee53e453421c20c58977577a9a8694ec2..993c4052bd022abbbbad77078ba563c26f6768fb 100644 --- a/src/HttpMiddleware/ValidatesCSRFTokenMiddleware.php +++ b/src/HttpMiddleware/ValidatesCSRFTokenMiddleware.php @@ -5,10 +5,12 @@ declare(strict_types=1); namespace Distantmagic\Resonance\HttpMiddleware; use Distantmagic\Resonance\Attribute; +use Distantmagic\Resonance\Attribute\GrantsFeature; use Distantmagic\Resonance\Attribute\HandlesMiddlewareAttribute; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\Attribute\ValidatesCSRFToken; use Distantmagic\Resonance\CSRFManager; +use Distantmagic\Resonance\Feature; use Distantmagic\Resonance\HttpInterceptableInterface; use Distantmagic\Resonance\HttpMiddleware; use Distantmagic\Resonance\HttpResponder\Error\BadRequest; @@ -21,6 +23,7 @@ use Psr\Http\Message\ServerRequestInterface; /** * @template-extends HttpMiddleware<ValidatesCSRFToken> */ +#[GrantsFeature(Feature::HttpSession)] #[HandlesMiddlewareAttribute( attribute: ValidatesCSRFToken::class, priority: 1100, diff --git a/src/HttpResponder.php b/src/HttpResponder.php index 405288b202e13f5f236754d827f1fbef41227f2f..85b40c6d60c1addc2a536059161472c2c83507f3 100644 --- a/src/HttpResponder.php +++ b/src/HttpResponder.php @@ -4,14 +4,13 @@ declare(strict_types=1); namespace Distantmagic\Resonance; -use LogicException; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; +use Stringable; abstract readonly class HttpResponder implements HttpResponderInterface { - public function handle(ServerRequestInterface $request): ResponseInterface + public function createStream(string|Stringable $contents): StreamInterface { - throw new LogicException('This method should not be called'); + return new PsrStringStream($contents); } } diff --git a/src/HttpResponder/Error/ServerError.php b/src/HttpResponder/Error/ServerError.php index 171ddb5bb122da28c18239868f3b6e9025631c1f..7473ca60a45c43f054b6a8a0223ebf2845befbc7 100644 --- a/src/HttpResponder/Error/ServerError.php +++ b/src/HttpResponder/Error/ServerError.php @@ -13,7 +13,6 @@ use Distantmagic\Resonance\HttpError\ServerError as ServerErrorEntity; use Distantmagic\Resonance\HttpInterceptableInterface; use Distantmagic\Resonance\HttpResponder\Error; use Distantmagic\Resonance\HttpResponderInterface; -use Distantmagic\Resonance\PsrStringStream; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Throwable; @@ -41,7 +40,7 @@ final readonly class ServerError extends Error return $response ->withStatus(500) ->withHeader('content-type', ContentType::TextPlain->value) - ->withBody(new PsrStringStream((string) $throwable)) + ->withBody($this->createStream($throwable)) ; } } diff --git a/src/HttpResponder/Json.php b/src/HttpResponder/Json.php index 3eb39ec934adf9b3c20698a0fc483cef7b2df067..1b259d5081ec53cbb7fba2a83014a14eb80aa65c 100644 --- a/src/HttpResponder/Json.php +++ b/src/HttpResponder/Json.php @@ -6,7 +6,6 @@ namespace Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\ContentType; use Distantmagic\Resonance\HttpResponder; -use Distantmagic\Resonance\PsrStringStream; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -19,7 +18,7 @@ readonly class Json extends HttpResponder return $response ->withStatus(200) ->withHeader('content-type', ContentType::ApplicationJson->value) - ->withBody(new PsrStringStream($this->json)) + ->withBody($this->createStream($this->json)) ; } } diff --git a/src/HttpResponder/NotAcceptable.php b/src/HttpResponder/NotAcceptable.php index ac97b8749c32cdffcbbcfbe5da36503c525c90d4..d28a2a7771233fc985e6c7234daf365b186064f7 100644 --- a/src/HttpResponder/NotAcceptable.php +++ b/src/HttpResponder/NotAcceptable.php @@ -7,7 +7,6 @@ namespace Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\ContentType; use Distantmagic\Resonance\HttpResponder; -use Distantmagic\Resonance\PsrStringStream; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -19,7 +18,7 @@ final readonly class NotAcceptable extends HttpResponder return $response ->withStatus(406) ->withHeader('content-type', ContentType::TextPlain->value) - ->withBody(new PsrStringStream('406')) + ->withBody($this->createStream('406')) ; } } diff --git a/src/HttpResponderInterface.php b/src/HttpResponderInterface.php index 4947b4a8120eca436bd194280e2b449f2a076bc9..a9bd5700793a02e1fa11797b7fc5aa130963f3fb 100644 --- a/src/HttpResponderInterface.php +++ b/src/HttpResponderInterface.php @@ -6,9 +6,8 @@ namespace Distantmagic\Resonance; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; -interface HttpResponderInterface extends RequestHandlerInterface +interface HttpResponderInterface { public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface|ResponseInterface|self; } diff --git a/src/PsrStringStream.php b/src/PsrStringStream.php index 003a8ac55d4eb7e6a7c4e7f4227b8984e3e8c5a0..8c9dc8a344d2e09d7cadf224e18d4497f12f202b 100644 --- a/src/PsrStringStream.php +++ b/src/PsrStringStream.php @@ -5,10 +5,16 @@ declare(strict_types=1); namespace Distantmagic\Resonance; use Psr\Http\Message\StreamInterface; +use Stringable; readonly class PsrStringStream implements StreamInterface { - public function __construct(private string $contents) {} + private string $contents; + + public function __construct(string|Stringable $contents) + { + $this->contents = (string) $contents; + } public function __toString(): string {