-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUri.php
More file actions
100 lines (83 loc) · 2.98 KB
/
Uri.php
File metadata and controls
100 lines (83 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<?php
declare(strict_types=1);
namespace TinyBlocks\Http\Internal\Request;
use Psr\Http\Message\ServerRequestInterface;
/**
* Provides access to route parameters extracted from a PSR-7 ServerRequestInterface.
*
* The route parameters are resolved in the following priority:
* 1. The explicitly specified attribute name (default: `__route__`).
* 2. A scan of all known framework attribute keys.
* 3. Direct attribute lookup on the request (for frameworks like Laravel).
*/
final readonly class Uri
{
private const string ROUTE = '__route__';
private function __construct(
private ServerRequestInterface $request,
private string $routeAttributeName,
private RouteParameterResolver $resolver
) {
}
public static function from(ServerRequestInterface $request): Uri
{
return new Uri(
request: $request,
routeAttributeName: self::ROUTE,
resolver: RouteParameterResolver::from(request: $request)
);
}
/**
* Returns a new Uri instance configured to read route parameters from the given attribute name.
*
* @param string $name The request attribute name where route params are stored.
* @return Uri A new instance targeting the specified attribute.
*/
public function route(string $name = self::ROUTE): Uri
{
return new Uri(
request: $this->request,
routeAttributeName: $name,
resolver: $this->resolver
);
}
/**
* Retrieves a single route parameter by key.
*
* Resolution order:
* 1. Look up the configured attribute name and extract the key from it.
* 2. If not found, scan all known framework attribute keys.
* 3. If still not found, try a direct `getAttribute($key)` on the request.
* 4. Falls back to `Attribute::from(null)` which provides safe defaults.
*
* @param string $key The route parameter name.
* @return Attribute A typed wrapper around the resolved value.
*/
public function get(string $key): Attribute
{
$value = $this->resolveValue(key: $key);
return Attribute::from(value: $value);
}
private function resolveValue(string $key): mixed
{
$parameters = $this->resolver->resolve(attributeName: $this->routeAttributeName);
if (array_key_exists($key, $parameters)) {
return $parameters[$key];
}
$attribute = $this->request->getAttribute($this->routeAttributeName);
if (is_scalar($attribute)) {
return $attribute;
}
return $this->resolveFromFallbacks(key: $key);
}
private function resolveFromFallbacks(string $key): mixed
{
if ($this->routeAttributeName === self::ROUTE) {
$allKnown = $this->resolver->resolveFromKnownAttributes();
if (array_key_exists($key, $allKnown)) {
return $allKnown[$key];
}
}
return $this->resolver->resolveDirectAttribute(key: $key);
}
}