Skip to content

Commit 7df2364

Browse files
feat: add support for PSR-7 ServerRequest (#108)
Implements feature request #25 by adding support for PSR-7 ServerRequest objects to the HAR library. Changes: - Add Request::fromPsr7ServerRequest() method to convert PSR-7 ServerRequest to HAR Request format - Create ServerRequest adapter class (Adapter\Psr7\ServerRequest) that implements ServerRequestInterface - ServerRequest adapter supports all PSR-7 ServerRequest features that are also supported by the HAR spec. - Fix null return type issues in Request::getQueryString(), CookiesTrait::getCookies(), and MimeTypeTrait::getMimeType() - Update PostData to use Query::build() instead of deprecated build_query() refs: #25 --------- Co-authored-by: Claude <[email protected]>
1 parent 4002a2c commit 7df2364

File tree

8 files changed

+628
-7
lines changed

8 files changed

+628
-7
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ repos:
2323
pass_filenames: false
2424
- id: phpunit
2525
name: PHPUnit
26-
entry: vendor/bin/phpunit
26+
entry: env XDEBUG_MODE=coverage vendor/bin/phpunit
2727
language: system
2828
types: [php]
2929
pass_filenames: false

src/Adapter/Psr7/ServerRequest.php

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Deviantintegral\Har\Adapter\Psr7;
6+
7+
use Deviantintegral\Har\Cookie;
8+
use Deviantintegral\Har\Params;
9+
use Deviantintegral\Har\PostData;
10+
use Psr\Http\Message\ServerRequestInterface;
11+
use Psr\Http\Message\StreamInterface;
12+
use Psr\Http\Message\UriInterface;
13+
14+
/**
15+
* Adapts PSR-7 ServerRequests.
16+
*
17+
* Only features supported by HAR spec are implemented. Unsupported features
18+
* will throw a \LogicException if they involve possible data loss.
19+
*/
20+
class ServerRequest extends Request implements ServerRequestInterface
21+
{
22+
public function getServerParams(): array
23+
{
24+
return [];
25+
}
26+
27+
public function getCookieParams(): array
28+
{
29+
$request = $this->getHarRequest();
30+
$cookieParams = [];
31+
foreach ($request->getCookies() as $cookie) {
32+
$cookieParams[$cookie->getName()] = $cookie->getValue();
33+
}
34+
35+
return $cookieParams;
36+
}
37+
38+
public function withCookieParams(array $cookies): ServerRequestInterface
39+
{
40+
$request = clone $this->getHarRequest();
41+
$harCookies = [];
42+
foreach ($cookies as $name => $value) {
43+
$harCookies[] = (new Cookie())
44+
->setName($name)
45+
->setValue($value);
46+
}
47+
$request->setCookies($harCookies);
48+
49+
return new static($request);
50+
}
51+
52+
public function getQueryParams(): array
53+
{
54+
$request = $this->getHarRequest();
55+
$queryParams = [];
56+
foreach ($request->getQueryString() as $param) {
57+
$queryParams[$param->getName()] = $param->getValue();
58+
}
59+
60+
return $queryParams;
61+
}
62+
63+
public function withQueryParams(array $query): ServerRequestInterface
64+
{
65+
$request = clone $this->getHarRequest();
66+
$harParams = [];
67+
foreach ($query as $name => $value) {
68+
$harParams[] = (new Params())
69+
->setName($name)
70+
->setValue((string) $value);
71+
}
72+
$request->setQueryString($harParams);
73+
74+
return new static($request);
75+
}
76+
77+
public function getUploadedFiles(): array
78+
{
79+
return [];
80+
}
81+
82+
public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
83+
{
84+
throw new \LogicException('Uploaded files are not supported.');
85+
}
86+
87+
public function getParsedBody()
88+
{
89+
$request = $this->getHarRequest();
90+
91+
if (!$request->hasPostData()) {
92+
return null;
93+
}
94+
95+
$postData = $request->getPostData();
96+
if ($postData->hasParams()) {
97+
$parsedBody = [];
98+
foreach ($postData->getParams() as $param) {
99+
$parsedBody[$param->getName()] = $param->getValue();
100+
}
101+
102+
return $parsedBody;
103+
}
104+
105+
if ($postData->hasText()) {
106+
// Try to parse as form data if content type suggests it
107+
$contentType = $postData->getMimeType();
108+
if ('application/x-www-form-urlencoded' === $contentType) {
109+
$parsedBody = [];
110+
parse_str($postData->getText(), $parsedBody);
111+
112+
return $parsedBody;
113+
}
114+
}
115+
116+
return null;
117+
}
118+
119+
public function withParsedBody($data): ServerRequestInterface
120+
{
121+
if (!\is_array($data) && !\is_object($data) && null !== $data) {
122+
throw new \InvalidArgumentException('Parsed body must be an array, object, or null.');
123+
}
124+
125+
$request = clone $this->getHarRequest();
126+
127+
if (\is_array($data) || \is_object($data)) {
128+
$postData = new PostData();
129+
$harParams = [];
130+
foreach ($data as $name => $value) {
131+
$harParams[] = (new Params())
132+
->setName($name)
133+
->setValue((string) $value);
134+
}
135+
$postData->setParams($harParams);
136+
$request->setPostData($postData);
137+
} elseif (null === $data) {
138+
// Clear post data
139+
$request->setPostData(new PostData());
140+
}
141+
142+
return new static($request);
143+
}
144+
145+
public function getAttributes(): array
146+
{
147+
return [];
148+
}
149+
150+
public function getAttribute($name, $default = null)
151+
{
152+
return $default;
153+
}
154+
155+
public function withAttribute($name, $value): ServerRequestInterface
156+
{
157+
throw new \LogicException('Attributes are not supported.');
158+
}
159+
160+
public function withoutAttribute($name): ServerRequestInterface
161+
{
162+
// Attributes are not part of HAR spec, return unchanged clone
163+
return new static($this->getHarRequest());
164+
}
165+
166+
/**
167+
* Override parent methods to return ServerRequestInterface.
168+
*/
169+
public function withMethod($method): ServerRequestInterface
170+
{
171+
$parent = parent::withMethod($method);
172+
173+
return new static($parent->getHarRequest());
174+
}
175+
176+
public function withUri(UriInterface $uri, $preserveHost = false): ServerRequestInterface
177+
{
178+
$parent = parent::withUri($uri, $preserveHost);
179+
180+
return new static($parent->getHarRequest());
181+
}
182+
183+
public function withRequestTarget($requestTarget): ServerRequestInterface
184+
{
185+
$parent = parent::withRequestTarget($requestTarget);
186+
187+
return new static($parent->getHarRequest());
188+
}
189+
190+
public function withBody(StreamInterface $body): ServerRequestInterface
191+
{
192+
$parent = parent::withBody($body);
193+
194+
return new static($parent->getHarRequest());
195+
}
196+
197+
public function withHeader($name, $value): ServerRequestInterface
198+
{
199+
$parent = parent::withHeader($name, $value);
200+
201+
return new static($parent->getHarRequest());
202+
}
203+
204+
public function withAddedHeader($name, $value): ServerRequestInterface
205+
{
206+
$parent = parent::withAddedHeader($name, $value);
207+
208+
return new static($parent->getHarRequest());
209+
}
210+
211+
public function withoutHeader($name): ServerRequestInterface
212+
{
213+
$parent = parent::withoutHeader($name);
214+
215+
return new static($parent->getHarRequest());
216+
}
217+
218+
public function withProtocolVersion($version): ServerRequestInterface
219+
{
220+
$parent = parent::withProtocolVersion($version);
221+
222+
return new static($parent->getHarRequest());
223+
}
224+
}

src/PostData.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
use Deviantintegral\Har\SharedFields\CommentTrait;
88
use Deviantintegral\Har\SharedFields\MimeTypeTrait;
99
use Deviantintegral\Har\SharedFields\TextTrait;
10+
use GuzzleHttp\Psr7\Query;
1011
use JMS\Serializer\Annotation as Serializer;
1112

12-
use function GuzzleHttp\Psr7\build_query;
13-
1413
/**
1514
* @see http://www.softwareishard.com/blog/har-12-spec/#postData
1615
*/
@@ -77,7 +76,7 @@ public function getBodySize(): int
7776
foreach ($this->params as $param) {
7877
$query[$param->getName()] = $param->getValue();
7978
}
80-
$string = build_query($query);
79+
$string = Query::build($query);
8180

8281
return \strlen($string);
8382
}

src/Request.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Deviantintegral\Har\SharedFields\HttpVersionTrait;
1212
use JMS\Serializer\Annotation as Serializer;
1313
use Psr\Http\Message\RequestInterface;
14+
use Psr\Http\Message\ServerRequestInterface;
1415

1516
/**
1617
* @see http://www.softwareishard.com/blog/har-12-spec/#request
@@ -75,6 +76,41 @@ public static function fromPsr7Request(RequestInterface $source): self
7576
return $request->getHarRequest();
7677
}
7778

79+
/**
80+
* Construct a new Request from a PSR-7 ServerRequest.
81+
*/
82+
public static function fromPsr7ServerRequest(ServerRequestInterface $source): self
83+
{
84+
// Start with the basic request conversion (ServerRequest extends Request)
85+
$harRequest = static::fromPsr7Request($source);
86+
87+
// Extract and set cookies from ServerRequest
88+
$cookies = [];
89+
foreach ($source->getCookieParams() as $name => $value) {
90+
$cookie = (new Cookie())
91+
->setName($name)
92+
->setValue($value);
93+
$cookies[] = $cookie;
94+
}
95+
if (!empty($cookies)) {
96+
$harRequest->setCookies($cookies);
97+
}
98+
99+
// Extract and set query parameters from ServerRequest
100+
$queryParams = [];
101+
foreach ($source->getQueryParams() as $name => $value) {
102+
$param = (new Params())
103+
->setName($name)
104+
->setValue((string) $value);
105+
$queryParams[] = $param;
106+
}
107+
if (!empty($queryParams)) {
108+
$harRequest->setQueryString($queryParams);
109+
}
110+
111+
return $harRequest;
112+
}
113+
78114
public function getMethod(): string
79115
{
80116
return $this->method;
@@ -104,7 +140,7 @@ public function setUrl(\Psr\Http\Message\UriInterface $url): self
104140
*/
105141
public function getQueryString(): array
106142
{
107-
return $this->queryString;
143+
return $this->queryString ?? [];
108144
}
109145

110146
/**

src/SharedFields/CookiesTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ trait CookiesTrait
2020
*/
2121
public function getCookies(): array
2222
{
23-
return $this->cookies;
23+
return $this->cookies ?? [];
2424
}
2525

2626
/**

src/SharedFields/MimeTypeTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ trait MimeTypeTrait
1919

2020
public function getMimeType(): string
2121
{
22-
return $this->mimeType;
22+
return $this->mimeType ?? '';
2323
}
2424

2525
public function setMimeType(string $mimeType): self

0 commit comments

Comments
 (0)