5
5
namespace WordPress \AiClient \Providers \Http \DTO ;
6
6
7
7
use InvalidArgumentException ;
8
+ use JsonException ;
8
9
use WordPress \AiClient \Common \AbstractDataTransferObject ;
9
10
use WordPress \AiClient \Providers \Http \Enums \HttpMethodEnum ;
10
11
@@ -47,6 +48,11 @@ class Request extends AbstractDataTransferObject
47
48
*/
48
49
protected array $ headers ;
49
50
51
+ /**
52
+ * @var array<string, string> Map of lowercase header names to actual header names for fast lookup.
53
+ */
54
+ protected array $ headersMap ;
55
+
50
56
/**
51
57
* @var string|array<string, mixed>|null The request data.
52
58
*/
@@ -73,6 +79,7 @@ public function __construct(HttpMethodEnum $method, string $uri, array $headers
73
79
$ this ->method = $ method ;
74
80
$ this ->uri = $ uri ;
75
81
$ this ->headers = $ this ->normalizeHeaders ($ headers );
82
+ $ this ->headersMap = $ this ->buildHeadersMap ($ this ->headers );
76
83
$ this ->data = $ data ;
77
84
}
78
85
@@ -120,6 +127,50 @@ public function getHeaders(): array
120
127
return $ this ->headers ;
121
128
}
122
129
130
+ /**
131
+ * Gets a specific header value.
132
+ *
133
+ * @since n.e.x.t
134
+ *
135
+ * @param string $name The header name (case-insensitive).
136
+ * @return list<string>|null The header value(s) or null if not found.
137
+ */
138
+ public function getHeader (string $ name ): ?array
139
+ {
140
+ $ lower = strtolower ($ name );
141
+ if (!isset ($ this ->headersMap [$ lower ])) {
142
+ return null ;
143
+ }
144
+ return $ this ->headers [$ this ->headersMap [$ lower ]];
145
+ }
146
+
147
+ /**
148
+ * Gets the first value of a specific header.
149
+ *
150
+ * @since n.e.x.t
151
+ *
152
+ * @param string $name The header name (case-insensitive).
153
+ * @return string|null The first header value or null if not found.
154
+ */
155
+ public function getHeaderLine (string $ name ): ?string
156
+ {
157
+ $ values = $ this ->getHeader ($ name );
158
+ return $ values !== null ? implode (', ' , $ values ) : null ;
159
+ }
160
+
161
+ /**
162
+ * Checks if a header exists.
163
+ *
164
+ * @since n.e.x.t
165
+ *
166
+ * @param string $name The header name (case-insensitive).
167
+ * @return bool True if the header exists, false otherwise.
168
+ */
169
+ public function hasHeader (string $ name ): bool
170
+ {
171
+ return isset ($ this ->headersMap [strtolower ($ name )]);
172
+ }
173
+
123
174
/**
124
175
* Gets the request body.
125
176
*
@@ -176,12 +227,8 @@ public function getBody(): ?string
176
227
*/
177
228
private function getContentType (): ?string
178
229
{
179
- foreach ($ this ->headers as $ name => $ values ) {
180
- if (strcasecmp ($ name , 'Content-Type ' ) === 0 ) {
181
- return $ values [0 ] ?? null ;
182
- }
183
- }
184
- return null ;
230
+ $ values = $ this ->getHeader ('Content-Type ' );
231
+ return $ values !== null ? $ values [0 ] : null ;
185
232
}
186
233
187
234
/**
@@ -231,6 +278,23 @@ private function normalizeHeaders(array $headers): array
231
278
return $ normalized ;
232
279
}
233
280
281
+ /**
282
+ * Builds a map of lowercase header names to actual header names.
283
+ *
284
+ * @since n.e.x.t
285
+ *
286
+ * @param array<string, list<string>> $headers The headers.
287
+ * @return array<string, string> The headers map.
288
+ */
289
+ private function buildHeadersMap (array $ headers ): array
290
+ {
291
+ $ map = [];
292
+ foreach (array_keys ($ headers ) as $ name ) {
293
+ $ map [strtolower ($ name )] = $ name ;
294
+ }
295
+ return $ map ;
296
+ }
297
+
234
298
/**
235
299
* Gets the request data.
236
300
*
0 commit comments