Passed
Push — master ( b972b8...98116b )
by Greg
06:02
created

route()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 13
c 2
b 0
f 0
nc 2
nop 2
dl 0
loc 23
rs 9.8333
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
use Aura\Router\RouterContainer;
21
use Fig\Http\Message\StatusCodeInterface;
22
use Fisharebest\Webtrees\Application;
23
use Fisharebest\Webtrees\Html;
24
use Fisharebest\Webtrees\Session;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Session. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
25
use Fisharebest\Webtrees\View as WebtreesView;
26
use Fisharebest\Webtrees\Webtrees;
27
use Psr\Http\Message\ResponseFactoryInterface;
28
use Psr\Http\Message\ResponseInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Psr\Http\Message\StreamFactoryInterface;
31
32
/**
33
 * Get the IoC container, or fetch something from it.
34
 *
35
 * @param string|null $abstract
36
 *
37
 * @return mixed
38
 */
39
function app(string $abstract = null)
40
{
41
    if ($abstract === null) {
42
        return Application::getInstance();
43
    }
44
45
    return Application::getInstance()->make($abstract);
46
}
47
48
/**
49
 * Generate a URL to an asset file in the public folder.
50
 * Add a version parameter for cache-busting.
51
 *
52
 * @param string $path
53
 *
54
 * @return string
55
 */
56
function asset(string $path): string
57
{
58
    if (substr($path, -1) === '/') {
59
        $version = '';
60
    } elseif (Webtrees::STABILITY === '') {
0 ignored issues
show
introduced by
The condition Fisharebest\Webtrees\Webtrees::STABILITY === '' is always false.
Loading history...
61
        $version = '?v=' . Webtrees::VERSION;
62
    } else {
63
        $version = '?v=' . filemtime(Webtrees::ROOT_DIR . 'public/' . $path);
64
    }
65
66
    $base_url = app(ServerRequestInterface::class)->getAttribute('base_url');
67
68
    return $base_url . '/public/' . $path . $version;
69
}
70
71
/**
72
 * Generate a CSRF token form field.
73
 *
74
 * @return string
75
 */
76
function csrf_field()
77
{
78
    return '<input type="hidden" name="csrf" value="' . e(Session::getCsrfToken()) . '">';
79
}
80
81
/**
82
 * Get the CSRF token value.
83
 *
84
 * @return string
85
 */
86
function csrf_token()
87
{
88
    return Session::getCsrfToken();
89
}
90
91
/**
92
 * @param string $url
93
 * @param int    $code
94
 *
95
 * @return ResponseInterface
96
 */
97
function redirect(string $url, $code = StatusCodeInterface::STATUS_FOUND): ResponseInterface
98
{
99
    /** @var ResponseFactoryInterface $response_factory */
100
    $response_factory = app(ResponseFactoryInterface::class);
101
102
    return $response_factory
103
        ->createResponse($code)
104
        ->withHeader('Location', $url);
105
}
106
107
/**
108
 * Create a response.
109
 *
110
 * @param mixed    $content
111
 * @param int      $code
112
 * @param string[] $headers
113
 *
114
 * @return ResponseInterface
115
 */
116
function response($content = '', $code = StatusCodeInterface::STATUS_OK, $headers = []): ResponseInterface
117
{
118
    if ($content === '' && $code === StatusCodeInterface::STATUS_OK) {
119
        $code = StatusCodeInterface::STATUS_NO_CONTENT;
120
    }
121
122
    if ($headers === []) {
123
        if (is_string($content)) {
124
            $headers = [
125
                'Content-Type'   => 'text/html; charset=utf-8',
126
                'Content-Length' => strlen($content),
127
            ];
128
        } else {
129
            $content = json_encode($content, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
130
            $headers = [
131
                'Content-Type'   => 'application/json',
132
                'Content-Length' => strlen($content),
133
            ];
134
        }
135
    }
136
137
    /** @var ResponseFactoryInterface $response_factory */
138
    $response_factory = app(ResponseFactoryInterface::class);
139
140
    /** @var StreamFactoryInterface $stream_factory */
141
    $stream_factory = app(StreamFactoryInterface::class);
142
143
    $stream = $stream_factory->createStream($content);
144
145
    $response = $response_factory
146
        ->createResponse($code)
147
        ->withBody($stream);
148
149
    foreach ($headers as $key => $value) {
150
        $response = $response->withHeader($key, $value);
151
    }
152
153
    return $response;
154
}
155
156
/**
157
 * Generate a URL for a named route.
158
 *
159
 * @param string  $route_name
160
 * @param mixed[] $parameters
161
 *
162
 * @return string
163
 */
164
function route(string $route_name, array $parameters = []): string
165
{
166
    $request          = app(ServerRequestInterface::class);
167
    $router_container = app(RouterContainer::class);
168
    $route            = $router_container->getMap()->getRoute($route_name);
169
170
    // Generate the URL.
171
    $url = $router_container->getGenerator()->generate($route_name, $parameters);
172
173
    // Aura ignores parameters that are not tokens.  We need to add them as query parameters.
174
    $parameters = array_filter($parameters, static function (string $key) use ($route): bool {
175
        return strpos($route->path, '{' . $key . '}') === false && strpos($route->path, '{/' . $key . '}') === false;
176
    }, ARRAY_FILTER_USE_KEY);
177
178
    // Turn the pretty URL into an ugly one.
179
    if ($request->getAttribute('rewrite_urls') !== '1') {
180
        $base_url   = $request->getAttribute('base_url');
181
        $path       = parse_url($url, PHP_URL_PATH);
182
        $parameters = ['route' => $path] + $parameters;
183
        $url        = $base_url . '/index.php';
184
    }
185
186
    return Html::url($url, $parameters);
187
}
188
189
/**
190
 * Cerate and render a view in a single operation.
191
 *
192
 * @param string  $name
193
 * @param mixed[] $data
194
 *
195
 * @return string
196
 */
197
function view(string $name, array $data = [])
198
{
199
    return WebtreesView::make($name, $data);
200
}
201