Passed
Push — master ( 92aafc...aa06e4 )
by Caen
04:12 queued 15s
created

Hyperlinks::isRemote()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Foundation\Kernel;
6
7
use Hyde\Facades\Config;
8
use Hyde\Support\Models\Route;
9
use Hyde\Foundation\HydeKernel;
10
use Hyde\Framework\Exceptions\BaseUrlNotSetException;
11
use Hyde\Framework\Exceptions\FileNotFoundException;
12
use Illuminate\Support\Str;
13
14
use function str_ends_with;
15
use function str_starts_with;
16
use function substr_count;
17
use function file_exists;
18
use function str_replace;
19
use function str_repeat;
20
use function substr;
21
use function blank;
22
use function rtrim;
23
use function trim;
24
25
/**
26
 * Contains helpers and logic for resolving web paths for compiled files.
27
 *
28
 * It's bound to the HydeKernel instance, and is an integral part of the framework.
29
 */
30
class Hyperlinks
31
{
32
    protected HydeKernel $kernel;
33
34
    public function __construct(HydeKernel $kernel)
35
    {
36
        $this->kernel = $kernel;
37
    }
38
39
    /**
40
     * Format a web link to an HTML file, allowing for pretty URLs, if enabled.
41
     *
42
     * @see \Hyde\Framework\Testing\Unit\Foundation\HyperlinkFormatHtmlPathTest
43
     */
44
    public function formatLink(string $destination): string
45
    {
46
        if (Config::getBool('hyde.pretty_urls', false) === true) {
47
            if (str_ends_with($destination, '.html')) {
48
                if ($destination === 'index.html') {
49
                    return '/';
50
                }
51
52
                if (str_ends_with($destination, 'index.html')) {
53
                    return substr($destination, 0, -10);
54
                }
55
56
                return substr($destination, 0, -5);
57
            }
58
        }
59
60
        return $destination;
61
    }
62
63
    /**
64
     * Inject the proper number of `../` before the links in Blade templates.
65
     *
66
     * @param  string  $destination  relative to output directory on compiled site
67
     *
68
     * @see \Hyde\Framework\Testing\Unit\Foundation\HyperlinkFileHelperRelativeLinkTest
69
     */
70
    public function relativeLink(string $destination): string
71
    {
72
        if (str_starts_with($destination, '../')) {
73
            return $destination;
74
        }
75
76
        $nestCount = substr_count($this->kernel->currentRouteKey() ?? '', '/');
77
        $route = '';
78
        if ($nestCount > 0) {
79
            $route .= str_repeat('../', $nestCount);
80
        }
81
        $route .= $this->formatLink($destination);
82
83
        if (Config::getBool('hyde.pretty_urls', false) === true && $route === '/') {
84
            return './';
85
        }
86
87
        return str_replace('//', '/', $route);
88
    }
89
90
    /**
91
     * Gets a relative web link to the given file stored in the _site/media folder.
92
     *
93
     * An exception will be thrown if the file does not exist in the _media directory,
94
     * and the second argument is set to true.
95
     */
96
    public function mediaLink(string $destination, bool $validate = false): string
97
    {
98
        if ($validate && ! file_exists($sourcePath = "{$this->kernel->getMediaDirectory()}/$destination")) {
99
            throw new FileNotFoundException($sourcePath);
100
        }
101
102
        return $this->relativeLink("{$this->kernel->getMediaOutputDirectory()}/$destination");
103
    }
104
105
    /**
106
     * Gets a relative web link to the given image stored in the _site/media folder.
107
     * If the image is remote (starts with http) it will be returned as is.
108
     *
109
     * If true is passed as the second argument, and a base URL is set,
110
     * the image will be returned with a qualified absolute URL.
111
     */
112
    public function asset(string $name, bool $preferQualifiedUrl = false): string
113
    {
114
        if (static::isRemote($name)) {
115
            return $name;
116
        }
117
118
        $name = Str::start($name, "{$this->kernel->getMediaOutputDirectory()}/");
119
120
        if ($preferQualifiedUrl && $this->hasSiteUrl()) {
121
            return $this->url($name);
122
        }
123
124
        return $this->relativeLink($name);
125
    }
126
127
    /**
128
     * Check if a site base URL has been set in config (or .env).
129
     *
130
     * The default value is `http://localhost`, which is not considered a valid site URL.
131
     */
132
    public function hasSiteUrl(): bool
133
    {
134
        $value = Config::getNullableString('hyde.url');
135
136
        return ! blank($value) && $value !== 'http://localhost';
137
    }
138
139
    /**
140
     * Return a qualified URL to the supplied path if a base URL is set.
141
     *
142
     * @param  string  $path  An optional relative path suffix. Omit to return the base URL.
143
     *
144
     * @throws BaseUrlNotSetException If no site URL is set and no path is provided.
145
     */
146
    public function url(string $path = ''): string
147
    {
148
        $path = $this->formatLink(trim($path, '/'));
149
150
        if (static::isRemote($path)) {
151
            return $path;
152
        }
153
154
        if ($this->hasSiteUrl()) {
155
            return rtrim(rtrim(Config::getString('hyde.url'), '/')."/$path", '/');
156
        }
157
158
        // Since v1.7.0, we return the relative path even if the base URL is not set,
159
        // as this is more likely to be the desired behavior the user's expecting.
160
        if (! blank($path)) {
161
            return $path;
162
        }
163
164
        // User is trying to get the base URL, but it's not set
165
        // This exception is deprecated and will be removed in v2.0.0, and we will return null instead.
166
        throw new BaseUrlNotSetException();
0 ignored issues
show
Deprecated Code introduced by
The class Hyde\Framework\Exceptions\BaseUrlNotSetException has been deprecated: This exception will be removed in v2.0.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

166
        throw /** @scrutinizer ignore-deprecated */ new BaseUrlNotSetException();
Loading history...
167
    }
168
169
    /**
170
     * Get a route instance by its key from the kernel's route collection.
171
     */
172
    public function route(string $key): ?Route
173
    {
174
        return $this->kernel->routes()->get($key);
175
    }
176
177
    /**
178
     * Determine if the given URL is a remote link.
179
     */
180
    public static function isRemote(string $url): bool
181
    {
182
        return str_starts_with($url, 'http') || str_starts_with($url, '//');
183
    }
184
}
185