Test Failed
Push — develop ( bcf63f...70e2cc )
by Andrew
09:44
created

UrlHelper::decomposeUrl()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 13
nc 5
nop 1
dl 0
loc 18
ccs 0
cts 4
cp 0
crap 20
rs 9.8333
c 1
b 0
f 0
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\helpers;
13
14
use nystudio107\seomatic\Seomatic;
15
16
use Craft;
17
use craft\errors\SiteNotFoundException;
18
use craft\helpers\UrlHelper as CraftUrlHelper;
19
20
use yii\base\Exception;
21
22
/**
23
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
24
 * @package   Seomatic
25
 * @since     3.0.0
26
 */
27
class UrlHelper extends CraftUrlHelper
28
{
29
    // Public Static Properties
30
    // =========================================================================
31
32
    // Public Static Methods
33
    // =========================================================================
34
35
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $path should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $params should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $scheme should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $siteId should have a doc-comment as per coding-style.
Loading history...
36
     * @inheritDoc
37
     */
38
    public static function siteUrl(string $path = '', $params = null, string $scheme = null, int $siteId = null): string
39
    {
40
        $siteUrl = Seomatic::$settings->siteUrlOverride;
41
        if (!empty($siteUrl)) {
42
            $siteUrl = MetaValue::parseString($siteUrl);
43
            // Extract out just the path part
44
            $parts = self::decomposeUrl($path);
45
            $path = $parts['path'].$parts['suffix'];
46
            $url = rtrim($siteUrl, '/').'/'.ltrim($path, '/');
47
            // Handle trailing slashes properly for generated URLs
48
            $generalConfig = Craft::$app->getConfig()->getGeneral();
49
            if ($generalConfig->addTrailingSlashesToUrls && !preg_match('/\.[^\/]+$/', $url)) {
50
                $url = rtrim($url, '/') . '/';
51
            }
52
            if (!$generalConfig->addTrailingSlashesToUrls) {
53
                $url = rtrim($url, '/');
54
            }
55
56
            return $url;
57
        }
58
59
        return parent::siteUrl($path, $params, $scheme, $siteId);
60
    }
61
62
    /**
63
     * Return the page trigger and the value of the page trigger (null if it doesn't exist)
64
     *
65
     * @return array
66
     */
67
    public static function pageTriggerValue(): array
68
    {
69
        $pageTrigger = Craft::$app->getConfig()->getGeneral()->pageTrigger;
70
        if (!\is_string($pageTrigger) || $pageTrigger === '') {
71
            $pageTrigger = 'p';
72
        }
73
        // Is this query string-based pagination?
74
        if ($pageTrigger[0] === '?') {
75
            $pageTrigger = trim($pageTrigger, '?=');
76
        }
77
        // Avoid conflict with the path param
78
        $pathParam = Craft::$app->getConfig()->getGeneral()->pathParam;
79
        if ($pageTrigger === $pathParam) {
80
            $pageTrigger = $pathParam === 'p' ? 'pg' : 'p';
81
        }
82
        $pageTriggerValue = Craft::$app->getRequest()->getParam($pageTrigger);
83
84
        return [$pageTrigger, $pageTriggerValue];
85
    }
86
87
    /**
88
     * Return an absolute URL with protocol that curl will be happy with
89
     *
90
     * @param string $url
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
91
     *
92
     * @return string
93
     */
94
    public static function absoluteUrlWithProtocol($url): string
95
    {
96
        // Make this a full URL
97
        if (!self::isAbsoluteUrl($url)) {
98
            $protocol = 'http';
99
            if (isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (IssetNode && strcasecmp...PROTO'], 'https') === 0, Probably Intended Meaning: IssetNode && (strcasecmp...ROTO'], 'https') === 0)
Loading history...
100
                || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0
101
            ) {
102
                $protocol = 'https';
103
            }
104
            if (self::isProtocolRelativeUrl($url)) {
105
                try {
106
                    $url = self::urlWithScheme($url, $protocol);
107
                } catch (SiteNotFoundException $e) {
108
                    Craft::error($e->getMessage(), __METHOD__);
109
                }
110
            } else {
111
                try {
112
                    $url = self::siteUrl($url, null, $protocol);
113
                    if (self::isProtocolRelativeUrl($url)) {
114
                        $url = self::urlWithScheme($url, $protocol);
115
                    }
116
                } catch (Exception $e) {
117
                    Craft::error($e->getMessage(), __METHOD__);
118
                }
119
            }
120
        }
121
        // Ensure that any spaces in the URL are encoded
122
        $url = str_replace(' ', '%20', $url);
123
124
        // Handle trailing slashes properly for generated URLs
125
        $generalConfig = Craft::$app->getConfig()->getGeneral();
126
        if ($generalConfig->addTrailingSlashesToUrls && !preg_match('/\.[^\/]+$/', $url)) {
127
            $url = rtrim($url, '/') . '/';
128
        }
129
        if (!$generalConfig->addTrailingSlashesToUrls) {
130
            $url = rtrim($url, '/');
131
        }
132
133
        return $url;
134
    }
135
136
    /**
137
     * Return whether this URL has a sub-directory as part of it
138
     *
139
     * @param string $url
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
140
     * @return bool
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
141
     */
142
    public static function urlHasSubDir(string $url): bool
143
    {
144
        return !empty(parse_url(trim($url, '/'), PHP_URL_PATH));
145
    }
146
147
    // Protected Methods
148
    // =========================================================================
149
150
    /**
151
     * Decompose a url into a prefix, path, and suffix
152
     *
153
     * @param $pathOrUrl
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
154
     *
155
     * @return array
156
     */
157
    protected static function decomposeUrl($pathOrUrl): array
158
    {
159
        $result = array();
160
161
        if (filter_var($pathOrUrl, FILTER_VALIDATE_URL)) {
162
            $url_parts = parse_url($pathOrUrl);
163
            $result['prefix'] = $url_parts['scheme'] . '://' . $url_parts['host'];
164
            $result['path'] = $url_parts['path'];
165
            $result['suffix'] = '';
166
            $result['suffix'] .= empty($url_parts['query']) ? '' : '?' . $url_parts['query'];
167
            $result['suffix'] .= empty($url_parts['fragment']) ? '' : '#' . $url_parts['fragment'];
168
        } else {
169
            $result['prefix'] = '';
170
            $result['path'] = $pathOrUrl;
171
            $result['suffix'] = '';
172
        }
173
174
        return $result;
175
    }
176
}
177