1208909d8SGreg Roach<?php 2208909d8SGreg Roach 3208909d8SGreg Roach/** 4208909d8SGreg Roach * webtrees: online genealogy 5*d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 6208909d8SGreg Roach * This program is free software: you can redistribute it and/or modify 7208909d8SGreg Roach * it under the terms of the GNU General Public License as published by 8208909d8SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9208909d8SGreg Roach * (at your option) any later version. 10208909d8SGreg Roach * This program is distributed in the hope that it will be useful, 11208909d8SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12208909d8SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13208909d8SGreg Roach * GNU General Public License for more details. 14208909d8SGreg Roach * You should have received a copy of the GNU General Public License 15208909d8SGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 16208909d8SGreg Roach */ 17208909d8SGreg Roach 18208909d8SGreg Roachdeclare(strict_types=1); 19208909d8SGreg Roach 20208909d8SGreg Roachnamespace Fisharebest\Webtrees\Factories; 21208909d8SGreg Roach 22208909d8SGreg Roachuse Fig\Http\Message\StatusCodeInterface; 23208909d8SGreg Roachuse Fisharebest\Webtrees\Contracts\ResponseFactoryInterface; 24208909d8SGreg Roachuse Fisharebest\Webtrees\Module\ModuleThemeInterface; 25208909d8SGreg Roachuse Fisharebest\Webtrees\Registry; 26208909d8SGreg Roachuse Fisharebest\Webtrees\Webtrees; 27208909d8SGreg Roachuse Psr\Http\Message\ResponseFactoryInterface as PSR17ResponseFactoryInterface; 28208909d8SGreg Roachuse Psr\Http\Message\ResponseInterface; 29208909d8SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 30208909d8SGreg Roachuse Psr\Http\Message\StreamFactoryInterface; 31208909d8SGreg Roachuse Psr\Http\Message\UriInterface; 32208909d8SGreg Roach 33208909d8SGreg Roachuse function app; 34208909d8SGreg Roachuse function is_string; 35208909d8SGreg Roachuse function json_encode; 36208909d8SGreg Roachuse function view; 37208909d8SGreg Roach 38208909d8SGreg Roachuse const JSON_THROW_ON_ERROR; 39208909d8SGreg Roachuse const JSON_UNESCAPED_UNICODE; 40208909d8SGreg Roach 41208909d8SGreg Roach/** 42208909d8SGreg Roach * Make a PSR-7 response (using a PSR-17 response factory). 43208909d8SGreg Roach */ 44208909d8SGreg Roachclass ResponseFactory implements ResponseFactoryInterface 45208909d8SGreg Roach{ 46208909d8SGreg Roach private PSR17ResponseFactoryInterface $response_factory; 47208909d8SGreg Roach 48208909d8SGreg Roach private StreamFactoryInterface $stream_factory; 49208909d8SGreg Roach 50208909d8SGreg Roach /** 51208909d8SGreg Roach * @param PSR17ResponseFactoryInterface $response_factory 52208909d8SGreg Roach * @param StreamFactoryInterface $stream_factory 53208909d8SGreg Roach */ 54208909d8SGreg Roach public function __construct(PSR17ResponseFactoryInterface $response_factory, StreamFactoryInterface $stream_factory) 55208909d8SGreg Roach { 56208909d8SGreg Roach $this->response_factory = $response_factory; 57208909d8SGreg Roach $this->stream_factory = $stream_factory; 58208909d8SGreg Roach } 59208909d8SGreg Roach 60208909d8SGreg Roach /** 61208909d8SGreg Roach * Redirect to a named route. 62208909d8SGreg Roach * 63208909d8SGreg Roach * @param string $route_name 64208909d8SGreg Roach * @param array<bool|int|string|array<string>|null> $parameters 65208909d8SGreg Roach * @param int $status 66208909d8SGreg Roach * 67208909d8SGreg Roach * @return ResponseInterface 68208909d8SGreg Roach * 69208909d8SGreg Roach */ 70208909d8SGreg Roach public function redirect( 71208909d8SGreg Roach string $route_name, 72208909d8SGreg Roach array $parameters = [], 73208909d8SGreg Roach int $status = StatusCodeInterface::STATUS_FOUND 74208909d8SGreg Roach ): ResponseInterface { 75208909d8SGreg Roach $url = Registry::routeFactory()->route($route_name, $parameters); 76208909d8SGreg Roach 77208909d8SGreg Roach return $this->redirectUrl($url, $status); 78208909d8SGreg Roach } 79208909d8SGreg Roach 80208909d8SGreg Roach /** 81208909d8SGreg Roach * Redirect to a URL. 82208909d8SGreg Roach * 83ac71572dSGreg Roach * @param UriInterface|string $url 84208909d8SGreg Roach * @param int $code 85208909d8SGreg Roach * 86208909d8SGreg Roach * @return ResponseInterface 87208909d8SGreg Roach */ 88ac71572dSGreg Roach public function redirectUrl(UriInterface|string $url, int $code = StatusCodeInterface::STATUS_FOUND): ResponseInterface 89208909d8SGreg Roach { 90208909d8SGreg Roach return $this->response_factory 91208909d8SGreg Roach ->createResponse($code) 926172e7f6SGreg Roach ->withHeader('location', (string) $url); 93208909d8SGreg Roach } 94208909d8SGreg Roach 95208909d8SGreg Roach /** 96208909d8SGreg Roach * @param string|array<mixed>|object $content 97208909d8SGreg Roach * @param int $code 98208909d8SGreg Roach * @param array<string,string> $headers 99208909d8SGreg Roach * 100208909d8SGreg Roach * @return ResponseInterface 101208909d8SGreg Roach */ 102ac71572dSGreg Roach public function response(string|array|object $content = '', int $code = StatusCodeInterface::STATUS_OK, array $headers = []): ResponseInterface 103208909d8SGreg Roach { 104208909d8SGreg Roach if ($content === '' && $code === StatusCodeInterface::STATUS_OK) { 105208909d8SGreg Roach $code = StatusCodeInterface::STATUS_NO_CONTENT; 106208909d8SGreg Roach } 107208909d8SGreg Roach 108208909d8SGreg Roach if (is_string($content)) { 1096172e7f6SGreg Roach $headers['content-type'] ??= 'text/html; charset=UTF-8'; 110208909d8SGreg Roach } else { 111208909d8SGreg Roach $content = json_encode($content, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE); 1126172e7f6SGreg Roach $headers['content-type'] ??= 'application/json'; 113208909d8SGreg Roach } 114208909d8SGreg Roach 115208909d8SGreg Roach $stream = $this->stream_factory->createStream($content); 116208909d8SGreg Roach 117208909d8SGreg Roach $response = $this->response_factory 118208909d8SGreg Roach ->createResponse($code) 119208909d8SGreg Roach ->withBody($stream); 120208909d8SGreg Roach 121208909d8SGreg Roach foreach ($headers as $key => $value) { 122208909d8SGreg Roach $response = $response->withHeader($key, $value); 123208909d8SGreg Roach } 124208909d8SGreg Roach 125208909d8SGreg Roach return $response; 126208909d8SGreg Roach } 127208909d8SGreg Roach 128208909d8SGreg Roach /** 129208909d8SGreg Roach * Create and render a view, and embed it in an HTML page. 130208909d8SGreg Roach * 131208909d8SGreg Roach * @param string $view_name 13224f79581SGreg Roach * @param array<string,mixed> $view_data 133208909d8SGreg Roach * @param int $status 134208909d8SGreg Roach * @param string $layout_name 135208909d8SGreg Roach * 136208909d8SGreg Roach * @return ResponseInterface 137208909d8SGreg Roach */ 138208909d8SGreg Roach public function view( 139208909d8SGreg Roach string $view_name, 140208909d8SGreg Roach array $view_data, 141208909d8SGreg Roach int $status = StatusCodeInterface::STATUS_OK, 142208909d8SGreg Roach string $layout_name = Webtrees::LAYOUT_DEFAULT 143208909d8SGreg Roach ): ResponseInterface { 144208909d8SGreg Roach // Render the view. 145208909d8SGreg Roach $content = view($view_name, $view_data); 146208909d8SGreg Roach 147208909d8SGreg Roach // Make the view's data available to the layout. 148208909d8SGreg Roach $layout_data = [ 149208909d8SGreg Roach 'content' => $content, 150208909d8SGreg Roach 'request' => app(ServerRequestInterface::class), 151208909d8SGreg Roach 'theme' => app(ModuleThemeInterface::class), 152208909d8SGreg Roach 'title' => $view_data['title'] ?? Webtrees::NAME, 153208909d8SGreg Roach ]; 154208909d8SGreg Roach 155d8d90d88SGreg Roach // Embed the content in the layout. 156208909d8SGreg Roach $html = view($layout_name, $layout_data); 157208909d8SGreg Roach 158208909d8SGreg Roach return $this->response($html, $status); 159208909d8SGreg Roach } 160208909d8SGreg Roach} 161