Skip to content
This repository was archived by the owner on Oct 20, 2025. It is now read-only.

Commit 1e278dc

Browse files
committed
added STRING<> strict type for declaring specific length
1 parent 807596c commit 1e278dc

File tree

3 files changed

+148
-107
lines changed

3 files changed

+148
-107
lines changed

src/Utils/Routes/Exception/InvalidTypesException.php

Lines changed: 115 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -7,111 +7,124 @@
77

88
class InvalidTypesException extends \PhpSlides\Exception
99
{
10-
/**
11-
* @var array $types List of valid data types for route parameters.
12-
*
13-
* The following types are supported:
14-
* - INT: Integer
15-
* - BOOL: Boolean
16-
* - JSON: JSON string
17-
* - ARRAY: Array
18-
* - FLOAT: Floating point number
19-
* - STRING: String
20-
* - BOOLEAN: Boolean (alias for BOOL)
21-
* - INTEGER: Integer (alias for INT)
22-
*/
23-
protected static array $types = [
24-
'INT',
25-
'BOOL',
26-
'JSON',
27-
'ARRAY',
28-
'FLOAT',
29-
'STRING',
30-
'BOOLEN',
31-
'INTEGER',
32-
];
10+
/**
11+
* @var array $types List of valid data types for route parameters.
12+
*
13+
* The following types are supported:
14+
* - INT: Integer
15+
* - BOOL: Boolean
16+
* - JSON: JSON string
17+
* - ARRAY: Array
18+
* - FLOAT: Floating point number
19+
* - STRING: String
20+
* - BOOLEAN: Boolean (alias for BOOL)
21+
* - INTEGER: Integer (alias for INT)
22+
*/
23+
protected static array $types = [
24+
'INT',
25+
'BOOL',
26+
'JSON',
27+
'ARRAY',
28+
'FLOAT',
29+
'STRING',
30+
'BOOLEN',
31+
'INTEGER',
32+
];
3333

34+
/**
35+
* Catches invalid strict types and throws an exception if any are found.
36+
*
37+
* @param array|string $type The type(s) to check against the recognized URL parameter types.
38+
* @param ?Closure $message Optional closure to generate a custom exception message.
39+
*
40+
* @throws self If any of the provided types are not recognized as URL parameter types.
41+
*/
42+
public static function catchInvalidStrictTypes(
43+
array|string $type,
44+
?Closure $message = null,
45+
): void {
46+
if (is_array($type)) {
47+
$type = array_map(fn($t) => strtoupper($t), $type);
3448

35-
/**
36-
* Catches invalid strict types and throws an exception if any are found.
37-
*
38-
* @param array|string $type The type(s) to check against the recognized URL parameter types.
39-
* @param ?Closure $message Optional closure to generate a custom exception message.
40-
*
41-
* @throws self If any of the provided types are not recognized as URL parameter types.
42-
*/
43-
public static function catchInvalidStrictTypes (array|string $type, ?Closure $message = null): void
44-
{
45-
if (is_array($type))
46-
{
47-
$type = array_map(fn($t) => strtoupper($t), $type);
48-
49-
foreach ($type as $t)
50-
{
51-
if (!in_array($t, self::$types) && !preg_match('/<(.+)>/', (string) $t))
52-
{
53-
if (!$message)
54-
{
55-
throw new self("{{$t}} is not recognized as a URL parameter type");
56-
}
57-
else
58-
{
59-
throw new self($message((string) $t));
60-
}
61-
}
62-
}
63-
}
64-
else
65-
{
66-
$type = strtoupper($type);
67-
if (!in_array($type, self::$types) && !preg_match('/<(.+)>/', (string) $type))
68-
{
69-
if (!$message)
70-
{
71-
throw new self("{{$type}} is not recognized as a URL parameter type");
72-
}
73-
else
74-
{
75-
throw new self($message((string) $type));
76-
}
77-
}
78-
}
79-
}
49+
foreach ($type as $t) {
50+
if (
51+
!in_array($t, self::$types) &&
52+
!self::matchStrictType((string) $t)
53+
) {
54+
$t = preg_replace('/<[^<>]*>/', '', $t);
8055

56+
if (!$message) {
57+
throw new self(
58+
"{{$t}} is not recognized as a URL parameter type",
59+
);
60+
} else {
61+
throw new self($message((string) $t));
62+
}
63+
}
64+
}
65+
} else {
66+
$type = strtoupper($type);
67+
if (
68+
!in_array($type, self::$types) &&
69+
!self::matchStrictType((string) $type)
70+
) {
71+
$type = preg_replace('/<[^<>]*>/', '', $type);
8172

82-
/**
83-
* Handles invalid parameter types by setting the HTTP response code and either
84-
* printing a custom error message or throwing an InvalidTypesException.
85-
*
86-
* @param array $typeRequested The types that were expected.
87-
* @param string $typeGotten The type that was actually received.
88-
* @param string|null $message Optional custom error message.
89-
* @param int $code The HTTP response code to set (default is 400).
90-
*
91-
* @return InvalidTypesException
92-
*/
93-
public static function catchInvalidParameterTypes (array $typeRequested, string $typeGotten, ?string $message = null, int $code = 400): InvalidTypesException
94-
{
95-
http_response_code($code);
73+
if (!$message) {
74+
throw new self(
75+
"{{$type}} is not recognized as a URL parameter type",
76+
);
77+
} else {
78+
throw new self($message((string) $type));
79+
}
80+
}
81+
}
82+
}
9683

97-
if (Application::$handleInvalidParameterType)
98-
{
99-
print_r((Application::$handleInvalidParameterType)($typeGotten));
100-
exit();
101-
}
102-
else
103-
{
104-
if (!$message)
105-
{
106-
$requested = implode(', ', $typeRequested);
107-
$requested = preg_replace('/<[^<>]*>/', '', $requested);
84+
/**
85+
* Handles invalid parameter types by setting the HTTP response code and either
86+
* printing a custom error message or throwing an InvalidTypesException.
87+
*
88+
* @param array $typeRequested The types that were expected.
89+
* @param string $typeGotten The type that was actually received.
90+
* @param string|null $message Optional custom error message.
91+
* @param int $code The HTTP response code to set (default is 400).
92+
*
93+
* @return InvalidTypesException
94+
*/
95+
public static function catchInvalidParameterTypes(
96+
array $typeRequested,
97+
string $typeGotten,
98+
?string $message = null,
99+
int $code = 400,
100+
): InvalidTypesException {
101+
http_response_code($code);
108102

109-
return new self(htmlspecialchars("Invalid request parameter type: Expected {{$requested}}, but received {{$typeGotten}}."));
110-
}
111-
else
112-
{
113-
return new self(htmlspecialchars($message));
114-
}
115-
}
116-
}
117-
}
103+
if (Application::$handleInvalidParameterType) {
104+
print_r((Application::$handleInvalidParameterType)($typeGotten));
105+
exit();
106+
} else {
107+
if (!$message) {
108+
$requested = implode(', ', $typeRequested);
109+
$requested = preg_replace('/<[^<>]*>/', '', $requested);
110+
111+
return new self(
112+
htmlspecialchars(
113+
"Invalid request parameter type: Expected {{$requested}}, but received {{$typeGotten}}.",
114+
),
115+
);
116+
} else {
117+
return new self(htmlspecialchars($message));
118+
}
119+
}
120+
}
121+
122+
private static function matchStrictType(string $type)
123+
{
124+
return preg_match('/ARRAY<(.+)>/', (string) $type) ||
125+
preg_match('/INT<(.+)>/', (string) $type) ||
126+
preg_match('/ENUM<(.+)>/', (string) $type) ||
127+
preg_match('/STRING<(.+)>/', (string) $type) ||
128+
preg_match('/INTEGER<(.+)>/', (string) $type);
129+
}
130+
}

src/Utils/Routes/StrictTypes.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ protected static function matchStrictType(
8888
*/
8989
private static function matches(string $needle, string $haystack): bool
9090
{
91+
$haystack = preg_replace('/INTEGER<(.+)>/', 'INT<$1>', $haystack);
92+
9193
$typeOfNeedle = self::typeOfString((string) $needle);
9294
$typeOfNeedle2 = $typeOfNeedle;
9395
$needle2 = $needle;
@@ -106,7 +108,7 @@ private static function matches(string $needle, string $haystack): bool
106108
$requested = implode(', ', $eachArrayTypes);
107109
throw InvalidTypesException::catchInvalidParameterTypes(
108110
$eachArrayTypes,
109-
$typeOfNeedle
111+
$typeOfNeedle,
110112
);
111113
}
112114

@@ -157,7 +159,33 @@ private static function matches(string $needle, string $haystack): bool
157159
(!$max && $needle < $min) ||
158160
($max && ($needle < $min || $needle > $max))
159161
) {
160-
$requested = !$max ? "INT min ($min)" : "INT min ($min), max($max)";
162+
$requested = !$max ? "INT min($min)" : "INT min($min), max($max)";
163+
throw InvalidTypesException::catchInvalidParameterTypes(
164+
[$requested],
165+
(string) $needle,
166+
);
167+
}
168+
return true;
169+
}
170+
171+
/**
172+
* MATCH STRING<MIN, MAX> LENGTH
173+
*/
174+
if (
175+
preg_match('/STRING<(\d+)(?:,\s*(\d+))?>/', $haystack, $matches) &&
176+
$typeOfNeedle === 'STRING'
177+
) {
178+
$min = (int) $matches[1];
179+
$max = (int) $matches[2] ?? null;
180+
$needle = (int) strlen($needle);
181+
182+
if (
183+
(!$max && $needle < $min) ||
184+
($max && ($needle < $min || $needle > $max))
185+
) {
186+
$requested = !$max
187+
? "STRING min($min)"
188+
: "STRING min($min), max($max)";
161189
throw InvalidTypesException::catchInvalidParameterTypes(
162190
[$requested],
163191
(string) $needle,

tests/manualTests/Router/RouteTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
Route::map(
2020
GET,
21-
"$dir/User/{id: int<6, 10>|bool|array<array<int<5,5>|bool>, string>}/{status: enum<success|failed|pending>}",
21+
"$dir/User/{id: int<6, 10>|string<3,3>|bool|array<array<int<5,5>|bool>, string>}/{status: enum<success|failed|pending>}",
2222
)
2323
->action(function (Request $req) {
2424
echo '<br>';
@@ -27,9 +27,9 @@
2727
->route('/posts/{id: int}', function (Request $req, Closure $accept) {
2828
$accept('POST');
2929
})
30-
->handleInvalidParameterType(function ($type) {
30+
/*->handleInvalidParameterType(function ($type) {
3131
return $type;
32-
})
32+
})*/
3333
->caseSensitive();
3434

3535
Render::WebRoute();

0 commit comments

Comments
 (0)