Skip to content

Commit 648b811

Browse files
committed
Merge branch 'cleanup'
2 parents f16b23f + ed530c9 commit 648b811

29 files changed

+1057
-302
lines changed

.php-cs-fixer.dist.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
__DIR__ . '/stubs',
77
__DIR__ . '/tests/unit',
88
__DIR__ . '/tests/fixtures',
9+
__DIR__ . '/tests/3rdparty',
910
__DIR__ . '/lk-util',
1011
__DIR__ . '/scripts',
1112
])

.prettyphp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
"scripts",
66
"src",
77
"stubs",
8+
"tests/3rdparty",
89
"tests/fixtures",
10+
"tests/legacy",
911
"tests/unit",
12+
"tests/phpstan-conditional.php",
1013
"tools/apigen",
14+
".php-cs-fixer.dist.php",
1115
"bootstrap.php"
1216
],
1317
"enable": [

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lkrms/dice": "^4.1.8",
1010
"psr/container": "^2",
1111
"psr/event-dispatcher": "^1",
12+
"psr/http-factory": "^1",
1213
"psr/http-message": "^1.1 || ^2",
1314
"psr/log": "^1"
1415
},
@@ -25,6 +26,7 @@
2526
"clue/phar-composer": "^1",
2627
"firebase/php-jwt": "^6",
2728
"league/oauth2-client": "^2",
29+
"php-http/psr7-integration-tests": "^1.3",
2830
"phpstan/extension-installer": "^1",
2931
"phpstan/phpstan": "^1",
3032
"phpstan/phpstan-deprecation-rules": "^1",
@@ -50,7 +52,8 @@
5052
"Lkrms\\LkUtil\\": "lk-util/",
5153
"Lkrms\\Tests\\": [
5254
"tests/unit/",
53-
"tests/fixtures/"
55+
"tests/fixtures/",
56+
"tests/3rdparty/"
5457
]
5558
},
5659
"files": [

lk-util/Command/Http/SendHttpRequest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Lkrms\Sync\Concept\HttpSyncProvider;
1111
use Lkrms\Utility\Arr;
1212
use Lkrms\Utility\Convert;
13+
use Lkrms\Utility\Get;
1314

1415
/**
1516
* Sends HTTP requests to HTTP sync providers
@@ -147,7 +148,7 @@ protected function run(string ...$args)
147148

148149
if ($this->Paginate) {
149150
/** @var iterable<array-key,mixed> $result */
150-
$array = Convert::iterableToArray($result);
151+
$array = Get::array($result);
151152
$result = $array;
152153
}
153154

phpstan.neon.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ parameters:
1010
- scripts
1111
- src
1212
- stubs
13+
- tests/3rdparty
1314
- tests/fixtures
1415
- tests/unit
16+
- tests/phpstan-conditional.php
1517
- bootstrap.php
1618
ignoreErrors:
1719
- "#^Property Lkrms\\\\.+\\\\Command\\\\.+\\:\\:\\$[a-zA-Z0-9_]+ is never written, only read\\.$#"

phpunit.xml.dist

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@
66
<testsuite name="unit">
77
<directory>tests/unit</directory>
88
</testsuite>
9+
<testsuite name="3rdparty">
10+
<directory>tests/3rdparty</directory>
11+
</testsuite>
912
</testsuites>
13+
<groups>
14+
<exclude>
15+
<group>internet</group>
16+
</exclude>
17+
</groups>
1018
<coverage
1119
cacheDirectory="build/cache/coverage"
1220
pathCoverage="false">
@@ -17,4 +25,24 @@
1725
<html outputDirectory="build/coverage" />
1826
</report>
1927
</coverage>
28+
<php>
29+
<const
30+
name="REQUEST_FACTORY"
31+
value="Lkrms\Http\HttpFactory" />
32+
<const
33+
name="RESPONSE_FACTORY"
34+
value="Lkrms\Http\HttpFactory" />
35+
<const
36+
name="SERVER_REQUEST_FACTORY"
37+
value="Lkrms\Http\HttpFactory" />
38+
<const
39+
name="STREAM_FACTORY"
40+
value="Lkrms\Http\HttpFactory" />
41+
<const
42+
name="UPLOADED_FILE_FACTORY"
43+
value="Lkrms\Http\HttpFactory" />
44+
<const
45+
name="URI_FACTORY"
46+
value="Lkrms\Http\HttpFactory" />
47+
</php>
2048
</phpunit>

src/Http/HttpFactory.php

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Lkrms\Http;
4+
5+
use Lkrms\Exception\MethodNotImplementedException;
6+
use Lkrms\Utility\File;
7+
use Psr\Http\Message\RequestFactoryInterface;
8+
use Psr\Http\Message\RequestInterface;
9+
use Psr\Http\Message\ResponseFactoryInterface;
10+
use Psr\Http\Message\ResponseInterface;
11+
use Psr\Http\Message\ServerRequestFactoryInterface;
12+
use Psr\Http\Message\ServerRequestInterface;
13+
use Psr\Http\Message\StreamFactoryInterface;
14+
use Psr\Http\Message\StreamInterface;
15+
use Psr\Http\Message\UploadedFileFactoryInterface;
16+
use Psr\Http\Message\UploadedFileInterface;
17+
use Psr\Http\Message\UriFactoryInterface;
18+
use Psr\Http\Message\UriInterface;
19+
20+
class HttpFactory implements
21+
RequestFactoryInterface,
22+
ResponseFactoryInterface,
23+
ServerRequestFactoryInterface,
24+
StreamFactoryInterface,
25+
UploadedFileFactoryInterface,
26+
UriFactoryInterface
27+
{
28+
/**
29+
* @inheritDoc
30+
*/
31+
public function createRequest(string $method, $uri): RequestInterface
32+
{
33+
return new HttpRequest($uri, $method);
34+
}
35+
36+
/**
37+
* @inheritDoc
38+
*/
39+
public function createResponse(
40+
int $code = 200,
41+
string $reasonPhrase = ''
42+
): ResponseInterface {
43+
throw new MethodNotImplementedException(
44+
static::class,
45+
__FUNCTION__,
46+
ResponseFactoryInterface::class
47+
);
48+
}
49+
50+
/**
51+
* @inheritDoc
52+
*
53+
* @param array<string,mixed> $serverParams
54+
*/
55+
public function createServerRequest(
56+
string $method,
57+
$uri,
58+
array $serverParams = []
59+
): ServerRequestInterface {
60+
throw new MethodNotImplementedException(
61+
static::class,
62+
__FUNCTION__,
63+
ServerRequestFactoryInterface::class
64+
);
65+
}
66+
67+
/**
68+
* @inheritDoc
69+
*/
70+
public function createStream(string $content = ''): StreamInterface
71+
{
72+
return Stream::fromContents($content);
73+
}
74+
75+
/**
76+
* @inheritDoc
77+
*/
78+
public function createStreamFromFile(
79+
string $filename,
80+
string $mode = 'r'
81+
): StreamInterface {
82+
return new Stream(File::open($filename, $mode));
83+
}
84+
85+
/**
86+
* @inheritDoc
87+
*/
88+
public function createStreamFromResource($resource): StreamInterface
89+
{
90+
return new Stream($resource);
91+
}
92+
93+
/**
94+
* @inheritDoc
95+
*/
96+
public function createUploadedFile(
97+
StreamInterface $stream,
98+
?int $size = null,
99+
int $error = \UPLOAD_ERR_OK,
100+
?string $clientFilename = null,
101+
?string $clientMediaType = null
102+
): UploadedFileInterface {
103+
throw new MethodNotImplementedException(
104+
static::class,
105+
__FUNCTION__,
106+
UploadedFileFactoryInterface::class
107+
);
108+
}
109+
110+
/**
111+
* @inheritDoc
112+
*/
113+
public function createUri(string $uri = ''): UriInterface
114+
{
115+
return (new Uri($uri, false))->normalise();
116+
}
117+
}

src/Http/HttpHeaders.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ public function __construct($items = [])
9090
foreach ($items as $key => $value) {
9191
$values = (array) $value;
9292
if (!$values) {
93-
continue;
93+
throw new InvalidArgumentException(
94+
sprintf('At least one value must be given for HTTP header: %s', $key)
95+
);
9496
}
9597
$lower = strtolower($key);
9698
$key = $this->filterName($key);
@@ -171,7 +173,9 @@ public function add($key, $value)
171173
{
172174
$values = (array) $value;
173175
if (!$values) {
174-
return $this;
176+
throw new InvalidArgumentException(
177+
sprintf('At least one value must be given for HTTP header: %s', $key)
178+
);
175179
}
176180
$lower = strtolower($key);
177181
$headers = $this->Headers;
@@ -189,10 +193,15 @@ public function add($key, $value)
189193
*/
190194
public function set($key, $value)
191195
{
196+
$values = (array) $value;
197+
if (!$values) {
198+
throw new InvalidArgumentException(
199+
sprintf('At least one value must be given for HTTP header: %s', $key)
200+
);
201+
}
192202
$lower = strtolower($key);
193203
$headers = $this->Headers;
194204
$index = $this->Index;
195-
$values = (array) $value;
196205
if (isset($index[$lower])) {
197206
// Return `$this` if existing values are being reapplied
198207
if (count($index[$lower]) === count($values)) {
@@ -255,8 +264,13 @@ public function merge($items, bool $preserveExisting = false)
255264
$index = $this->Index;
256265
$applied = false;
257266
foreach ($items as $key => $value) {
258-
$lower = strtolower($key);
259267
$values = (array) $value;
268+
if (!$values) {
269+
throw new InvalidArgumentException(
270+
sprintf('At least one value must be given for HTTP header: %s', $key)
271+
);
272+
}
273+
$lower = strtolower($key);
260274
if (
261275
!$preserveExisting &&
262276
// Checking against $this->Index instead of $index means any
@@ -268,10 +282,6 @@ public function merge($items, bool $preserveExisting = false)
268282
foreach ($index[$lower] as $i) {
269283
unset($headers[$i]);
270284
}
271-
if (!$values) {
272-
unset($index[$lower]);
273-
continue;
274-
}
275285
// Maintain the order of $index for comparison
276286
$index[$lower] = [];
277287
}

src/Http/HttpRequest.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,7 @@ private function getHost(): string
148148

149149
private function filterMethod(string $method): string
150150
{
151-
$method = Str::upper($method);
152-
if (!HttpRequestMethod::hasValue($method)) {
151+
if (!HttpRequestMethod::hasValue(Str::upper($method))) {
153152
throw new InvalidArgumentException(
154153
sprintf('Invalid HTTP method: %s', $method)
155154
);
@@ -213,8 +212,8 @@ private function filterUri($uri): Uri
213212
{
214213
// `UriInterface` makes no distinction between empty and undefined URI
215214
// components, but `/path?` and `/path` are not necessarily equivalent,
216-
// so URIs are always converted to instances of `Uri`, which surfaces
217-
// empty and undefined queries as `""` and `null` respectively
218-
return Uri::from($uri);
215+
// so URIs are always converted to instances of `Lkrms\Http\Uri`, which
216+
// surfaces empty and undefined queries as `""` and `null` respectively
217+
return Uri::from($uri)->normalise();
219218
}
220219
}

src/Http/Uri.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,11 @@ public function follow($reference): self
443443
*/
444444
public function removeDotSegments(): self
445445
{
446+
// Relative references can only be resolved relative to an absolute URI
447+
if ($this->isReference()) {
448+
return $this;
449+
}
450+
446451
return $this->withPath(File::resolve($this->Path, true));
447452
}
448453

0 commit comments

Comments
 (0)