Skip to content

Conversation

@Blezigen
Copy link

@Blezigen Blezigen commented Nov 26, 2025

Introduce a proper bridge between PSR-7 ServerRequestInterface and Yii Request, including request body parsing.

The setPsr7Request method now:

  • extracts the raw Content-Type header (trimming parameters like charset=UTF-8);
  • resolves an appropriate request parser from $this->parsers (or the '*' fallback, if configured);
  • parses the PSR-7 request body and injects the result into parsedBody via $request->withParsedBody();
  • wraps the request in ServerRequestAdapter while adding the statelessAppStartTime header for tracing/debugging;
  • updates the PSR-7 adapter for UploadedFile via UploadedFile::setPsr7Adapter().

This change:

  • aligns PSR-7-based requests with the existing Yii Request behavior regarding body parsing and UploadedFile handling;
  • enables stateless application startup time tracing at the PSR-7 request level;
  • keeps compatibility with existing Yii request parsers configured in the application.

Pull Request

Q A
Is bugfix? ✔️
New feature?
Breaks BC?
Fixed issues -

Summary by CodeRabbit

  • New Features

    • Content-type aware request parsing: requests are now parsed based on their base content type, with a fallback option for unknown types.
    • Parsed request body data is applied automatically when available, improving downstream request handling.
  • Behavior

    • No change when parsing yields no data; existing header behavior and adapter flow are preserved.

✏️ Tip: You can customize this high-level summary in your review settings.

Introduce a proper bridge between PSR-7 ServerRequestInterface and Yii Request, including request body parsing.

The setPsr7Request method now:
- extracts the raw Content-Type header (trimming parameters like `charset=UTF-8`);
- resolves an appropriate request parser from `$this->parsers` (or the `'*'` fallback, if configured);
- parses the PSR-7 request body and injects the result into `parsedBody` via `$request->withParsedBody()`;
- wraps the request in `ServerRequestAdapter` while adding the `statelessAppStartTime` header for tracing/debugging;
- updates the PSR-7 adapter for `UploadedFile` via `UploadedFile::setPsr7Adapter()`.

This change:
- aligns PSR-7-based requests with the existing Yii Request behavior regarding body parsing and UploadedFile handling;
- enables stateless application startup time tracing at the PSR-7 request level;
- keeps compatibility with existing Yii request parsers configured in the application.
@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

setPsr7Request() now strips parameters from Content-Type, selects a parser from a parsers map (specific type or *), validates it implements RequestParserInterface, parses the body before creating the PSR-7 adapter, and applies parsed data to the PSR-7 request only when parsing yields data.

Changes

Cohort / File(s) Summary
Request adapter parsing
src/http/Request.php
Extract base content-type (strip parameters), lookup parser from a parsers map with * fallback, validate RequestParserInterface, parse request body before adapter creation, and conditionally apply parsed params to the PSR-7 request. Minor formatting tweaks.

Sequence Diagram

sequenceDiagram
    actor Client
    participant setPsr7Request as setPsr7Request()
    participant ParsersMap as Parsers Map
    participant Parser as Parser\n(RequestParserInterface)
    participant Adapter as PSR-7 Adapter / Request

    Client->>setPsr7Request: call with incoming request
    setPsr7Request->>setPsr7Request: read Content-Type\nstrip parameters (semicolon)
    
    rect rgb(230,240,250)
      note over setPsr7Request,ParsersMap: Select & validate parser
      setPsr7Request->>ParsersMap: lookup by base type or '*'
      ParsersMap-->>setPsr7Request: parser instance or none
      setPsr7Request->>Parser: assert implements RequestParserInterface
    end

    rect rgb(240,250,230)
      note over setPsr7Request,Parser: Parse body
      alt parser found & returns data
        setPsr7Request->>Parser: parse body
        Parser-->>setPsr7Request: parsed params
        setPsr7Request->>Adapter: create adapter with parsed body
      else no parser or no data
        setPsr7Request->>Adapter: create adapter with original body
      end
    end

    Adapter-->>Client: PSR-7 request (possibly with parsed body)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20-25 minutes

  • Inspect content-type parsing and semicolon/parameter edge cases.
  • Verify parser map lookup and * fallback logic.
  • Confirm RequestParserInterface validation and behavior when parser returns no data.
  • Check adapter creation remains consistent with existing headers (e.g., statelessAppStartTime).

Possibly related PRs

Suggested labels

bug

Poem

🐰 I nibbled headers, stripped the tail,
Found parsers tucked in Content-Type trail,
I hop and parse, then build the bridge,
PSR‑7 carries what I did abridge,
A tiny rabbit fix — light as hail.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(http): Enhance setPsr7Request: parse body' clearly and specifically summarizes the main change: enhancing the setPsr7Request method to parse request bodies.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca94b34 and 178a159.

📒 Files selected for processing (1)
  • src/http/Request.php (3 hunks)
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:23.564Z
Learning: In yii2-extensions/psr-bridge, the Request::setPsr7Request() method calls getRequestStartTime() to initialize timing at the moment the PSR-7 request is set, which marks the actual start of the request cycle in worker environments. This ensures profiling panels get accurate timing from the true request beginning rather than lazy initialization on first access.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:41.975Z
Learning: In yii2-extensions/psr-bridge Request class, the getRequestStartTime() call in setPsr7Request() is intentionally placed to capture accurate request timing at the moment the PSR-7 request is set, which corresponds to when the request cycle begins. This ensures profiling panels get the correct start time reference rather than when timing is first accessed later.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 172
File: docs/testing.md:17-45
Timestamp: 2025-09-25T20:39:56.402Z
Learning: In the yii2-extensions/psr-bridge repository, documentation formatting in markdown files is handled automatically by prettier, so sentence fragments before code blocks are intentional formatting choices that should not be flagged as readability issues.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 160
File: tests/http/UploadedFileTest.php:122-179
Timestamp: 2025-08-28T22:08:51.812Z
Learning: In yii2-extensions/psr-bridge, when the PSR-7 adapter is set in UploadedFile, it indicates worker mode (like RoadRunner, Swoole), where $_FILES is not meaningful and should not be checked as a fallback. The PSR-7 adapter becomes the authoritative source for uploaded files in this mode.
📚 Learning: 2025-08-15T01:04:23.564Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:23.564Z
Learning: In yii2-extensions/psr-bridge, the Request::setPsr7Request() method calls getRequestStartTime() to initialize timing at the moment the PSR-7 request is set, which marks the actual start of the request cycle in worker environments. This ensures profiling panels get accurate timing from the true request beginning rather than lazy initialization on first access.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-15T01:04:41.975Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:41.975Z
Learning: In yii2-extensions/psr-bridge Request class, the getRequestStartTime() call in setPsr7Request() is intentionally placed to capture accurate request timing at the moment the PSR-7 request is set, which corresponds to when the request cycle begins. This ensures profiling panels get the correct start time reference rather than when timing is first accessed later.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-10T13:15:30.396Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 78
File: tests/adapter/ServerParamsPsr7Test.php:8-8
Timestamp: 2025-08-10T13:15:30.396Z
Learning: In the yii2-extensions/psr-bridge project, classes referenced in PHPDoc annotations (such as throws declarations) must be imported even if not used in the actual code, to avoid ghost class references and maintain proper documentation.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-10T13:17:04.265Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 78
File: src/http/Request.php:0-0
Timestamp: 2025-08-10T13:17:04.265Z
Learning: In the yii2-extensions/psr-bridge project, PHPStan type annotations should be defensive when dealing with external input from PSR-7 sources. For methods like `getUploadedFiles()` and `convertPsr7ToUploadedFiles()`, use `mixed` in the return type annotation to account for untrusted input values, even if the implementation filters them.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-13T23:36:57.972Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 90
File: tests/http/StatelessApplicationTest.php:1375-1378
Timestamp: 2025-08-13T23:36:57.972Z
Learning: In yii2-extensions/psr-bridge, unserialize() calls should follow the same pattern as Yii2 core framework (using unserialize($data) without allowed_classes restriction) to maintain consistency with the upstream framework's security model and avoid compatibility issues.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-28T22:08:51.812Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 160
File: tests/http/UploadedFileTest.php:122-179
Timestamp: 2025-08-28T22:08:51.812Z
Learning: In yii2-extensions/psr-bridge, when the PSR-7 adapter is set in UploadedFile, it indicates worker mode (like RoadRunner, Swoole), where $_FILES is not meaningful and should not be checked as a fallback. The PSR-7 adapter becomes the authoritative source for uploaded files in this mode.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-29T09:44:57.466Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 160
File: src/http/UploadedFile.php:110-115
Timestamp: 2025-08-29T09:44:57.466Z
Learning: In yii2-extensions/psr-bridge, the official Yii2 \yii\web\UploadedFile constructor already handles the 'tempResource' key in the config array and properly maps it to the $_tempResource protected property. Therefore, passing 'tempResource' in the config array to the UploadedFile constructor will not cause UnknownPropertyException.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-22T00:50:26.546Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 21
File: tests/http/PSR7ResponseTest.php:0-0
Timestamp: 2025-07-22T00:50:26.546Z
Learning: In yii2-extensions/psr-bridge, the ResponseAdapter::formatCookieHeader() method uses `$expire !== 1` to skip validation for Yii2's special deletion cookies, but this should be extended to handle all expired cookies, not just the special case where expire=1.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-20T16:35:15.341Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 6
File: tests/http/RequestTest.php:1536-1552
Timestamp: 2025-07-20T16:35:15.341Z
Learning: In the yii2-extensions/psr-bridge project, the base TestCase class already handles $_SERVER cleanup in setUp() and tearDown() methods, so individual test methods that extend TestCase don't need manual $_SERVER restoration.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-20T16:35:15.341Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 6
File: tests/http/RequestTest.php:1536-1552
Timestamp: 2025-07-20T16:35:15.341Z
Learning: In the yii2-extensions/psr-bridge project, the base TestCase class already handles $_SERVER cleanup in setUp() and tearDown() methods (lines 28 and 32), so individual test methods that extend TestCase don't need manual $_SERVER restoration.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-24T11:52:50.563Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 141
File: tests/http/stateless/ApplicationRoutingTest.php:1-164
Timestamp: 2025-08-24T11:52:50.563Z
Learning: In yii2-extensions/psr-bridge, tests that manipulate PHP superglobals ($_POST, $_GET, $_SERVER) in the http group do not require process isolation and work fine with the current PHPUnit configuration.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-06T22:52:05.608Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 64
File: tests/http/StatelessApplicationTest.php:1939-1967
Timestamp: 2025-08-06T22:52:05.608Z
Learning: In yii2-extensions/psr-bridge tests, when testing specific component methods like Request::resolve(), it's necessary to call $app->handle($request) first to initialize all application components before testing the method in isolation. This ensures proper component lifecycle initialization.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-20T16:33:57.495Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 6
File: tests/http/RequestTest.php:1564-1578
Timestamp: 2025-07-20T16:33:57.495Z
Learning: The TestCase class in yii2-extensions/psr-bridge automatically handles $_SERVER superglobal cleanup by saving its original state before each test and restoring it afterward in setUp() and tearDown() methods. Manual $_SERVER cleanup in individual test methods is unnecessary when extending this TestCase.

Applied to files:

  • src/http/Request.php
🔇 Additional comments (4)
src/http/Request.php (4)

10-10: LGTM! Import correctly added.

The RequestParserInterface import is properly included in the yii\web namespace group and resolves the previously flagged missing import issue.


792-798: LGTM! Content-Type correctly extracted from PSR-7 request.

The Content-Type is now properly extracted from the incoming PSR-7 request headers rather than falling back to $_SERVER, and parameters are correctly stripped to derive the base content type for parser selection.


800-814: LGTM! Parser selection and validation logic is sound.

The parser selection correctly follows precedence (specific content-type, then wildcard fallback), validates that parsers implement RequestParserInterface, and appropriately parses the request body. The implementation aligns with Yii2 patterns and PSR-7 best practices.


816-821: LGTM! Parsed body correctly applied without type coercion.

The code appropriately applies the parsed body only when parsing yields non-null data, preserves the array|object return type from RequestParserInterface::parse() (no cast), and correctly passes the updated request to the adapter. This resolves the previously flagged issue about the unnecessary array cast.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/http/Request.php (1)

815-815: Casting to array may discard object structure.

RequestParserInterface::parse() can return array|object|null. Casting an object to (array) may not preserve the intended structure if parsers return objects.

Consider preserving the original type:

         if ($parsedParams !== null) {
-            $request = $request->withParsedBody((array)$parsedParams);
+            $request = $request->withParsedBody($parsedParams);
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0e288e3 and 84147bf.

📒 Files selected for processing (1)
  • src/http/Request.php (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:23.564Z
Learning: In yii2-extensions/psr-bridge, the Request::setPsr7Request() method calls getRequestStartTime() to initialize timing at the moment the PSR-7 request is set, which marks the actual start of the request cycle in worker environments. This ensures profiling panels get accurate timing from the true request beginning rather than lazy initialization on first access.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:41.975Z
Learning: In yii2-extensions/psr-bridge Request class, the getRequestStartTime() call in setPsr7Request() is intentionally placed to capture accurate request timing at the moment the PSR-7 request is set, which corresponds to when the request cycle begins. This ensures profiling panels get the correct start time reference rather than when timing is first accessed later.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 160
File: tests/http/UploadedFileTest.php:122-179
Timestamp: 2025-08-28T22:08:51.812Z
Learning: In yii2-extensions/psr-bridge, when the PSR-7 adapter is set in UploadedFile, it indicates worker mode (like RoadRunner, Swoole), where $_FILES is not meaningful and should not be checked as a fallback. The PSR-7 adapter becomes the authoritative source for uploaded files in this mode.
📚 Learning: 2025-08-15T01:04:23.564Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:23.564Z
Learning: In yii2-extensions/psr-bridge, the Request::setPsr7Request() method calls getRequestStartTime() to initialize timing at the moment the PSR-7 request is set, which marks the actual start of the request cycle in worker environments. This ensures profiling panels get accurate timing from the true request beginning rather than lazy initialization on first access.

Applied to files:

  • src/http/Request.php
🧬 Code graph analysis (1)
src/http/Request.php (1)
src/adapter/ServerRequestAdapter.php (1)
  • ServerRequestAdapter (47-441)
🔇 Additional comments (1)
src/http/Request.php (1)

818-821: LGTM!

The stateless application start time header injection aligns with the timing initialization pattern for worker environments. Based on learnings, this ensures profiling panels get accurate timing from the true request beginning.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/http/Request.php (1)

802-814: Consider extracting parser validation to reduce duplication.

The parser validation logic (lines 804-806 and 810-812) is duplicated between the specific content-type and fallback branches. Consider extracting to a small helper method for clarity.

Example refactor:

+    /**
+     * @throws InvalidConfigException
+     */
+    private function validateParser(mixed $parser, string $context): RequestParserInterface
+    {
+        if (!($parser instanceof RequestParserInterface)) {
+            throw new InvalidConfigException("The '$context' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
+        }
+        return $parser;
+    }
+
     public function setPsr7Request(ServerRequestInterface $request): void
     {
         // ... content-type extraction ...
         
         if (isset($this->parsers[$contentType])) {
-            $parser = Yii::createObject($this->parsers[$contentType]);
-            if (!($parser instanceof RequestParserInterface)) {
-                throw new InvalidConfigException("The '$contentType' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
-            }
+            $parser = $this->validateParser(
+                Yii::createObject($this->parsers[$contentType]),
+                $contentType
+            );
             $parsedParams = $parser->parse((string)$request->getBody(), $rawContentType);
         } elseif (isset($this->parsers['*'])) {
-            $parser = Yii::createObject($this->parsers['*']);
-            if (!($parser instanceof RequestParserInterface)) {
-                throw new InvalidConfigException('The fallback request parser is invalid. It must implement the yii\\web\\RequestParserInterface.');
-            }
+            $parser = $this->validateParser(
+                Yii::createObject($this->parsers['*']),
+                'fallback'
+            );
             $parsedParams = $parser->parse((string)$request->getBody(), $rawContentType);
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84147bf and ca94b34.

📒 Files selected for processing (1)
  • src/http/Request.php (3 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:23.564Z
Learning: In yii2-extensions/psr-bridge, the Request::setPsr7Request() method calls getRequestStartTime() to initialize timing at the moment the PSR-7 request is set, which marks the actual start of the request cycle in worker environments. This ensures profiling panels get accurate timing from the true request beginning rather than lazy initialization on first access.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 172
File: docs/testing.md:17-45
Timestamp: 2025-09-25T20:39:56.402Z
Learning: In the yii2-extensions/psr-bridge repository, documentation formatting in markdown files is handled automatically by prettier, so sentence fragments before code blocks are intentional formatting choices that should not be flagged as readability issues.
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:41.975Z
Learning: In yii2-extensions/psr-bridge Request class, the getRequestStartTime() call in setPsr7Request() is intentionally placed to capture accurate request timing at the moment the PSR-7 request is set, which corresponds to when the request cycle begins. This ensures profiling panels get the correct start time reference rather than when timing is first accessed later.
📚 Learning: 2025-08-15T01:04:23.564Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:23.564Z
Learning: In yii2-extensions/psr-bridge, the Request::setPsr7Request() method calls getRequestStartTime() to initialize timing at the moment the PSR-7 request is set, which marks the actual start of the request cycle in worker environments. This ensures profiling panels get accurate timing from the true request beginning rather than lazy initialization on first access.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-15T01:04:41.975Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 95
File: src/http/Request.php:844-845
Timestamp: 2025-08-15T01:04:41.975Z
Learning: In yii2-extensions/psr-bridge Request class, the getRequestStartTime() call in setPsr7Request() is intentionally placed to capture accurate request timing at the moment the PSR-7 request is set, which corresponds to when the request cycle begins. This ensures profiling panels get the correct start time reference rather than when timing is first accessed later.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-10T13:15:30.396Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 78
File: tests/adapter/ServerParamsPsr7Test.php:8-8
Timestamp: 2025-08-10T13:15:30.396Z
Learning: In the yii2-extensions/psr-bridge project, classes referenced in PHPDoc annotations (such as throws declarations) must be imported even if not used in the actual code, to avoid ghost class references and maintain proper documentation.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-28T22:08:51.812Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 160
File: tests/http/UploadedFileTest.php:122-179
Timestamp: 2025-08-28T22:08:51.812Z
Learning: In yii2-extensions/psr-bridge, when the PSR-7 adapter is set in UploadedFile, it indicates worker mode (like RoadRunner, Swoole), where $_FILES is not meaningful and should not be checked as a fallback. The PSR-7 adapter becomes the authoritative source for uploaded files in this mode.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-29T09:44:57.466Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 160
File: src/http/UploadedFile.php:110-115
Timestamp: 2025-08-29T09:44:57.466Z
Learning: In yii2-extensions/psr-bridge, the official Yii2 \yii\web\UploadedFile constructor already handles the 'tempResource' key in the config array and properly maps it to the $_tempResource protected property. Therefore, passing 'tempResource' in the config array to the UploadedFile constructor will not cause UnknownPropertyException.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-22T00:50:26.546Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 21
File: tests/http/PSR7ResponseTest.php:0-0
Timestamp: 2025-07-22T00:50:26.546Z
Learning: In yii2-extensions/psr-bridge, the ResponseAdapter::formatCookieHeader() method uses `$expire !== 1` to skip validation for Yii2's special deletion cookies, but this should be extended to handle all expired cookies, not just the special case where expire=1.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-20T16:35:15.341Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 6
File: tests/http/RequestTest.php:1536-1552
Timestamp: 2025-07-20T16:35:15.341Z
Learning: In the yii2-extensions/psr-bridge project, the base TestCase class already handles $_SERVER cleanup in setUp() and tearDown() methods, so individual test methods that extend TestCase don't need manual $_SERVER restoration.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-20T16:35:15.341Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 6
File: tests/http/RequestTest.php:1536-1552
Timestamp: 2025-07-20T16:35:15.341Z
Learning: In the yii2-extensions/psr-bridge project, the base TestCase class already handles $_SERVER cleanup in setUp() and tearDown() methods (lines 28 and 32), so individual test methods that extend TestCase don't need manual $_SERVER restoration.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-24T11:52:50.563Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 141
File: tests/http/stateless/ApplicationRoutingTest.php:1-164
Timestamp: 2025-08-24T11:52:50.563Z
Learning: In yii2-extensions/psr-bridge, tests that manipulate PHP superglobals ($_POST, $_GET, $_SERVER) in the http group do not require process isolation and work fine with the current PHPUnit configuration.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-06T22:52:05.608Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 64
File: tests/http/StatelessApplicationTest.php:1939-1967
Timestamp: 2025-08-06T22:52:05.608Z
Learning: In yii2-extensions/psr-bridge tests, when testing specific component methods like Request::resolve(), it's necessary to call $app->handle($request) first to initialize all application components before testing the method in isolation. This ensures proper component lifecycle initialization.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-08-10T13:17:04.265Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 78
File: src/http/Request.php:0-0
Timestamp: 2025-08-10T13:17:04.265Z
Learning: In the yii2-extensions/psr-bridge project, PHPStan type annotations should be defensive when dealing with external input from PSR-7 sources. For methods like `getUploadedFiles()` and `convertPsr7ToUploadedFiles()`, use `mixed` in the return type annotation to account for untrusted input values, even if the implementation filters them.

Applied to files:

  • src/http/Request.php
📚 Learning: 2025-07-20T16:33:57.495Z
Learnt from: terabytesoftw
Repo: yii2-extensions/psr-bridge PR: 6
File: tests/http/RequestTest.php:1564-1578
Timestamp: 2025-07-20T16:33:57.495Z
Learning: The TestCase class in yii2-extensions/psr-bridge automatically handles $_SERVER superglobal cleanup by saving its original state before each test and restoring it afterward in setUp() and tearDown() methods. Manual $_SERVER cleanup in individual test methods is unnecessary when extending this TestCase.

Applied to files:

  • src/http/Request.php
🔇 Additional comments (4)
src/http/Request.php (4)

10-10: Import added - previous critical issue resolved.

The RequestParserInterface import correctly addresses the fatal error flagged in the previous review.


792-798: Content-Type extraction fixed - now reads from PSR-7 request.

The extraction now correctly uses $request->getHeaderLine('Content-Type'), resolving the critical issue from the previous review where it was reading from $_SERVER instead.


820-824: LGTM - adapter creation preserves parsed body.

The adapter is correctly instantiated with the potentially updated $request object, ensuring that any parsed body data flows through to the Yii2 bridge. The statelessAppStartTime header remains in place for profiling, as per established patterns in this codebase.

Based on learnings, the timing header ensures profiling panels get accurate request timing in worker environments.


800-814: Verify PSR-7 stream rewindability before parsing request body.

The code casts $request->getBody() to string without verifying the stream is seekable or handling rewind. Per PSR-7 specification, streams are not guaranteed to be rewindable—especially non-seekable sources like php://input. If the stream has been read or is non-seekable, the cast will return an empty string, causing parsers to receive empty input.

Two items to verify:

  1. Stream rewindability: Confirm the ServerRequest implementation provides a rewindable stream, or add rewind() after parsing. Use Guzzle's Utils::streamFor() or Message::rewindBody() helper if needed to safely handle non-seekable streams.

  2. Parser property: Confirm $this->parsers is properly configured in the application config (e.g., config/web.php) with the expected Content-Type mappings.

Remove the unnecessary (array) cast to support object-based parsed bodies.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant