Completed
Push — master ( 3a7ed1...6676dd )
by Lars
01:49
created

domElementAfterMinification()   C

Complexity

Conditions 16
Paths 49

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 16

Importance

Changes 0
Metric Value
dl 0
loc 57
ccs 25
cts 25
cp 1
rs 5.5666
c 0
b 0
f 0
cc 16
nc 49
nop 2
crap 16

How to fix   Long Method    Complexity   

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
declare(strict_types=1);
4
5
namespace voku\helper;
6
7
/**
8
 * HtmlMinDomObserverOptimizeAttributes: Optimize html attributes. [protected html is still protected]
9
 *
10
 * Sort HTML-Attributes, so that gzip can do better work and remove some default attributes...
11
 */
12
final class HtmlMinDomObserverOptimizeAttributes implements HtmlMinDomObserverInterface
13
{
14
    /**
15
     * // https://mathiasbynens.be/demo/javascript-mime-type
16
     * // https://developer.mozilla.org/en/docs/Web/HTML/Element/script#attr-type
17
     *
18
     * @var array
19
     */
20
    private static $executableScriptsMimeTypes = [
21
        'text/javascript'          => '',
22
        'text/ecmascript'          => '',
23
        'text/jscript'             => '',
24
        'application/javascript'   => '',
25
        'application/x-javascript' => '',
26
        'application/ecmascript'   => '',
27
    ];
28
29
    /**
30
     * Receive dom elements before the minification.
31
     *
32
     * @param SimpleHtmlDom $element
33
     * @param HtmlMin       $htmlMin
34
     */
35 33
    public function domElementBeforeMinification(SimpleHtmlDom $element, HtmlMin $htmlMin) {
36
37 33
    }
38
39
    /**
40
     * Receive dom elements after the minification.
41
     *
42
     * @param SimpleHtmlDom $element
43
     * @param HtmlMin       $htmlMin
44
     */
45 33
    public function domElementAfterMinification(SimpleHtmlDom $element, HtmlMin $htmlMin) {
46 33
        $attributes = $element->getAllAttributes();
47 33
        if ($attributes === null) {
48 33
            return;
49
        }
50
51 20
        $attrs = [];
52 20
        foreach ((array) $attributes as $attrName => $attrValue) {
53
54
            // -------------------------------------------------------------------------
55
            // Remove optional "http:"-prefix from attributes.
56
            // -------------------------------------------------------------------------
57
58 20
            if ($htmlMin->isDoRemoveHttpPrefixFromAttributes() === true) {
59
                if (
60 3
                    ($attrName === 'href' || $attrName === 'src' || $attrName === 'action')
61
                    &&
62 3
                    !(isset($attributes['rel']) && $attributes['rel'] === 'external')
63
                    &&
64 3
                    !(isset($attributes['target']) && $attributes['target'] === '_blank')
65
                ) {
66 2
                    $attrValue = \str_replace('http://', '//', $attrValue);
67
                }
68
            }
69
70 20
            if ($this->removeAttributeHelper($element->tag, $attrName, $attrValue, $attributes, $htmlMin)) {
71 4
                $element->{$attrName} = null;
72
73 4
                continue;
74
            }
75
76
            // -------------------------------------------------------------------------
77
            // Sort css-class-names, for better gzip results.
78
            // -------------------------------------------------------------------------
79
80 20
            if ($htmlMin->isDoSortCssClassNames() === true) {
81 19
                $attrValue = $this->sortCssClassNames($attrName, $attrValue);
82
            }
83
84 20
            if ($htmlMin->isDoSortHtmlAttributes() === true) {
85 19
                $attrs[$attrName] = $attrValue;
86 20
                $element->{$attrName} = null;
87
            }
88
        }
89
90
        // -------------------------------------------------------------------------
91
        // Sort html-attributes, for better gzip results.
92
        // -------------------------------------------------------------------------
93
94 20
        if ($htmlMin->isDoSortHtmlAttributes() === true) {
95 19
            \ksort($attrs);
96 19
            foreach ($attrs as $attrName => $attrValue) {
97 19
                $attrValue = HtmlDomParser::replaceToPreserveHtmlEntities($attrValue);
98 19
                $element->setAttribute($attrName, $attrValue, true);
99
            }
100
        }
101 20
    }
102
103
104
    /**
105
     * Check if the attribute can be removed.
106
     *
107
     * @param string  $tag
108
     * @param string  $attrName
109
     * @param string  $attrValue
110
     * @param array   $allAttr
111
     * @param HtmlMin $htmlMin
112
     *
113
     * @return bool
114
     */
115 20
    private function removeAttributeHelper($tag, $attrName, $attrValue, $allAttr, HtmlMin $htmlMin): bool
116
    {
117
        // remove defaults
118 20
        if ($htmlMin->isDoRemoveDefaultAttributes() === true) {
119 1
            if ($tag === 'script' && $attrName === 'language' && $attrValue === 'javascript') {
120
                return true;
121
            }
122
123 1
            if ($tag === 'form' && $attrName === 'method' && $attrValue === 'get') {
124
                return true;
125
            }
126
127 1
            if ($tag === 'input' && $attrName === 'type' && $attrValue === 'text') {
128
                return true;
129
            }
130
131 1
            if ($tag === 'area' && $attrName === 'shape' && $attrValue === 'rect') {
132
                return true;
133
            }
134
        }
135
136
        // remove deprecated charset-attribute (the browser will use the charset from the HTTP-Header, anyway)
137 20
        if ($htmlMin->isDoRemoveDeprecatedScriptCharsetAttribute() === true) {
138 19
            if ($tag === 'script' && $attrName === 'charset' && !isset($allAttr['src'])) {
139
                return true;
140
            }
141
        }
142
143
        // remove deprecated anchor-jump
144 20
        if ($htmlMin->isDoRemoveDeprecatedAnchorName() === true) {
145 19
            if ($tag === 'a' && $attrName === 'name' && isset($allAttr['id']) && $allAttr['id'] === $attrValue) {
146
                return true;
147
            }
148
        }
149
150
        // remove "type=text/css" for css links
151 20 View Code Duplication
        if ($htmlMin->isDoRemoveDeprecatedTypeFromStylesheetLink() === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
152 19
            if ($tag === 'link' && $attrName === 'type' && $attrValue === 'text/css' && isset($allAttr['rel']) && $allAttr['rel'] === 'stylesheet') {
153 1
                return true;
154
            }
155
        }
156
157
        // remove deprecated script-mime-types
158 20
        if ($htmlMin->isDoRemoveDeprecatedTypeFromScriptTag() === true) {
159 19
            if ($tag === 'script' && $attrName === 'type' && isset($allAttr['src'], self::$executableScriptsMimeTypes[$attrValue])) {
160 1
                return true;
161
            }
162
        }
163
164
        // remove 'value=""' from <input type="text">
165 20 View Code Duplication
        if ($htmlMin->isDoRemoveValueFromEmptyInput() === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
166 19
            if ($tag === 'input' && $attrName === 'value' && $attrValue === '' && isset($allAttr['type']) && $allAttr['type'] === 'text') {
167 1
                return true;
168
            }
169
        }
170
171
        // remove some empty attributes
172 20
        if ($htmlMin->isDoRemoveEmptyAttributes() === true) {
173 19
            if (\trim($attrValue) === '' && \preg_match('/^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$/', $attrName)) {
174 3
                return true;
175
            }
176
        }
177
178 20
        return false;
179
    }
180
181
182
    /**
183
     * @param $attrName
184
     * @param $attrValue
185
     *
186
     * @return string
187
     */
188 19
    private function sortCssClassNames($attrName, $attrValue): string
189
    {
190 19
        if ($attrName !== 'class' || !$attrValue) {
191 16
            return $attrValue;
192
        }
193
194 10
        $classes = \array_unique(
195 10
            \explode(' ', $attrValue)
196
        );
197 10
        \sort($classes);
198
199 10
        $attrValue = '';
200 10
        foreach ($classes as $class) {
201 10
            if (!$class) {
202 3
                continue;
203
            }
204
205 10
            $attrValue .= \trim($class) . ' ';
206
        }
207
208 10
        return \trim($attrValue);
209
    }
210
}
211