browserCacheMaxAge = $browserCacheMaxAge; $this->defaultName = $defaultName; $this->i18nService = $i18nService; $this->manifestData = $manifestData; $this->reactOnPath = $reactOnPath; $this->resourceManager = $resourceManager; $this->responseCache = $responseCache; } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { if ($request->getUri()->getPath() === $this->reactOnPath) { return $this->createResponse($request); } return $handler->handle($request); } /** * @param ServerRequestInterface $request * @return ResponseInterface * @throws CacheException * @throws InvalidDataException * @throws \JsonException * @throws Exception * @throws MissingActionNameException */ protected function createResponse(ServerRequestInterface $request): ResponseInterface { $cacheId = (string)$this->i18nService->getConfiguration()->getCurrentLocale(); if ($this->responseCache->has($cacheId)) { $response = $this->responseCache->get($cacheId); } else { $result = $this->manifestData; if ($result['name'] === null) { $result['name'] = $this->defaultName; } if ($result['short_name'] === null) { $result['short_name'] = $this->defaultName; } if ($result['lang'] === null) { $result['lang'] = \str_replace( '_', '-', (string)$this->i18nService->getConfiguration()->getCurrentLocale() ); } foreach ($this->uriProperties as $uriProperty) { if (\is_array($result[$uriProperty])) { $uriBuilder = new UriBuilder(); $uriBuilder->setRequest(ActionRequest::fromHttpRequest($request)); if (isset($result[$uriProperty]['format']) && \is_string($result[$uriProperty]['format'])) { $uriBuilder->setFormat($result[$uriProperty]['format']); } if (!isset($result[$uriProperty]['action'])) { throw new \InvalidArgumentException( 'if ' . $uriProperty . ' is in array form, action is required', 1718957544 ); } $result[$uriProperty] = $uriBuilder->uriFor( $result[$uriProperty]['action'], $result[$uriProperty]['arguments'] ?? [], $result[$uriProperty]['controller'] ?? null, $result[$uriProperty]['package'] ?? null, $result[$uriProperty]['subPackage'] ?? null, ); } } foreach ($result['icons'] as &$iconData) { if (!isset($iconData['src']) || !isset($iconData['sizes']) || !isset($iconData['type'])) { throw new \InvalidArgumentException( 'Icons in manifests require src, sizes and type', 1718961281 ); } if (\str_starts_with($iconData['src'], 'resource://')) { $iconData['src'] = $this->resourceManager->getPublicPackageResourceUriByPath($iconData['src']); } } unset($iconData); if ($result['id'] === null) { $result['id'] = $result['start_url']; } $response = \json_encode($result, \JSON_THROW_ON_ERROR); $this->responseCache->set($cacheId, $response); } return new Response( 200, [ 'Content-Type' => 'application/manifest+json', 'Cache-Control' => 'max-age=' . $this->browserCacheMaxAge . ', must-revalidate', 'Last-Modified' => $this->getCacheDate(), 'Vary' => 'Accept, Accept-Language' ], $response ); } protected function getCacheDate(): string { if (false === $lastModified = $this->responseCache->get('lastModified')) { $lastModified = (new \DateTimeImmutable())->format(\DATE_RFC7231); $this->responseCache->set('lastModified', $lastModified); } return $lastModified; } }