Completed
Push — master ( 43515f...3205a5 )
by Derek
02:22
created

AbstractUriPart   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 82%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 1
dl 0
loc 191
ccs 41
cts 50
cp 0.82
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __toString() 0 4 1
A __construct() 0 10 3
A getValidPattern() 0 6 1
A isValid() 0 8 1
A toUriString() 0 4 1
A encode() 0 12 2
A compileValidPattern() 0 21 2
A compileUnencodedCharacters() 0 12 3
1
<?php
2
namespace Subreality\Dilmun\Anshar\Http\UriParts;
3
4
use Subreality\Dilmun\Anshar\Utils\StringHelper;
5
6
/**
7
 * Class AbstractUriPart
8
 * @package Subreality\Dilmun\Anshar\Http\UriParts
9
 */
10
abstract class AbstractUriPart implements UriPartInterface
11
{
12
    protected static $unreserved_pattern  = '\w\-\.~';
13
    protected static $pct_encoded_pattern = '%[A-Fa-f0-9]{2}';
14
    protected static $sub_delims_pattern  = '\!\$&\'\(\)\*\+,;\=';
15
    protected static $pchar_pattern       = '\:@';
16
17
    protected static $unreserved_characters = array("_", "-", ".", "~");
18
    protected static $pchar_characters      = array(":", "@");
19
20
    protected static $sub_delims_characters = array(
21
        "!",
22
        "$",
23
        "&",
24
        "'",
25
        "(",
26
        ")",
27
        "*",
28
        "+",
29
        ",",
30
        ";",
31
        "=",
32
    );
33
34
    protected $data = "";
35
36
    protected static $part_pattern;
37
38
    /**
39
     * Provides a common composition of allowed characters for validation and encoding.
40
     *
41
     * @see AbstractUriPart::compileUnencodedCharacters()
42
     * @see AbstractUriPart::compileValidPattern()
43
     *
44
     * @var array
45
     */
46
    protected static $compositions = array(
47
        "unreserved_characters",
48
        "pchar_characters",
49
        "sub_delims_characters",
50
    );
51
52
    protected static $unencoded_characters = array();
53
54
    protected static $valid_pattern;
55
56
    /**
57
     * Constructor for URI parts.
58
     *
59
     * Note that, if overriding the abstract class's constructor, care should be taken to compile unencoded characters
60
     * prior to compiling the part's valid pattern, as the default behavior of the abstract class is to base the part's
61
     * validation pattern on compiled unencoded characters.
62
     *
63
     * @see AbstractUriPart::compileUnencodedCharacters()
64
     * @see AbstractUriPart::compileValidPattern()
65
     *
66
     * @param string $part_data The data used to construct a URI part
67
     * @param string $part_name The name of the URI part for exception reporting
68
     * @param string $part_type [optional] The expected type of the URI part
69
     */
70 171
    public function __construct($part_data, $part_name, $part_type = "string")
71
    {
72 171
        if (gettype($part_data) != $part_type) {
73 24
            throw new \InvalidArgumentException("{$part_name} must be a {$part_type}");
74 147
        } elseif (!static::isValid($part_data)) {
75 24
            $part_data = $this->encode($part_data);
76 24
        }
77
78 147
        $this->data = $part_data;
79 147
    }
80
81
    /**
82
     * Returns a string representation of the URI component
83
     *
84
     * @return string   A string representation of the URI component
85
     */
86 137
    public function __toString()
87
    {
88 137
        return (string) $this->data;
89
    }
90
91 21
    public static function getValidPattern()
92
    {
93 21
        static::compileValidPattern();
94
95 21
        return static::$part_pattern;
96
    }
97
98
    /**
99
     * Determines whether a given string adheres to the RFC3986 specification for the extending URI part.
100
     *
101
     * Requires extending classes to define self::$valid_pattern.
102
     *
103
     * @see https://tools.ietf.org/html/rfc3986#appendix-A
104
     *
105
     * @param mixed $data   The data to check for validity
106
     *
107
     * @return bool         Returns true if the provided query matches the RFC3986 specification
108
     *                      Returns false otherwise
109
     */
110 216
    public static function isValid($data)
111
    {
112 216
        static::compileValidPattern();
113
114 216
        $pattern_found = preg_match(static::$valid_pattern, $data, $matches);
115
116 216
        return (bool) $pattern_found;
117
    }
118
119
    /**
120
     * @return string
121
     */
122 49
    public function toUriString()
123
    {
124 49
        return (string) $this;
125
    }
126
127
    /**
128
     * Percent-encodes invalid characters within a given string. Percent-encoding ignores valid as defined by the
129
     * component per RFC3986.
130
     *
131
     * @see https://tools.ietf.org/html/rfc3986#appendix-A
132
     *
133
     * @param string $string     The query string to be percent-encoded
134
     *
135
     * @return string            The query string with invalid characters percent-encoded
136
     */
137 24
    protected function encode($string)
138
    {
139 24
        $encoded_query = $string;
140
141 24
        if (!empty(static::$unencoded_characters)) {
142 24
            $string_helper = new StringHelper($string);
143
144 24
            $encoded_query = $string_helper->affectChunks("rawurlencode", ...static::$unencoded_characters);
145 24
        }
146
147 24
        return $encoded_query;
148
    }
149
150
    /**
151
     * Creates a validation pattern based upon a URI part's unencoded characters, allowing for empty strings (^$),
152
     * word characters (\w), and percent encoding by default.
153
     *
154
     * @see AbstractUriPart::compileUnencodedCharacters()
155
     *
156
     * @return void
157
     */
158 186
    protected static function compileValidPattern()
159
    {
160 186
        static::compileUnencodedCharacters();
161
162 186
        $valid_character_string = implode(static::$unencoded_characters);
163
164 186
        if (empty(static::$part_pattern)) {
165
            static::$part_pattern = '([\w';   //start decoded group
166
167
            static::$part_pattern = static::$part_pattern . preg_quote($valid_character_string, "/");
168
169
            static::$part_pattern = static::$part_pattern .
170
                ']|' .                          //predefined patterns or percent-encoding
171
                self::$pct_encoded_pattern .
172
                ')*';
173
        }
174
175 186
        static::$valid_pattern = '/^$|^' . //allows part to be empty
176 186
            static::$part_pattern .
177 186
            '$/';
178 186
    }
179
180
    /**
181
     * Compiles unencoded characters provided a URI part's composition, as defined by its compositions property.
182
     * Note that unencoded characters form the basis for the URI part's validation pattern.
183
     *
184
     * @see AbstractUriPart::compileValidPattern()
185
     *
186
     * @return void
187
     */
188 209
    protected static function compileUnencodedCharacters()
189
    {
190 209
        foreach (static::$compositions as $composition) {
191 209
            $composition_characters = self::${$composition};
192
193 209
            $delta = array_diff($composition_characters, static::$unencoded_characters);
194
195 209
            if (!empty($delta)) {
196
                static::$unencoded_characters = array_merge(static::$unencoded_characters, self::${$composition});
197
            }
198 209
        }
199 209
    }
200
}
201