Completed
Push — master ( 3089f7...b04f5d )
by ignace nyamagana
10s
created

HierarchicalPath::getExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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