-
Notifications
You must be signed in to change notification settings - Fork 36
Backport abstract request/response with adapters #212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
a8cd7b2 to
563d217
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR backports the 0.34.x HTTP adapter split by making Utopia\Request and Utopia\Response abstract and introducing concrete adapters for FPM and Swoole, then updating docs/tests to use the new adapter classes.
Changes:
- Make core
Request/Responseabstract and move environment-specific IO to adapters. - Add
Utopia\Adapter\FPM\*andUtopia\Adapter\Swoole\*Request/Response (and Server wrappers). - Update tests, README, and Getting Started guide to import adapter Request/Response classes.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/e2e/server.php | Switch e2e server bootstrap to use FPM adapter Request/Response imports. |
| tests/UtopiaRequestTest.php | Update test helper class to extend FPM adapter Request. |
| tests/ResponseTest.php | Update tests to instantiate FPM adapter Response instead of abstract base. |
| tests/RequestTest.php | Update tests to instantiate FPM adapter Request instead of abstract base. |
| tests/ModelTest.php | Update model tests to use FPM adapter Request/Response. |
| tests/HttpTest.php | Update HTTP tests to use FPM adapter Request/Response. |
| src/Response.php | Convert Response to abstract; extract IO primitives (write/end/status/header/cookie) into abstract methods. |
| src/Request.php | Convert Request to abstract; extract environment-specific accessors and input parsing into abstract methods; adjust size calculation formatting. |
| src/Adapter/Adapter.php | Introduce abstract adapter interface for server lifecycle hooks. |
| src/Adapter/FPM/Server.php | Add FPM server adapter wrapper that wires FPM Request/Response into callbacks/resources. |
| src/Adapter/FPM/Request.php | Add concrete Request implementation for PHP-FPM superglobals + php://input parsing. |
| src/Adapter/FPM/Response.php | Add concrete Response implementation for PHP-FPM output/headers/cookies. |
| src/Adapter/Swoole/Server.php | Add Swoole server adapter wrapper bridging Swoole request/response to Utopia adapters. |
| src/Adapter/Swoole/Request.php | Add concrete Request implementation backed by Swoole request object. |
| src/Adapter/Swoole/Response.php | Add concrete Response implementation backed by Swoole response object. |
| docs/Getting-Starting-Guide.md | Update Swoole examples to use adapter Request/Response namespaces. |
| README.md | Update usage examples to import FPM adapter Request/Response. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| { | ||
| protected SwooleServer $server; | ||
|
|
||
| public function __construct(string $host, ?string $port = null, array $settings = []) |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$port is typed as ?string and passed to new SwooleServer($host, $port), but Swoole’s server constructor expects an integer port. This can lead to runtime type errors depending on the Swoole version/build. Prefer int $port = 80 (or ?int) and cast/validate before passing to Swoole.
| public function __construct(string $host, ?string $port = null, array $settings = []) | |
| public function __construct(string $host, int $port = 80, array $settings = []) |
| domain: $options['domain'] ?? '', | ||
| secure: $options['secure'] ?? false, | ||
| httponly: $options['httponly'] ?? false, | ||
| samesite: $options['samesite'] ?? false, |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sendCookie() passes samesite: $options['samesite'] ?? false. Swoole’s cookie API expects samesite to be a string (or null/empty), not a boolean; passing false can cause a TypeError. Use ''/null as the default and only pass valid SameSite strings.
| samesite: $options['samesite'] ?? false, | |
| samesite: isset($options['samesite']) && is_string($options['samesite']) ? $options['samesite'] : null, |
| */ | ||
| public function getReferer(string $default = ''): string | ||
| { | ||
| return $this->getHeader('referer', ''); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getReferer() ignores the $default parameter and always falls back to an empty string. This breaks the method contract vs the abstract Request API and differs from the FPM adapter. Use $default as the fallback value.
| return $this->getHeader('referer', ''); | |
| return $this->getHeader('referer', $default); |
| */ | ||
| public function getHeader(string $key, string $default = ''): string | ||
| { | ||
| return $this->swoole->header[$key] ?? $default; |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getHeader() looks up $this->swoole->header[$key] without normalizing the key. Swoole header keys are typically lowercased; callers may pass mixed-case names (e.g. Content-Type) and get unexpected misses. Consider normalizing (strtolower) and/or delegating to generateHeaders() (which already lowercases keys).
| return $this->swoole->header[$key] ?? $default; | |
| if (isset($this->swoole->header[$key])) { | |
| return $this->swoole->header[$key]; | |
| } | |
| $normalizedKey = \strtolower($key); | |
| return $this->swoole->header[$normalizedKey] ?? $default; |
src/Http/Adapter/Swoole/Response.php
Outdated
| */ | ||
| protected function sendStatus(int $statusCode): void | ||
| { | ||
| $this->swoole->status((string) $statusCode); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sendStatus() passes (string) $statusCode into $this->swoole->status(...). Swoole’s status() expects an int status code; passing a string may throw a TypeError in newer versions. Pass the integer status code through unchanged.
| $this->swoole->status((string) $statusCode); | |
| $this->swoole->status($statusCode); |
| */ | ||
| public function sendHeader(string $key, mixed $value): void | ||
| { | ||
| $this->swoole->header($key, $value); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sendHeader() forwards $value directly to $this->swoole->header($key, $value), but in this codebase headers may be arrays (see FPM adapter + base Response handling). Swoole’s header() expects a string value per call; array values should be expanded into multiple header() calls (or joined appropriately) to avoid runtime errors.
| $this->swoole->header($key, $value); | |
| if (\is_array($value)) { | |
| foreach ($value as $singleValue) { | |
| if ($singleValue === null) { | |
| continue; | |
| } | |
| $this->swoole->header($key, (string) $singleValue); | |
| } | |
| return; | |
| } | |
| if ($value !== null) { | |
| $this->swoole->header($key, (string) $value); | |
| } |
| $headerStrings[] = $key . ': ' . $value; | ||
| } | ||
| } | ||
| return \mb_strlen(\implode("\n", $headerStrings), '8bit') + \mb_strlen(\file_get_contents('php://input'), '8bit'); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request::getSize() still reads the body from php://input, which is FPM-specific. For non-FPM adapters (e.g. Swoole) this will report incorrect request sizes (and may do unnecessary IO). Since getRawPayload() is now abstract, prefer using mb_strlen($this->getRawPayload(), '8bit') here (or let adapters override getSize()).
| return \mb_strlen(\implode("\n", $headerStrings), '8bit') + \mb_strlen(\file_get_contents('php://input'), '8bit'); | |
| $rawPayload = (string) $this->getRawPayload(); | |
| return \mb_strlen(\implode("\n", $headerStrings), '8bit') + \mb_strlen($rawPayload, '8bit'); |
| { | ||
| echo $content; | ||
| } | ||
| abstract public function write(string $content): bool; |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Response::write() now returns bool, but core code paths (e.g. chunked send loop and chunk()) do not check the return value. If adapters use false to signal “client disconnected / cannot write”, the framework will continue writing anyway. Either handle the false return (stop further writes + mark response as sent), or keep write() as void if it’s not meant to be acted upon.
| } | ||
|
|
||
| /** | ||
| * Remvoe header |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in docblock: "Remvoe header" → "Remove header".
| * Remvoe header | |
| * Remove header |
Backport 0.34.x HTTP adapter split: make Request/Response abstract and add FPM/Swoole adapters. Update docs/tests to use adapters.