Completed
Push — master ( 4b40ba...4de594 )
by ignace nyamagana
03:31
created

HierarchicalPath::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * League.Uri (http://uri.thephpleague.com)
4
 *
5
 * @package   League.uri
6
 * @author    Ignace Nyamagana Butera <[email protected]>
7
 * @copyright 2013-2015 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\Components;
13
14
use InvalidArgumentException;
15
use League\Uri\Interfaces\HierarchicalComponent;
16
use League\Uri\Interfaces\HierarchicalPath as HierarchicalPathInterface;
17
18
/**
19
 * Value object representing a URI path component.
20
 *
21
 * @package League.uri
22
 * @author  Ignace Nyamagana Butera <[email protected]>
23
 * @since   1.0.0
24
 */
25
class HierarchicalPath extends AbstractHierarchicalComponent implements HierarchicalPathInterface
26
{
27
    use PathTrait;
28
29
    /**
30
     * @inheritdoc
31
     */
32
    protected static $separator = '/';
33
34
    /**
35
     * New Instance
36
     *
37
     * @param string $path
38
     */
39 1015
    public function __construct($path = '')
40
    {
41 1015
        $path = $this->validateString($path);
42 1006
        $this->isAbsolute = self::IS_RELATIVE;
43 1006
        if (static::$separator == mb_substr($path, 0, 1, 'UTF-8')) {
44 827
            $this->isAbsolute = self::IS_ABSOLUTE;
45 827
            $path = mb_substr($path, 1, mb_strlen($path), 'UTF-8');
46 551
        }
47
48 1006
        $append_delimiter = false;
49 1006
        if (static::$separator === mb_substr($path, -1, 1, 'UTF-8')) {
50 138
            $path = mb_substr($path, 0, -1, 'UTF-8');
51 138
            $append_delimiter = true;
52 92
        }
53
54 1006
        $this->data = $this->validate($path);
55 1006
        if ($append_delimiter) {
56 138
            $this->data[] = '';
57 92
        }
58 1006
    }
59
60
    /**
61
     * validate the submitted data
62
     *
63
     * @param string $data
64
     *
65
     * @return array
66
     */
67
    protected function validate($data)
68
    {
69 1006
        $filterSegment = function ($segment) {
70 1006
            return isset($segment);
71 1006
        };
72
73 1006
        $data = $this->decodePath($data);
74
75 1006
        return array_filter(explode(static::$separator, $data), $filterSegment);
76
    }
77
78
    /**
79
     * Retrieves a single path segment.
80
     *
81
     * Retrieves a single path segment. If the segment offset has not been set,
82
     * returns the default value provided.
83
     *
84
     * @param string $offset  the segment offset
85
     * @param mixed  $default Default value to return if the offset does not exist.
86
     *
87
     * @return mixed
88
     */
89 9
    public function getSegment($offset, $default = null)
90
    {
91 9
        if (isset($this->data[$offset])) {
92 6
            return $this->data[$offset];
93
        }
94
95 3
        return $default;
96
    }
97
98
    /**
99
     * @inheritdoc
100
     */
101 9
    public static function __set_state(array $properties)
102
    {
103 9
        return static::createFromArray($properties['data'], $properties['isAbsolute']);
104
    }
105
106
    /**
107
     * @inheritdoc
108
     */
109 973
    public function getContent()
110
    {
111 973
        $front_delimiter = '';
112 973
        if ($this->isAbsolute == self::IS_ABSOLUTE) {
113 785
            $front_delimiter = static::$separator;
114 523
        }
115
116 973
        return $this->encodePath(
117 973
            $front_delimiter.implode(static::$separator, $this->data)
118 648
        );
119
    }
120
121
    /**
122
     * @inheritdoc
123
     */
124 973
    public function __toString()
125
    {
126 973
        return (string) $this->getContent();
127
    }
128
129
    /**
130
     * Returns an instance with the specified component appended
131
     *
132
     * This method MUST retain the state of the current instance, and return
133
     * an instance that contains the modified component with the appended data
134
     *
135
     * @param HierarchicalComponent|string $component the component to append
136
     *
137
     * @return static
138
     */
139 72
    public function append($component)
140
    {
141 72
        $source = $this->toArray();
142 72
        if (!empty($source) && '' === end($source)) {
143 30
            array_pop($source);
144 20
        }
145
146 72
        return $this->newCollectionInstance(array_merge(
147 48
            $source,
148 72
            $this->validateComponent($component)->toArray()
149 48
        ));
150
    }
151
152
    /**
153
     * Returns the path basename
154
     *
155
     * @return string
156
     */
157 63
    public function getBasename()
158
    {
159 63
        $data = $this->data;
160
161 63
        return (string) array_pop($data);
162
    }
163
164
    /**
165
     * Returns parent directory's path
166
     *
167
     * @return string
168
     */
169 24
    public function getDirname()
170
    {
171 24
        return str_replace(
172 24
            ['\\', "\0"],
173 24
            [static::$separator, '\\'],
174 24
            dirname(str_replace('\\', "\0", $this->__toString()))
175 16
        );
176
    }
177
178
    /**
179
     * Returns the basename extension
180
     *
181
     * @return string
182
     */
183 57
    public function getExtension()
184
    {
185 57
        list($basename, ) = explode(';', $this->getBasename(), 2);
186
187 57
        return pathinfo($basename, PATHINFO_EXTENSION);
188
    }
189
190
    /**
191
     * Returns an instance with the specified basename extension
192
     *
193
     * This method MUST retain the state of the current instance, and return
194
     * an instance that contains the extension basename modified.
195
     *
196
     * @param string $extension the new extension
197
     *                          can preceeded with or without the dot (.) character
198
     *
199
     * @throws InvalidArgumentException If the extension is invalid
200
     *
201
     * @return static
202
     */
203 63
    public function withExtension($extension)
204
    {
205 63
        $extension = $this->formatExtension($extension);
206 57
        $segments = $this->toArray();
207 57
        $basename = array_pop($segments);
208 57
        $parts = explode(';', $basename, 2);
209 57
        $basenamePart = array_shift($parts);
210 57
        if ('' === $basenamePart || is_null($basenamePart)) {
211 6
            return $this;
212
        }
213
214 51
        $newBasename = $this->buildBasename($basenamePart, $extension, array_shift($parts));
215 51
        if ($basename === $newBasename) {
216 3
            return $this;
217
        }
218 48
        $segments[] = $newBasename;
219
220 48
        return $this->newCollectionInstance($segments);
221
    }
222
223
    /**
224
     * create a new basename with a new extension
225
     *
226
     * @param string $basenamePart  the basename file part
227
     * @param string $extension     the new extension to add
228
     * @param string $parameterPart the basename parameter part
229
     *
230
     * @return string
231
     */
232 51
    protected function buildBasename($basenamePart, $extension, $parameterPart)
233
    {
234 51
        $length = mb_strrpos($basenamePart, '.'.pathinfo($basenamePart, PATHINFO_EXTENSION), 'UTF-8');
235 51
        if (false !== $length) {
236 45
            $basenamePart = mb_substr($basenamePart, 0, $length, 'UTF-8');
237 30
        }
238
239 51
        $parameterPart = trim($parameterPart);
240 51
        if ('' !== $parameterPart) {
241 24
            $parameterPart = ";$parameterPart";
242 16
        }
243
244 51
        $extension = trim($extension);
245 51
        if ('' !== $extension) {
246 36
            $extension = ".$extension";
247 24
        }
248
249 51
        return $basenamePart.$extension.$parameterPart;
250
    }
251
252
    /**
253
     * validate and format the given extension
254
     *
255
     * @param string $extension the new extension to use
256
     *
257
     * @throws InvalidArgumentException If the extension is not valid
258
     *
259
     * @return string
260
     */
261 63
    protected function formatExtension($extension)
262
    {
263 63
        if (0 === strpos($extension, '.')) {
264 3
            throw new InvalidArgumentException('an extension sequence can not contain a leading `.` character');
265
        }
266
267 60
        if (strpos($extension, static::$separator)) {
268 3
            throw new InvalidArgumentException('an extension sequence can not contain a path delimiter');
269
        }
270
271 57
        return implode(static::$separator, $this->validate($extension));
272
    }
273
}
274