toResourceDocument($data, $context); return $this->jsonApi(200, $document); } public function created(string $location, mixed $data, array $context = []): ResponseInterface { $document = $this->toResourceDocument($data, $context); $response = $this->jsonApi(201, $document); return $response->withHeader('Location', $location); } public function error(int $status, string $title, ?string $detail = null, array $meta = []): ResponseInterface { $payload = [ 'errors' => [[ 'status' => (string) $status, 'title' => $title, 'detail' => $detail, 'meta' => (object) $meta, ]], ]; return $this->jsonApi($status, $payload); } private function jsonApi(int $status, array $document): ResponseInterface { // If neomerx/json-api is installed, you can swap this simple encoding with its encoder. $json = json_encode($document, JSON_THROW_ON_ERROR); $stream = Stream::create($json); return (new Response($status, ['Content-Type' => 'application/vnd.api+json']))->withBody($stream); } /** * Convert domain data to a very simple JSON:API resource document. * Context may include: 'type' (required for non-array scalars), 'id', 'includes', 'links', 'meta'. * This is intentionally minimal until a full encoder is wired. * * @param mixed $data * @param array $context * @return array */ private function toResourceDocument(mixed $data, array $context): array { // If neomerx/json-api not present, produce a simple document requiring caller to provide 'type'. if (!isset($context['type'])) { // Keep developer feedback explicit to encourage proper setup. throw new LogicException('JSON:API response requires context["type"]. Consider installing neomerx/json-api for advanced encoding.'); } $resource = [ 'type' => (string) $context['type'], ]; if (is_array($data) && array_key_exists('id', $data)) { $resource['id'] = (string) $data['id']; $attributes = $data; unset($attributes['id']); } else { $attributes = $data; if (isset($context['id'])) { $resource['id'] = (string) $context['id']; } } $resource['attributes'] = $attributes; $document = ['data' => $resource]; if (!empty($context['links']) && is_array($context['links'])) { $document['links'] = $context['links']; } if (!empty($context['meta']) && is_array($context['meta'])) { $document['meta'] = $context['meta']; } return $document; } }