Completed
Push — master ( 5e61d1...b0bce0 )
by ignace nyamagana
05:19
created

src/Modifiers/Relativize.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * League.Uri (http://uri.thephpleague.com)
4
 *
5
 * @package   League.uri
6
 * @author    Ignace Nyamagana Butera <[email protected]>
7
 * @copyright 2016 Ignace Nyamagana Butera
8
 * @license   https://github.com/thephpleague/uri/blob/master/LICENSE (MIT License)
9
 * @version   4.2.0
10
 * @link      https://github.com/thephpleague/uri/
11
 */
12
namespace League\Uri\Modifiers;
13
14
use League\Uri\Interfaces\Uri;
15
use Psr\Http\Message\UriInterface;
16
17
/**
18
 * Resolve an URI according to a base URI using
19
 * RFC3986 rules
20
 *
21
 * @package League.uri
22
 * @author  Ignace Nyamagana Butera <[email protected]>
23
 * @since   4.2.0
24
 */
25
class Relativize extends AbstractUriModifier
26
{
27
    /**
28
     * New instance
29
     *
30
     * @param Uri|UriInterface $uri
31
     */
32 102
    public function __construct($uri)
33
    {
34 102
        $this->assertUriObject($uri);
35 102
        $this->uri = $uri;
0 ignored issues
show
The property uri does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
36 102
    }
37
38
    /**
39
     * Return a Uri object modified according to the modifier
40
     *
41
     * @param Uri|UriInterface $payload
42
     *
43
     * @return Uri|UriInterface
44
     */
45 102
    public function __invoke($payload)
46
    {
47 102
        $this->assertUriObject($payload);
48 102
        if ($this->uri->getScheme() !== $payload->getScheme()
49 102
            || $this->uri->getAuthority() !== $payload->getAuthority()
50 68
        ) {
51 33
            return $payload;
52
        }
53
54 69
        $path = $this->relativizePath($payload->getPath());
55
56
        return $payload
57 69
            ->withScheme('')
58 69
            ->withPort(null)
59 69
            ->withUserInfo('')
60 69
            ->withHost('')
61 69
            ->withPath($this->formatPath($path));
62
    }
63
64
    /**
65
     * Relative the URI for a authority-less payload URI
66
     *
67
     * @param string $path
68
     *
69
     * @return string
70
     */
71 69
    protected function relativizePath($path)
72
    {
73 69
        $segments = $this->getSegments($path);
74 69
        $basename = array_pop($segments);
75 69
        $basePath = $this->uri->getPath();
76 69
        if ($basePath === $path) {
77 18
            return $basename;
78
        }
79
80 51
        $baseSegments = $this->getSegments($basePath);
81 51
        array_pop($baseSegments);
82 51
        foreach ($baseSegments as $offset => $segment) {
83 48
            if (!isset($segments[$offset]) || $segment !== $segments[$offset]) {
84 24
                break;
85
            }
86 33
            unset($baseSegments[$offset], $segments[$offset]);
87 34
        }
88 51
        $segments[] = $basename;
89
90 51
        return str_repeat('../', count($baseSegments)).implode('/', $segments);
91
    }
92
93
    /**
94
     * returns the path segments
95
     *
96
     * @param string $path
97
     *
98
     * @return array
99
     */
100 69
    protected function getSegments($path)
101
    {
102 69
        if ('' !== $path && '/' === $path[0]) {
103 66
            $path = substr($path, 1);
104 44
        }
105
106 69
        return explode('/', $path);
107
    }
108
109
    /**
110
     * Post formatting the path to keep a valid URI
111
     *
112
     * @param string $path
113
     *
114
     * @return string
115
     */
116 69
    protected function formatPath($path)
117
    {
118 69
        if ('' === $path) {
119 9
            $basePath = $this->uri->getPath();
120
121 9
            return in_array($basePath, ['', '/']) ? $basePath : './';
122
        }
123
124 60
        if (false === ($colonPos = strpos($path, ':'))) {
125 54
            return $path;
126
        }
127
128 6
        $slashPos = strpos($path, '/');
129 6
        if (false === $slashPos || $colonPos < $slashPos) {
130 3
            return "./$path";
131
        }
132
133 3
        return $path;
134
    }
135
}
136