Completed
Pull Request — master (#58)
by ignace nyamagana
03:41
created

AbstractHierarchicalComponent::modify()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2
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\Types\ImmutableCollectionTrait;
17
use League\Uri\Types\ImmutableComponentTrait;
18
19
/**
20
 * An abstract class to ease collection like Component object manipulation
21
 *
22
 * @package League.uri
23
 * @author  Ignace Nyamagana Butera <[email protected]>
24
 * @since   4.0.0
25
 */
26
abstract class AbstractHierarchicalComponent implements HierarchicalComponent
27
{
28
    use ImmutableCollectionTrait;
29
30
    use ImmutableComponentTrait;
31
32
    const IS_ABSOLUTE = 1;
33
34
    const IS_RELATIVE = 0;
35
36
    /**
37
     * Hierarchical component separator
38
     *
39
     * @var string
40
     */
41
    protected static $separator;
42
43
    /**
44
     * Is the object considered absolute
45
     *
46
     * @var int
47
     */
48
    protected $isAbsolute = self::IS_RELATIVE;
49
50
    /**
51
     * new instance
52
     *
53
     * @param null|string $str the component value
54
     */
55
    abstract public function __construct($str);
56
57
    /**
58
     * Returns an instance with the specified string
59
     *
60
     * This method MUST retain the state of the current instance, and return
61
     * an instance that contains the modified data
62
     *
63
     * @param string $value
64
     *
65
     * @return static
66
     */
67 414
    public function modify($value)
68
    {
69 414
        if ($value == $this->__toString()) {
70 114
            return $this;
71
        }
72
73 360
        return new static($value);
74
    }
75
76
    /**
77
     * Returns whether or not the component is absolute or not
78
     *
79
     * @return bool
80
     */
81 27
    public function isAbsolute()
82
    {
83 27
        return $this->isAbsolute == self::IS_ABSOLUTE;
84
    }
85
86
    /**
87
     * Return a new instance when needed
88
     *
89
     * @param array $data
90
     *
91
     * @return static
92
     */
93 285
    protected function newCollectionInstance(array $data)
94
    {
95 285
        if ($data == $this->data) {
96 6
            return $this;
97
        }
98
99 279
        return $this->createFromArray($data, $this->isAbsolute);
100
    }
101
102
    /**
103
     * Returns the instance string representation
104
     * with its optional URI delimiters
105
     *
106
     * @return string
107
     */
108 652
    public function getUriComponent()
109
    {
110 652
        return $this->__toString();
111
    }
112
113
    /**
114
     * Returns an instance with the specified component prepended
115
     *
116
     * This method MUST retain the state of the current instance, and return
117
     * an instance that contains the modified component with the prepended data
118
     *
119
     * @param HierarchicalComponent|string $component the component to prepend
120
     *
121
     * @return static
122
     */
123 60
    public function prepend($component)
124
    {
125 60
        return $this->createFromArray(
126 60
                $this->validateComponent($component),
127 60
                $this->isAbsolute
128 60
            )->append($this);
129
    }
130
131
    /**
132
     * Returns an instance with the specified component appended
133
     *
134
     * This method MUST retain the state of the current instance, and return
135
     * an instance that contains the modified component with the appended data
136
     *
137
     * @param HierarchicalComponent|string $component the component to append
138
     *
139
     * @return static
140
     */
141
    abstract public function append($component);
142
143
    /**
144
     * Validate a component as a HierarchicalComponentInterface object
145
     *
146
     * @param HierarchicalComponent|string $component
147
     *
148
     * @return static
149
     */
150 186
    protected function validateComponent($component)
151
    {
152 186
        if (!$component instanceof HierarchicalComponent) {
153 75
            return $this->modify($component);
154
        }
155
156 135
        return $component;
157
    }
158
159
    /**
160
     * return a new instance from an array or a traversable object
161
     *
162
     * @param \Traversable|string[] $data The segments list
163
     * @param int                   $type one of the constant IS_ABSOLUTE or IS_RELATIVE
164
     *
165
     * @throws InvalidArgumentException If $type is not a recognized constant
166
     *
167
     * @return static
168
     */
169 486
    public static function createFromArray($data, $type = self::IS_RELATIVE)
170
    {
171 486
        static $type_list = [self::IS_ABSOLUTE => 1, self::IS_RELATIVE => 1];
172
173 486
        if (!isset($type_list[$type])) {
174 6
            throw new InvalidArgumentException('Please verify the submitted constant');
175
        }
176
177 480
        return new static(static::formatComponentString($data, $type));
178
    }
179
180
    /**
181
     * Return a formatted component string according to its type
182
     *
183
     * @param \Traversable|string[] $data The segments list
184
     * @param int                   $type
185
     *
186
     * @throws InvalidArgumentException If $data is invalid
187
     *
188
     * @return string
189
     */
190 336
    protected static function formatComponentString($data, $type)
191
    {
192 336
        $path = implode(static::$separator, static::validateIterator($data));
193 324
        if (self::IS_ABSOLUTE == $type) {
194 252
            return static::$separator.$path;
195
        }
196
197 72
        return $path;
198
    }
199
200
    /**
201
     * Returns an instance with the modified segment
202
     *
203
     * This method MUST retain the state of the current instance, and return
204
     * an instance that contains the modified component with the replaced data
205
     *
206
     * @param int                          $offset    the label offset to remove and replace by
207
     *                                                the given component
208
     * @param HierarchicalComponent|string $component the component added
209
     *
210
     * @return static
211
     */
212 69
    public function replace($offset, $component)
213
    {
214 69
        if (!empty($this->data) && !$this->hasKey($offset)) {
215 15
            return $this;
216
        }
217
218 54
        $source = $this->toArray();
219 54
        $dest   = $this->validateComponent($component)->toArray();
220 54
        if ('' == $dest[count($dest) - 1]) {
221 12
            array_pop($dest);
222 12
        }
223
224 54
        return $this->newCollectionInstance(
225 54
            array_merge(array_slice($source, 0, $offset), $dest, array_slice($source, $offset + 1))
226 54
        );
227
    }
228
}
229