Skip to content

Commit 308ef2a

Browse files
committed
Adding support for BackedEnum
1 parent de028d9 commit 308ef2a

File tree

12 files changed

+196
-67
lines changed

12 files changed

+196
-67
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All Notable changes to `League\Uri\Interfaces` will be documented in this file
88

99
- `QueryString::compose` and `QueryString::composeFromValue` a userland improved `http_build_query` method.
1010
- `QueryExtractMode` and `QueryComposeMode` Enum to improve query parsing and building.
11+
- Added support for `BackedEnum`
1112

1213
### Fixed
1314

Contracts/Conditionable.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
namespace League\Uri\Contracts;
1515

16+
/**
17+
* @method self tap(callable $callback) Executes the given callback with the current instance and returns the instance unchanged.
18+
*/
1619
interface Conditionable
1720
{
1821
/**

Encoder.php

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313

1414
namespace League\Uri;
1515

16+
use BackedEnum;
1617
use Closure;
1718
use Deprecated;
1819
use League\Uri\Contracts\UriComponentInterface;
1920
use League\Uri\Exceptions\SyntaxError;
2021
use League\Uri\IPv6\Converter as IPv6Converter;
22+
use PhpBench\Report\Func\FitToAxis;
2123
use SensitiveParameter;
2224
use Stringable;
2325

@@ -64,10 +66,14 @@ final class Encoder
6466
/**
6567
* Tell whether the user component is correctly encoded.
6668
*/
67-
public static function isUserEncoded(Stringable|string|null $encoded): bool
69+
public static function isUserEncoded(BackedEnum|Stringable|string|null $encoded): bool
6870
{
6971
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.']+|'.self::REGEXP_PART_ENCODED.'/';
7072

73+
if ($encoded instanceof BackedEnum) {
74+
$encoded = $encoded->value;
75+
}
76+
7177
return null === $encoded || 1 !== preg_match($pattern, (string) $encoded);
7278
}
7379

@@ -76,11 +82,11 @@ public static function isUserEncoded(Stringable|string|null $encoded): bool
7682
*
7783
* All generic delimiters MUST be encoded
7884
*/
79-
public static function encodeUser(Stringable|string|null $component): ?string
85+
public static function encodeUser(BackedEnum|Stringable|string|null $user): ?string
8086
{
8187
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.']+|'.self::REGEXP_PART_ENCODED.'/';
8288

83-
return self::encode($component, $pattern);
89+
return self::encode($user, $pattern);
8490
}
8591

8692
/**
@@ -90,7 +96,7 @@ public static function encodeUser(Stringable|string|null $component): ?string
9096
* any characters. To determine what characters to encode, please refer to
9197
* RFC 3986.
9298
*/
93-
public static function normalizeUser(Stringable|string|null $user): ?string
99+
public static function normalizeUser(BackedEnum|Stringable|string|null $user): ?string
94100
{
95101
return self::normalize(self::encodeUser(self::decodeUnreservedCharacters($user)));
96102
}
@@ -111,10 +117,14 @@ private static function normalize(?string $component): ?string
111117
/**
112118
* Tell whether the password component is correctly encoded.
113119
*/
114-
public static function isPasswordEncoded(#[SensitiveParameter] Stringable|string|null $encoded): bool
120+
public static function isPasswordEncoded(#[SensitiveParameter] BackedEnum|Stringable|string|null $encoded): bool
115121
{
116122
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.':]+|'.self::REGEXP_PART_ENCODED.'/';
117123

124+
if ($encoded instanceof BackedEnum) {
125+
$encoded = $encoded->value;
126+
}
127+
118128
return null === $encoded || 1 !== preg_match($pattern, (string) $encoded);
119129
}
120130

@@ -123,7 +133,7 @@ public static function isPasswordEncoded(#[SensitiveParameter] Stringable|string
123133
*
124134
* Generic delimiters ":" MUST NOT be encoded
125135
*/
126-
public static function encodePassword(#[SensitiveParameter] Stringable|string|null $component): ?string
136+
public static function encodePassword(#[SensitiveParameter] BackedEnum|Stringable|string|null $component): ?string
127137
{
128138
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.':]+|'.self::REGEXP_PART_ENCODED.'/';
129139

@@ -137,32 +147,40 @@ public static function encodePassword(#[SensitiveParameter] Stringable|string|nu
137147
* any characters. To determine what characters to encode, please refer to
138148
* RFC 3986.
139149
*/
140-
public static function normalizePassword(#[SensitiveParameter] Stringable|string|null $password): ?string
150+
public static function normalizePassword(#[SensitiveParameter] BackedEnum|Stringable|string|null $password): ?string
141151
{
142152
return self::normalize(self::encodePassword(self::decodeUnreservedCharacters($password)));
143153
}
144154

145155
/**
146156
* Tell whether the userInfo component is correctly encoded.
147157
*/
148-
public static function isUserInfoEncoded(#[SensitiveParameter] Stringable|string|null $userInfo): bool
158+
public static function isUserInfoEncoded(#[SensitiveParameter] BackedEnum|Stringable|string|null $userInfo): bool
149159
{
150160
if (null === $userInfo) {
151161
return true;
152162
}
153163

164+
if ($userInfo instanceof BackedEnum) {
165+
$userInfo = $userInfo->value;
166+
}
167+
154168
[$user, $password] = explode(':', (string) $userInfo, 2) + [1 => null];
155169

156170
return self::isUserEncoded($user)
157171
&& self::isPasswordEncoded($password);
158172
}
159173

160-
public static function encodeUserInfo(#[SensitiveParameter] Stringable|string|null $userInfo): ?string
174+
public static function encodeUserInfo(#[SensitiveParameter] BackedEnum|Stringable|string|null $userInfo): ?string
161175
{
162176
if (null === $userInfo) {
163177
return null;
164178
}
165179

180+
if ($userInfo instanceof BackedEnum) {
181+
$userInfo = $userInfo->value;
182+
}
183+
166184
[$user, $password] = explode(':', (string) $userInfo, 2) + [1 => null];
167185
$userInfo = self::encodeUser($user);
168186
if (null === $password) {
@@ -172,12 +190,16 @@ public static function encodeUserInfo(#[SensitiveParameter] Stringable|string|nu
172190
return $userInfo.':'.self::encodePassword($password);
173191
}
174192

175-
public static function normalizeUserInfo(#[SensitiveParameter] Stringable|string|null $userInfo): ?string
193+
public static function normalizeUserInfo(#[SensitiveParameter] BackedEnum|Stringable|string|null $userInfo): ?string
176194
{
177195
if (null === $userInfo) {
178196
return null;
179197
}
180198

199+
if ($userInfo instanceof BackedEnum) {
200+
$userInfo = $userInfo->value;
201+
}
202+
181203
[$user, $password] = explode(':', (string) $userInfo, 2) + [1 => null];
182204
$userInfo = self::normalizeUser($user);
183205
if (null === $password) {
@@ -190,15 +212,15 @@ public static function normalizeUserInfo(#[SensitiveParameter] Stringable|string
190212
/**
191213
* Decodes all the URI component characters.
192214
*/
193-
public static function decodeAll(Stringable|string|null $component): ?string
215+
public static function decodeAll(BackedEnum|Stringable|string|null $component): ?string
194216
{
195217
return self::decode($component, static fn (array $matches): string => rawurldecode($matches[0]));
196218
}
197219

198220
/**
199221
* Decodes the URI component without decoding the unreserved characters which are already encoded.
200222
*/
201-
public static function decodeNecessary(Stringable|string|int|null $component): ?string
223+
public static function decodeNecessary(BackedEnum|Stringable|string|int|null $component): ?string
202224
{
203225
$decoder = static function (array $matches): string {
204226
if (1 === preg_match(self::REGEXP_CHARS_PREVENTS_DECODING, $matches[0])) {
@@ -214,8 +236,12 @@ public static function decodeNecessary(Stringable|string|int|null $component): ?
214236
/**
215237
* Decodes the component unreserved characters.
216238
*/
217-
public static function decodeUnreservedCharacters(Stringable|string|null $str): ?string
239+
public static function decodeUnreservedCharacters(BackedEnum|Stringable|string|null $str): ?string
218240
{
241+
if ($str instanceof BackedEnum) {
242+
$str = $str->value;
243+
}
244+
219245
if (null === $str) {
220246
return null;
221247
}
@@ -230,10 +256,14 @@ public static function decodeUnreservedCharacters(Stringable|string|null $str):
230256
/**
231257
* Tell whether the path component is correctly encoded.
232258
*/
233-
public static function isPathEncoded(Stringable|string|null $encoded): bool
259+
public static function isPathEncoded(BackedEnum|Stringable|string|null $encoded): bool
234260
{
235261
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.':@\/]+|'.self::REGEXP_PART_ENCODED.'/';
236262

263+
if ($encoded instanceof BackedEnum) {
264+
$encoded = $encoded->value;
265+
}
266+
237267
return null === $encoded || 1 !== preg_match($pattern, (string) $encoded);
238268
}
239269

@@ -242,7 +272,7 @@ public static function isPathEncoded(Stringable|string|null $encoded): bool
242272
*
243273
* Generic delimiters ":", "@", and "/" MUST NOT be encoded
244274
*/
245-
public static function encodePath(Stringable|string|null $component): string
275+
public static function encodePath(BackedEnum|Stringable|string|null $component): string
246276
{
247277
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.':@\/]+|'.self::REGEXP_PART_ENCODED.'/';
248278

@@ -252,7 +282,7 @@ public static function encodePath(Stringable|string|null $component): string
252282
/**
253283
* Decodes the path component while preserving characters that should not be decoded in the context of a full valid URI.
254284
*/
255-
public static function decodePath(Stringable|string|null $path): ?string
285+
public static function decodePath(BackedEnum|Stringable|string|null $path): ?string
256286
{
257287
$decoder = static function (array $matches): string {
258288
$encodedChar = strtoupper($matches[0]);
@@ -270,25 +300,28 @@ public static function decodePath(Stringable|string|null $path): ?string
270300
* any characters. To determine what characters to encode, please refer to
271301
* RFC 3986.
272302
*/
273-
public static function normalizePath(Stringable|string|null $component): ?string
303+
public static function normalizePath(BackedEnum|Stringable|string|null $component): ?string
274304
{
275305
return self::normalize(self::encodePath(self::decodePath($component)));
276306
}
277307

278308
/**
279309
* Tell whether the query component is correctly encoded.
280310
*/
281-
public static function isQueryEncoded(Stringable|string|null $encoded): bool
311+
public static function isQueryEncoded(BackedEnum|Stringable|string|null $encoded): bool
282312
{
283313
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.'\/?%]+|'.self::REGEXP_PART_ENCODED.'/';
314+
if ($encoded instanceof BackedEnum) {
315+
$encoded = $encoded->value;
316+
}
284317

285318
return null === $encoded || 1 !== preg_match($pattern, (string) $encoded);
286319
}
287320

288321
/**
289322
* Decodes the query component while preserving characters that should not be decoded in the context of a full valid URI.
290323
*/
291-
public static function decodeQuery(Stringable|string|null $path): ?string
324+
public static function decodeQuery(BackedEnum|Stringable|string|null $path): ?string
292325
{
293326
$decoder = static function (array $matches): string {
294327
$encodedChar = strtoupper($matches[0]);
@@ -306,25 +339,29 @@ public static function decodeQuery(Stringable|string|null $path): ?string
306339
* any characters. To determine what characters to encode, please refer to
307340
* RFC 3986.
308341
*/
309-
public static function normalizeQuery(Stringable|string|null $query): ?string
342+
public static function normalizeQuery(BackedEnum|Stringable|string|null $query): ?string
310343
{
311344
return self::normalize(self::encodeQueryOrFragment(self::decodeQuery($query)));
312345
}
313346

314347
/**
315348
* Tell whether the query component is correctly encoded.
316349
*/
317-
public static function isFragmentEncoded(Stringable|string|null $encoded): bool
350+
public static function isFragmentEncoded(BackedEnum|Stringable|string|null $encoded): bool
318351
{
319352
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.':@\/?%]|'.self::REGEXP_PART_ENCODED.'/';
320353

354+
if ($encoded instanceof BackedEnum) {
355+
$encoded = $encoded->value;
356+
}
357+
321358
return null === $encoded || 1 !== preg_match($pattern, (string) $encoded);
322359
}
323360

324361
/**
325362
* Decodes the fragment component while preserving characters that should not be decoded in the context of a full valid URI.
326363
*/
327-
public static function decodeFragment(Stringable|string|null $path): ?string
364+
public static function decodeFragment(BackedEnum|Stringable|string|null $path): ?string
328365
{
329366
return self::decode($path, static fn (array $matches): string => '%20' === $matches[0] ? $matches[0] : rawurldecode($matches[0]));
330367
}
@@ -336,7 +373,7 @@ public static function decodeFragment(Stringable|string|null $path): ?string
336373
* any characters. To determine what characters to encode, please refer to
337374
* RFC 3986.
338375
*/
339-
public static function normalizeFragment(Stringable|string|null $fragment): ?string
376+
public static function normalizeFragment(BackedEnum|Stringable|string|null $fragment): ?string
340377
{
341378
return self::normalize(self::encodeQueryOrFragment(self::decodeFragment($fragment)));
342379
}
@@ -350,8 +387,12 @@ public static function normalizeFragment(Stringable|string|null $fragment): ?str
350387
* any characters. To determine what characters to encode, please refer to
351388
* RFC 3986.
352389
*/
353-
public static function normalizeHost(Stringable|string|null $host): ?string
390+
public static function normalizeHost(BackedEnum|Stringable|string|null $host): ?string
354391
{
392+
if ($host instanceof BackedEnum) {
393+
$host = (string) $host->value;
394+
}
395+
355396
if ($host instanceof Stringable) {
356397
$host = (string) $host;
357398
}
@@ -378,7 +419,7 @@ public static function normalizeHost(Stringable|string|null $host): ?string
378419
*
379420
* Generic delimiters ":", "@", "?", and "/" MUST NOT be encoded
380421
*/
381-
public static function encodeQueryOrFragment(Stringable|string|null $component): ?string
422+
public static function encodeQueryOrFragment(BackedEnum|Stringable|string|null $component): ?string
382423
{
383424
static $pattern = '/[^'.self::REGEXP_PART_UNRESERVED.self::REGEXP_PART_SUBDELIM.':@\/?]+|'.self::REGEXP_PART_ENCODED.'/';
384425

@@ -400,6 +441,10 @@ public static function encodeQueryKeyValue(mixed $component): ?string
400441

401442
private static function filterComponent(mixed $component): ?string
402443
{
444+
if ($component instanceof BackedEnum) {
445+
$component = $component->value;
446+
}
447+
403448
return match (true) {
404449
true === $component => '1',
405450
false === $component => '0',
@@ -414,7 +459,7 @@ private static function filterComponent(mixed $component): ?string
414459
/**
415460
* Encodes the URI component characters using a regular expression to find which characters need encoding.
416461
*/
417-
private static function encode(Stringable|string|int|bool|null $component, string $pattern): ?string
462+
private static function encode(BackedEnum|Stringable|string|int|bool|null $component, string $pattern): ?string
418463
{
419464
$component = self::filterComponent($component);
420465
if (null === $component || '' === $component) {
@@ -431,7 +476,7 @@ private static function encode(Stringable|string|int|bool|null $component, strin
431476
/**
432477
* Decodes the URI component characters using a closure.
433478
*/
434-
private static function decode(Stringable|string|int|null $component, Closure $decoder): ?string
479+
private static function decode(BackedEnum|Stringable|string|int|null $component, Closure $decoder): ?string
435480
{
436481
$component = self::filterComponent($component);
437482
if (null === $component || '' === $component) {
@@ -461,7 +506,7 @@ private static function decode(Stringable|string|int|null $component, Closure $d
461506
* Create a new instance from the environment.
462507
*/
463508
#[Deprecated(message:'use League\Uri\Encoder::decodeNecessary() instead', since:'league/uri:7.6.0')]
464-
public static function decodePartial(Stringable|string|int|null $component): ?string
509+
public static function decodePartial(BackedEnum|Stringable|string|int|null $component): ?string
465510
{
466511
return self::decodeNecessary($component);
467512
}

Exceptions/ConversionFailed.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace League\Uri\Exceptions;
1515

16+
use BackedEnum;
1617
use League\Uri\Idna\Error;
1718
use League\Uri\Idna\Result;
1819
use Stringable;
@@ -27,10 +28,14 @@ private function __construct(
2728
parent::__construct($message);
2829
}
2930

30-
public static function dueToIdnError(Stringable|string $host, Result $result): self
31+
public static function dueToIdnError(BackedEnum|Stringable|string $host, Result $result): self
3132
{
3233
$reasons = array_map(fn (Error $error): string => $error->description(), $result->errors());
3334

35+
if ($host instanceof BackedEnum) {
36+
$host = (string) $host->value;
37+
}
38+
3439
return new self('Host `'.$host.'` is invalid: '.implode('; ', $reasons).'.', (string) $host, $result);
3540
}
3641

0 commit comments

Comments
 (0)