Lines
89.85%
62 / 69
Methods
66.66%
8 / 12
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| withHtml | 86.66% | 13 / 15 | 0.00% | 0 / 1 | 5.06 | ||
| html | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| withXml | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| withJson | 100.00% | 7 / 7 | 100.00% | 1 / 1 | 2 | ||
| json | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| xml | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| withLastModified | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| lastModified | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| getCachableResponse | 78.57% | 11 / 14 | 0.00% | 0 / 1 | 5.25 | ||
| redirect | 100.00% | 11 / 11 | 100.00% | 1 / 1 | 4 | ||
| requireContainer | 75.00% | 3 / 4 | 0.00% | 0 / 1 | 2.06 | ||
| requireResponse | 66.66% | 2 / 3 | 0.00% | 0 / 1 | 2.15 | ||
| 16 | class Render | |
| 17 | { | |
| 18 | public static ?ContainerInterface $container = null; | |
| 19 | ||
| 20 | public static ?RequestInterface $request = null; | |
| 21 | ||
| 22 | public static ?ResponseInterface $response = null; | |
| 23 | ||
| 24 | public static function withHtml( | |
| 25 | ResponseInterface $response, | |
| 26 | string $template, | |
| 27 | array $parameters = [], | |
| 28 | int $status = 200 | |
| 29 | ): ResponseInterface { | |
| 30 | Profiler::add("Controller"); | |
| 31 | $response = $response->withStatus($status); | |
| 32 | $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8'); | |
| 33 | App::$templatedefaults['debug'] = App::DEBUG; | |
| 34 | $request = self::$request; | |
| 35 | if (null === $request && null !== self::$container) { | |
| 36 | $request = self::$container->get('request'); | |
| 37 | $request = $request instanceof RequestInterface ? $request : null; | |
| 38 | } | |
| 39 | $templateRequest = $request instanceof Request ? $request : null; | |
| 40 | App::$templatedefaults['includeUrl'] = Helper\TemplateUrls::resolveIncludeUrl($templateRequest); | |
| 41 | App::$templatedefaults['baseUrl'] = Helper\TemplateUrls::resolveBaseUrl($templateRequest); | |
| 42 | $parameters = array_merge(App::$templatedefaults, $parameters); | |
| 43 | $response = self::requireContainer()->get('view')->render($response, $template, $parameters); | |
| 44 | Profiler::add("Rendering"); | |
| 45 | return $response ; | |
| 46 | } | |
| 47 | ||
| 48 | public static function html(string $template, array $parameters = [], int $status = 200): ResponseInterface | |
| 49 | { | |
| 50 | self::$response = self::withHtml(self::requireResponse(), $template, $parameters, $status); | |
| 51 | return self::$response; | |
| 52 | } | |
| 53 | ||
| 54 | public static function withXml(ResponseInterface $response, string $data, int $status = 200): ResponseInterface | |
| 55 | { | |
| 56 | Profiler::add("Controller"); | |
| 57 | $response = $response->withStatus($status); | |
| 58 | $response = $response->withHeader('Content-Type', 'application/soap+xml'); | |
| 59 | $response->getBody()->write($data); | |
| 60 | Profiler::add("Rendering"); | |
| 61 | return $response; | |
| 62 | } | |
| 63 | ||
| 64 | public static function withJson(ResponseInterface $response, mixed $data, int $status = 200): ResponseInterface | |
| 65 | { | |
| 66 | Profiler::add("Controller"); | |
| 67 | $response = $response->withStatus($status); | |
| 68 | $response = $response->withHeader('Content-Type', 'application/json'); | |
| 69 | $payload = json_encode($data, JSON_UNESCAPED_SLASHES); | |
| 70 | $response->getBody()->write($payload !== false ? $payload : 'null'); | |
| 71 | Profiler::add("Rendering"); | |
| 72 | return $response; | |
| 73 | } | |
| 74 | ||
| 75 | public static function json(mixed $data, int $status = 200): ResponseInterface | |
| 76 | { | |
| 77 | self::$response = self::withJson(self::requireResponse(), $data, $status); | |
| 78 | return self::$response; | |
| 79 | } | |
| 80 | ||
| 81 | public static function xml(string $data, int $status = 200): ResponseInterface | |
| 82 | { | |
| 83 | self::$response = self::withXml(self::requireResponse(), $data, $status); | |
| 84 | return self::$response; | |
| 85 | } | |
| 86 | ||
| 87 | /** | |
| 88 | * Add `Last-Modified` header to PSR7 response object | |
| 89 | * | |
| 90 | * @param ResponseInterface $response A PSR7 response object | |
| 91 | * @param int|string $date A UNIX timestamp or a valid `strtotime()` string | |
| 92 | * @param string $expires | |
| 93 | * | |
| 94 | * @return ResponseInterface A new PSR7 response object with `Last-Modified` header | |
| 95 | * | |
| 96 | */ | |
| 97 | public static function withLastModified( | |
| 98 | ResponseInterface $response, | |
| 99 | string|int $date, | |
| 100 | string $expires = '+5 minutes' | |
| 101 | ): ResponseInterface { | |
| 102 | return self::getCachableResponse($response, $date, $expires); | |
| 103 | } | |
| 104 | ||
| 105 | /** | |
| 106 | * @param string|int $date strtotime interpreted | |
| 107 | * @param string $expires strtotime interpreted | |
| 108 | * | |
| 109 | * @return ResponseInterface | |
| 110 | */ | |
| 111 | public static function lastModified(string|int $date, string $expires = '+5 minutes'): ResponseInterface | |
| 112 | { | |
| 113 | self::$response = self::withLastModified(self::requireResponse(), $date, $expires); | |
| 114 | return self::$response; | |
| 115 | } | |
| 116 | ||
| 117 | /** | |
| 118 | * @param string|int $date strtotime interpreted | |
| 119 | * @param string $expires strtotime interpreted | |
| 120 | * | |
| 121 | * @return ResponseInterface | |
| 122 | */ | |
| 123 | public static function getCachableResponse( | |
| 124 | ResponseInterface $response, | |
| 125 | string|int $date, | |
| 126 | string $expires = '+5 minutes' | |
| 127 | ): ResponseInterface { | |
| 128 | if (is_int($date)) { | |
| 129 | $timestamp = $date !== 0 ? $date : time(); | |
| 130 | } else { | |
| 131 | $parsed = strtotime($date); | |
| 132 | $timestamp = $parsed !== false ? $parsed : time(); | |
| 133 | } | |
| 134 | ||
| 135 | $expireTs = strtotime($expires); | |
| 136 | if ($expireTs === false) { | |
| 137 | $expires = '+' . $expires . ' seconds'; | |
| 138 | $maxAge = (int) $expires; | |
| 139 | } else { | |
| 140 | $maxAge = $expireTs - time(); | |
| 141 | } | |
| 142 | $response = $response->withAddedHeader('Cache-Control', 'max-age=' . $maxAge); | |
| 143 | $cache = self::requireContainer()->get('cache'); | |
| 144 | $response = $cache->withExpires($response, $expires); | |
| 145 | $response = $cache->withLastModified($response, $timestamp); | |
| 146 | ||
| 147 | return $response; | |
| 148 | } | |
| 149 | ||
| 150 | /** | |
| 151 | * @param string $route_name | |
| 152 | * @param array $arguments parameters in the route path | |
| 153 | * @param array|null $parameter parameters to append with "?" | |
| 154 | * @param int $statuscode see an HTTP reference | |
| 155 | */ | |
| 156 | public static function redirect( | |
| 157 | string $route_name, | |
| 158 | array $arguments, | |
| 159 | ?array $parameter = null, | |
| 160 | int $statuscode = 302 | |
| 161 | ): Response { | |
| 162 | Profiler::add("Controller"); | |
| 163 | ||
| 164 | $url = App::$slim->urlFor($route_name, $arguments); | |
| 165 | $sanitized = Helper::proxySanitizeUri($url); | |
| 166 | $url = is_string($sanitized) ? $sanitized : $url; | |
| 167 | $url = preg_replace('#^.*?(https?://)#', '\1', $url) ?? $url; // allow http:// routes | |
| 168 | if ($parameter !== null && $parameter !== []) { | |
| 169 | $url .= '?' . http_build_query($parameter); | |
| 170 | } | |
| 171 | ||
| 172 | $response = App::$slim->getResponseFactory()->createResponse($statuscode); | |
| 173 | $response = self::requireContainer()->get('cache')->denyCache($response); | |
| 174 | /** @var Response $response */ | |
| 175 | $response = $response->withHeader('Location', $url); | |
| 176 | ||
| 177 | return $response->withAddedHeader('Cache-Control', 'max-age=0'); | |
| 178 | } | |
| 179 | ||
| 180 | private static function requireContainer(): ContainerInterface | |
| 181 | { | |
| 182 | $container = App::$slim->getContainer(); | |
| 183 | if (!$container instanceof ContainerInterface) { | |
| 184 | throw new \RuntimeException('Slim container is not initialized'); | |
| 185 | } | |
| 186 | return $container; | |
| 187 | } | |
| 188 | ||
| 189 | private static function requireResponse(): ResponseInterface | |
| 190 | { | |
| 191 | if (!self::$response instanceof ResponseInterface) { | |
| 192 | throw new \RuntimeException('Render response is not initialized'); | |
| 193 | } | |
| 194 | return self::$response; | |
| 195 | } | |
| 196 | } |