Completed
Push — master ( b66e97...9d450b )
by Kevin
02:16
created

Element::getAllowedAttrbutes()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 147
Code Lines 131

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 147
ccs 0
cts 130
cp 0
rs 8.2857
cc 1
eloc 131
nc 1
nop 0
crap 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Groundskeeper\Tokens\Elements;
4
5
use Groundskeeper\Configuration;
6
use Groundskeeper\Tokens\AbstractToken;
7
use Groundskeeper\Tokens\Token;
8
9
class Element extends AbstractToken
10
{
11
    const ATTR_CI_ENUM   = 'attr_ci_enum';// case-insensitive enumeration
12
    const ATTR_JS        = 'attr_js';
13
    const ATTR_CI_STRING = 'attr_ci_str'; // case-insensitive string
14
    const ATTR_CS_STRING = 'attr_cs_str'; // case-sensitive string
15
    const ATTR_URI       = 'attr_uri';
16
17
    /** @var array */
18
    private $attributes;
19
20
    /** @var array[Token] */
21
    private $children;
22
23
    /** @var string */
24
    private $name;
25
26
    /**
27
     * Constructor
28
     */
29 3
    public function __construct($name, array $attributes = array(), Token $parent = null)
30
    {
31 3
        parent::__construct(Token::ELEMENT, $parent);
32
33 3
        $this->attributes = $attributes;
34 3
        $this->children = array();
35 3
        $this->setName($name);
36 3
    }
37
38
    /**
39
     * Getter for 'attributes'.
40
     */
41 1
    public function getAttributes()
42
    {
43 1
        return $this->attributes;
44
    }
45
46
    public function addAttribute($key, $value)
47
    {
48
        $key = strtolower($key);
49
        $this->attributes[$key] = $value;
50
51
        return $this;
52
    }
53
54
    public function removeAttribute($key)
55
    {
56
        $key = strtolower($key);
57
        if (isset($this->attributes[$key])) {
58
            unset($this->attributes[$key]);
59
60
            return true;
61
        }
62
63
        return false;
64
    }
65
66
    /**
67
     * Getter for 'children'.
68
     */
69 1
    public function getChildren()
70
    {
71 1
        return $this->children;
72
    }
73
74
    public function addChild(Token $token)
75
    {
76
        $this->children[] = $token;
77
78
        return $this;
79
    }
80
81
    public function removeChild(Token $token)
82
    {
83
        $key = array_search($token, $this->children);
84
        if ($key !== false) {
85
            unset($this->children[$key]);
86
87
            return true;
88
        }
89
90
        return false;
91
    }
92
93
    /**
94
     * Getter for 'name'.
95
     */
96 1
    public function getName()
97
    {
98 1
        return $this->name;
99
    }
100
101
    /**
102
     * Chainable setter for 'name'.
103
     */
104 3
    public function setName($name)
105
    {
106 3
        if (!is_string($name)) {
107
            throw new \InvalidArgumentException('Element name must be string type.');
108
        }
109
110 3
        $this->name = trim(strtolower($name));
111
112 3
        return $this;
113
    }
114
115
    protected function getAllowedAttrbutes()
116
    {
117
        return array(
118
            // Global Attributes
119
            '/^accesskey$/i' => self::ATTR_CS_STRING,
120
            '/^contenteditable$/i' => self::ATTR_CS_STRING,
121
            '/^contextmenu$/i' => self::ATTR_CS_STRING,
122
            '/^dir$/i' => self::ATTR_CS_STRING,
123
            '/^draggable$/i' => self::ATTR_CS_STRING,
124
            '/^dropzone$/i' => self::ATTR_CS_STRING,
125
            '/^hidden$/i' => self::ATTR_CS_STRING,
126
            '/^is$/i' => self::ATTR_CS_STRING,
127
            '/^itemid$/i' => self::ATTR_CS_STRING,
128
            '/^itemprop$/i' => self::ATTR_CS_STRING,
129
            '/^itemref$/i' => self::ATTR_CS_STRING,
130
            '/^itemscope$/i' => self::ATTR_CS_STRING,
131
            '/^itemtype$/i' => self::ATTR_CS_STRING,
132
            '/^lang$/i' => self::ATTR_CI_STRING,
133
            '/^spellcheck$/i' => self::ATTR_CS_STRING,
134
            '/^style$/i' => self::ATTR_CS_STRING,
135
            '/^tabindex$/i' => self::ATTR_CS_STRING,
136
            '/^title$/i' => self::ATTR_CS_STRING,
137
            '/^translate$/i' => self::ATTR_CI_ENUM . '("","yes","no")',
138
139
            // Event Handler Content Attributes
140
            // https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-content-attributes
141
            '/^onabort$/i' => self::ATTR_JS,
142
            '/^onautocomplete$/i' => self::ATTR_JS,
143
            '/^onautocompleteerror$/i' => self::ATTR_JS,
144
            '/^onblur$/i' => self::ATTR_JS,
145
            '/^oncancel$/i' => self::ATTR_JS,
146
            '/^oncanplay$/i' => self::ATTR_JS,
147
            '/^oncanplaythrough$/i' => self::ATTR_JS,
148
            '/^onchange$/i' => self::ATTR_JS,
149
            '/^onclick$/i' => self::ATTR_JS,
150
            '/^onclose$/i' => self::ATTR_JS,
151
            '/^oncontextmenu$/i' => self::ATTR_JS,
152
            '/^oncuechange$/i' => self::ATTR_JS,
153
            '/^ondblclick$/i' => self::ATTR_JS,
154
            '/^ondrag$/i' => self::ATTR_JS,
155
            '/^ondragend$/i' => self::ATTR_JS,
156
            '/^ondragenter$/i' => self::ATTR_JS,
157
            '/^ondragexit$/i' => self::ATTR_JS,
158
            '/^ondragleave$/i' => self::ATTR_JS,
159
            '/^ondragover$/i' => self::ATTR_JS,
160
            '/^ondragstart$/i' => self::ATTR_JS,
161
            '/^ondrop$/i' => self::ATTR_JS,
162
            '/^ondurationchange$/i' => self::ATTR_JS,
163
            '/^onemptied$/i' => self::ATTR_JS,
164
            '/^onended$/i' => self::ATTR_JS,
165
            '/^onerror$/i' => self::ATTR_JS,
166
            '/^onfocus$/i' => self::ATTR_JS,
167
            '/^oninput$/i' => self::ATTR_JS,
168
            '/^oninvalid$/i' => self::ATTR_JS,
169
            '/^onkeydown$/i' => self::ATTR_JS,
170
            '/^onkeypress$/i' => self::ATTR_JS,
171
            '/^onkeyup$/i' => self::ATTR_JS,
172
            '/^onload$/i' => self::ATTR_JS,
173
            '/^onloadeddata$/i' => self::ATTR_JS,
174
            '/^onloadedmetadata$/i' => self::ATTR_JS,
175
            '/^onloadstart$/i' => self::ATTR_JS,
176
            '/^onmousedown$/i' => self::ATTR_JS,
177
            '/^onmouseenter$/i' => self::ATTR_JS,
178
            '/^onmouseleave$/i' => self::ATTR_JS,
179
            '/^onmousemove$/i' => self::ATTR_JS,
180
            '/^onmouseout$/i' => self::ATTR_JS,
181
            '/^onmouseover$/i' => self::ATTR_JS,
182
            '/^onmouseup$/i' => self::ATTR_JS,
183
            '/^onwheel$/i' => self::ATTR_JS,
184
            '/^onpause$/i' => self::ATTR_JS,
185
            '/^onplay$/i' => self::ATTR_JS,
186
            '/^onplaying$/i' => self::ATTR_JS,
187
            '/^onprogress$/i' => self::ATTR_JS,
188
            '/^onratechange$/i' => self::ATTR_JS,
189
            '/^onreset$/i' => self::ATTR_JS,
190
            '/^onresize$/i' => self::ATTR_JS,
191
            '/^onscroll$/i' => self::ATTR_JS,
192
            '/^onseeked$/i' => self::ATTR_JS,
193
            '/^onseeking$/i' => self::ATTR_JS,
194
            '/^onselect$/i' => self::ATTR_JS,
195
            '/^onshow$/i' => self::ATTR_JS,
196
            '/^onstalled$/i' => self::ATTR_JS,
197
            '/^onsubmit$/i' => self::ATTR_JS,
198
            '/^onsuspend$/i' => self::ATTR_JS,
199
            '/^ontimeupdate$/i' => self::ATTR_JS,
200
            '/^ontoggle$/i' => self::ATTR_JS,
201
            '/^onvolumechange$/i' => self::ATTR_JS,
202
            '/^onwaiting$/i' => self::ATTR_JS,
203
204
            // WAI-ARIA
205
            // https://w3c.github.io/aria/aria/aria.html
206
            '/^role$/i' => self::ATTR_CI_STRING,
207
208
            // ARIA global states and properties
209
            '/^aria-atomic$/i' => self::ATTR_CS_STRING,
210
            '/^aria-busy$/i' => self::ATTR_CS_STRING,
211
            '/^aria-controls$/i' => self::ATTR_CS_STRING,
212
            '/^aria-current$/i' => self::ATTR_CS_STRING,
213
            '/^aria-describedby$/i' => self::ATTR_CS_STRING,
214
            '/^aria-details$/i' => self::ATTR_CS_STRING,
215
            '/^aria-disabled$/i' => self::ATTR_CS_STRING,
216
            '/^aria-dropeffect$/i' => self::ATTR_CS_STRING,
217
            '/^aria-errormessage$/i' => self::ATTR_CS_STRING,
218
            '/^aria-flowto$/i' => self::ATTR_CS_STRING,
219
            '/^aria-grabbed$/i' => self::ATTR_CS_STRING,
220
            '/^aria-haspopup$/i' => self::ATTR_CS_STRING,
221
            '/^aria-hidden$/i' => self::ATTR_CS_STRING,
222
            '/^aria-invalid$/i' => self::ATTR_CS_STRING,
223
            '/^aria-label$/i' => self::ATTR_CS_STRING,
224
            '/^aria-labelledby$/i' => self::ATTR_CS_STRING,
225
            '/^aria-live$/i' => self::ATTR_CS_STRING,
226
            '/^aria-owns$/i' => self::ATTR_CS_STRING,
227
            '/^aria-relevant$/i' => self::ATTR_CS_STRING,
228
            '/^aria-roledescription$/i' => self::ATTR_CS_STRING,
229
230
            // ARIA widget attributes
231
            '/^aria-autocomplete$/i' => self::ATTR_CS_STRING,
232
            '/^aria-checked$/i' => self::ATTR_CS_STRING,
233
            '/^aria-expanded$/i' => self::ATTR_CS_STRING,
234
            '/^aria-level$/i' => self::ATTR_CS_STRING,
235
            '/^aria-modal$/i' => self::ATTR_CS_STRING,
236
            '/^aria-multiline$/i' => self::ATTR_CS_STRING,
237
            '/^aria-multiselectable$/i' => self::ATTR_CS_STRING,
238
            '/^aria-orientation$/i' => self::ATTR_CS_STRING,
239
            '/^aria-placeholder$/i' => self::ATTR_CS_STRING,
240
            '/^aria-pressed$/i' => self::ATTR_CS_STRING,
241
            '/^aria-readonly$/i' => self::ATTR_CS_STRING,
242
            '/^aria-required$/i' => self::ATTR_CS_STRING,
243
            '/^aria-selected$/i' => self::ATTR_CS_STRING,
244
            '/^aria-sort$/i' => self::ATTR_CS_STRING,
245
            '/^aria-valuemax$/i' => self::ATTR_CS_STRING,
246
            '/^aria-valuemin$/i' => self::ATTR_CS_STRING,
247
            '/^aria-valuenow$/i' => self::ATTR_CS_STRING,
248
            '/^aria-valuetext$/i' => self::ATTR_CS_STRING,
249
250
            // ARIA relationship attributes
251
            '/^aria-activedescendant$/i' => self::ATTR_CS_STRING,
252
            '/^aria-colcount$/i' => self::ATTR_CS_STRING,
253
            '/^aria-colindex$/i' => self::ATTR_CS_STRING,
254
            '/^aria-colspan$/i' => self::ATTR_CS_STRING,
255
            '/^aria-posinset$/i' => self::ATTR_CS_STRING,
256
            '/^aria-rowcount$/i' => self::ATTR_CS_STRING,
257
            '/^aria-rowindex$/i' => self::ATTR_CS_STRING,
258
            '/^aria-rowspan$/i' => self::ATTR_CS_STRING,
259
            '/^aria-setsize$/i' => self::ATTR_CS_STRING
260
        );
261
    }
262
263
    protected function isAttributeNameValid($name)
264
    {
265
        $allowedAttributes = $this->getAllowedAttrbutes();
266
        foreach ($allowedAttributes as $attrRegex => $valueType) {
267
            if (preg_match($attrRegex, $name) === 1) {
268
                return true;
269
            }
270
        }
271
272
        return false;
273
    }
274
275 2
    public function validate(Configuration $configuration)
276
    {
277 2
        parent::validate($configuration);
278
279 2
        if (!$this->isValid) {
280
            return;
281
        }
282
283 2
        if ($configuration->get('strategy') == 'standard') {
284
            // Remove non-standard attributes.
285 2
            foreach ($this->attributes as $name => $value) {
286
                // Validate attribute name
287
                if (!$this->isAttributeNameValid($name)) {
288
                    unset($this->attributes[$name]);
289
                    continue;
290
                }
291
292
                // Validate attributes value
293
                /// @todo
294 2
            }
295 2
        }
296
297 2
        foreach ($this->children as $child) {
298
            $child->validate($configuration);
299 2
        }
300 2
    }
301
302 2 View Code Duplication
    public function toString(Configuration $configuration, $prefix = '', $suffix = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
303
    {
304 2
        if (!$this->isValid) {
305
            return '';
306
        }
307
308 2
        $output = $this->toStringTag($configuration, $prefix, $suffix);
309 2
        if (empty($this->children)) {
310 2
            return $output;
311
        }
312
313
        foreach ($this->children as $child) {
314
            $newPrefix = $prefix . str_repeat(' ', $configuration->get('indent-spaces'));
315
            $output .= $child->toString($options, $newPrefix, $suffix);
0 ignored issues
show
Bug introduced by
The variable $options does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
316
        }
317
318
        return $output . $prefix . '</' . $this->name . '>' . $suffix;
319
    }
320
321 2
    protected function toStringTag(Configuration $configuration, $prefix = '', $suffix = '', $forceOpen = false)
0 ignored issues
show
Unused Code introduced by
The parameter $configuration is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
322
    {
323 2
        $output = $prefix . '<' . $this->name;
324 2
        foreach ($this->attributes as $key => $value) {
325
            $output .= ' ' . strtolower($key);
326
            if (is_string($value)) {
327
                $output .= '="' . $value . '"';
328
            }
329 2
        }
330
331 2
        if (!$forceOpen && empty($this->children)) {
332 2
            return $output . '/>' . $suffix;
333
        }
334
335
        return $output . '>' . $suffix;
336
    }
337
}
338