33namespace Tobyz \JsonApiServer ;
44
55use ArrayObject ;
6+ use HttpAccept \AcceptParser ;
67use Psr \Http \Message \ServerRequestInterface ;
78use RuntimeException ;
89use Tobyz \JsonApiServer \Endpoint \Endpoint ;
10+ use Tobyz \JsonApiServer \Exception \NotAcceptableException ;
911use Tobyz \JsonApiServer \Exception \Request \InvalidSparseFieldsetsException ;
1012use Tobyz \JsonApiServer \Resource \Collection ;
1113use Tobyz \JsonApiServer \Resource \Resource ;
@@ -29,6 +31,8 @@ class Context
2931
3032 private ?array $ body ;
3133 private ?string $ path ;
34+ private ?array $ requestedExtensions = null ;
35+ private ?array $ requestedProfiles = null ;
3236
3337 private WeakMap $ endpoints ;
3438 private WeakMap $ resourceIds ;
@@ -38,6 +42,8 @@ class Context
3842
3943 public function __construct (public JsonApi $ api , public ServerRequestInterface $ request )
4044 {
45+ $ this ->parseAcceptHeader ();
46+
4147 $ this ->endpoints = new WeakMap ();
4248 $ this ->resourceIds = new WeakMap ();
4349 $ this ->modelIds = new WeakMap ();
@@ -211,13 +217,93 @@ public function sortRequested(string $field): bool
211217 return false ;
212218 }
213219
220+ /**
221+ * Determine whether a profile has been requested.
222+ */
223+ public function profileRequested (string $ uri ): bool
224+ {
225+ return in_array ($ uri , $ this ->requestedProfiles ());
226+ }
227+
228+ /**
229+ * Get all requested profile URIs.
230+ *
231+ * @return array
232+ */
233+ public function requestedProfiles (): array
234+ {
235+ if ($ this ->requestedProfiles === null ) {
236+ $ this ->parseAcceptHeader ();
237+ }
238+
239+ return $ this ->requestedProfiles ;
240+ }
241+
242+ /**
243+ * Get all requested extension URIs from Accept header.
244+ *
245+ * @return array
246+ */
247+ public function requestedExtensions (): array
248+ {
249+ if ($ this ->requestedExtensions === null ) {
250+ $ this ->parseAcceptHeader ();
251+ }
252+
253+ return $ this ->requestedExtensions ;
254+ }
255+
256+ private function parseAcceptHeader (): void
257+ {
258+ $ accept = $ this ->request ->getHeaderLine ('Accept ' );
259+
260+ if (!$ accept ) {
261+ $ this ->requestedProfiles = [];
262+ $ this ->requestedExtensions = [];
263+ return ;
264+ }
265+
266+ $ list = (new AcceptParser ())->parse ($ accept );
267+
268+ foreach ($ list as $ mediaType ) {
269+ if (!in_array ($ mediaType ->name (), [$ this ->api ::MEDIA_TYPE , '*/* ' ])) {
270+ continue ;
271+ }
272+
273+ if (array_diff (array_keys ($ mediaType ->parameters ()), ['ext ' , 'profile ' ])) {
274+ continue ;
275+ }
276+
277+ $ extensionUris = $ mediaType ->hasParamater ('ext ' )
278+ ? explode (' ' , $ mediaType ->getParameter ('ext ' ))
279+ : [];
280+
281+ if (array_diff ($ extensionUris , array_keys ($ this ->api ->extensions ))) {
282+ continue ;
283+ }
284+
285+ $ profileUris = $ mediaType ->hasParamater ('profile ' )
286+ ? explode (' ' , $ mediaType ->getParameter ('profile ' ))
287+ : [];
288+
289+ $ this ->requestedProfiles = $ profileUris ;
290+ $ this ->requestedExtensions = $ extensionUris ;
291+ return ;
292+ }
293+
294+ throw new NotAcceptableException ();
295+ }
296+
214297 public function withRequest (ServerRequestInterface $ request ): static
215298 {
216299 $ new = clone $ this ;
217300 $ new ->request = $ request ;
218301 $ new ->sparseFields = new WeakMap ();
219302 $ new ->body = null ;
220303 $ new ->path = null ;
304+ $ new ->requestedProfiles = null ;
305+ $ new ->requestedExtensions = null ;
306+ $ new ->parseAcceptHeader ();
221307 return $ new ;
222308 }
223309
0 commit comments