Completed
Pull Request — master (#40)
by ignace nyamagana
11:26
created

AbstractHierarchicalComponent   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 18
Bugs 3 Features 0
Metric Value
wmc 16
c 18
b 3
f 0
lcom 1
cbo 2
dl 0
loc 192
ccs 38
cts 38
cp 1
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
__construct() 0 1 ?
A isAbsolute() 0 4 1
A newCollectionInstance() 0 8 2
A getUriComponent() 0 4 1
A prepend() 0 7 1
append() 0 1 ?
A validateComponent() 0 8 2
A createFromArray() 0 10 2
A formatComponentString() 0 9 2
A replace() 0 16 4
A __set_state() 0 4 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.1.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 whether or not the component is absolute or not
59
     *
60 16
     * @return bool
61
     */
62 16
    public function isAbsolute()
63
    {
64
        return $this->isAbsolute == self::IS_ABSOLUTE;
65
    }
66
67
    /**
68
     * Return a new instance when needed
69
     *
70
     * @param array $data
71
     *
72 190
     * @return static
73
     */
74 190
    protected function newCollectionInstance(array $data)
75 4
    {
76
        if ($data == $this->data) {
77
            return $this;
78 186
        }
79
80
        return $this->createFromArray($data, $this->isAbsolute);
81
    }
82
83
    /**
84 414
     * Returns the instance string representation
85
     * with its optional URI delimiters
86 414
     *
87
     * @return string
88
     */
89
    public function getUriComponent()
90
    {
91
        return $this->__toString();
92 40
    }
93
94 40
    /**
95 40
     * Returns an instance with the specified component prepended
96 40
     *
97 40
     * This method MUST retain the state of the current instance, and return
98
     * an instance that contains the modified component with the prepended data
99
     *
100
     * @param HierarchicalComponent|string $component the component to prepend
101
     *
102
     * @return static
103
     */
104
    public function prepend($component)
105
    {
106
        return $this->createFromArray(
107
            $this->validateComponent($component),
108
            $this->isAbsolute)
109
        ->append($this);
110
    }
111
112 124
    /**
113
     * Returns an instance with the specified component appended
114 124
     *
115 50
     * This method MUST retain the state of the current instance, and return
116
     * an instance that contains the modified component with the appended data
117
     *
118 90
     * @param HierarchicalComponent|string $component the component to append
119
     *
120
     * @return static
121
     */
122
    abstract public function append($component);
123
124
    /**
125
     * Validate a component as a HierarchicalComponentInterface object
126
     *
127
     * @param HierarchicalComponent|string $component
128
     *
129
     * @return static
130
     */
131 314
    protected function validateComponent($component)
132
    {
133 314
        if (!$component instanceof HierarchicalComponent) {
134
            return $this->modify($component);
135 314
        }
136 4
137
        return $component;
138
    }
139 310
140
    /**
141
     * return a new instance from an array or a traversable object
142
     *
143
     * @param \Traversable|string[] $data The segments list
144
     * @param int                   $type one of the constant IS_ABSOLUTE or IS_RELATIVE
145
     *
146
     * @throws InvalidArgumentException If $type is not a recognized constant
147
     *
148
     * @return static
149
     */
150
    public static function createFromArray($data, $type = self::IS_RELATIVE)
151
    {
152 218
        static $type_list = [self::IS_ABSOLUTE => 1, self::IS_RELATIVE => 1];
153
154 218
        if (!isset($type_list[$type])) {
155 210
            throw new InvalidArgumentException('Please verify the submitted constant');
156 162
        }
157
158
        return new static(static::formatComponentString($data, $type));
159 48
    }
160
161
    /**
162
     * Return a formatted component string according to its type
163
     *
164
     * @param \Traversable|string[] $data The segments list
165 46
     * @param int                   $type
166
     *
167 46
     * @throws InvalidArgumentException If $data is invalid
168 10
     *
169
     * @return string
170
     */
171 36
    protected static function formatComponentString($data, $type)
172 36
    {
173 36
        $path = implode(static::$separator, static::validateIterator($data));
174 8
        if (self::IS_ABSOLUTE == $type) {
175 8
            return static::$separator.$path;
176
        }
177 36
178 36
        return $path;
179 36
    }
180
181
    /**
182
     * Returns an instance with the modified segment
183
     *
184
     * This method MUST retain the state of the current instance, and return
185
     * an instance that contains the modified component with the replaced data
186
     *
187
     * @param int                          $offset    the label offset to remove and replace by
188
     *                                                the given component
189
     * @param HierarchicalComponent|string $component the component added
190
     *
191
     * @return static
192
     */
193
    public function replace($offset, $component)
194
    {
195
        if (!empty($this->data) && !$this->hasKey($offset)) {
196
            return $this;
197
        }
198
199
        $source = $this->toArray();
200
        $dest   = $this->validateComponent($component)->toArray();
201
        if ('' == $dest[count($dest) - 1]) {
202
            array_pop($dest);
203
        }
204
205
        return $this->newCollectionInstance(
206
            array_merge(array_slice($source, 0, $offset), $dest, array_slice($source, $offset + 1))
207
        );
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213
    public static function __set_state(array $properties)
214
    {
215
        return static::createFromArray($properties['data'], $properties['isAbsolute']);
216
    }
217
}
218