Completed
Push — master ( 895d73...5bc057 )
by Federico
02:36
created

AttributesCompiler   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 192
rs 8.3999
wmc 46
lcom 1
cbo 1

How to fix   Complexity   

Complex Class

Complex classes like AttributesCompiler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AttributesCompiler, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Jade\Compiler;
4
5
abstract class AttributesCompiler extends CompilerFacade
6
{
7
    protected function getAttributeDisplayCode($key, $value, $valueCheck)
8
    {
9
        if ($key === 'style') {
10
            $value = preg_replace('/::get(Escaped|Unescaped)Value/', '::get$1Style', $value, 1);
11
        }
12
13
        return is_null($valueCheck)
14
            ? ' ' . $key . '=' . $this->quote . $value . $this->quote
15
            : $this->createCode('if (true === ($__value = %1$s)) { ', $valueCheck)
16
                . $this->getBooleanAttributeDisplayCode($key)
17
                . $this->createCode('} else if (\\Jade\\Compiler::isDisplayable($__value)) { ')
18
                . ' ' . $key . '=' . $this->quote . $value . $this->quote
19
                . $this->createCode('}');
20
    }
21
22
    protected function getBooleanAttributeDisplayCode($key)
23
    {
24
        return ' ' . $key . ($this->terse
25
            ? ''
26
            : '=' . $this->quote . $key . $this->quote
27
        );
28
    }
29
30
    protected function getValueStatement($statements)
31
    {
32
        return is_string($statements[0])
33
            ? $statements[0]
34
            : $statements[0][0];
35
    }
36
37
    protected function getAndAttributeCode($attr, &$classes, &$classesCheck)
38
    {
39
        $addClasses = '""';
40
        if (count($classes) || count($classesCheck)) {
41
            foreach ($classes as &$value) {
42
                $value = var_export($value, true);
43
            }
44
            foreach ($classesCheck as $value) {
45
                $statements = $this->createStatements($value);
46
                $classes[] = $statements[0][0];
47
            }
48
            $addClasses = '" " . implode(" ", array(' . implode(', ', $classes) . '))';
49
            $classes = array();
50
            $classesCheck = array();
51
        }
52
        $value = empty($attr['value']) ? 'attributes' : $attr['value'];
53
        $statements = $this->createStatements($value);
54
55
        return $this->createCode(
56
            '$__attributes = ' . $this->getValueStatement($statements) . ';' .
57
            'if (is_array($__attributes)) { ' .
58
                '$__attributes["class"] = trim(' .
59
                    '$__classes = (empty($__classes) ? "" : $__classes . " ") . ' .
60
                    '(isset($__attributes["class"]) ? (is_array($__attributes["class"]) ? implode(" ", $__attributes["class"]) : $__attributes["class"]) : "") . ' .
61
                    $addClasses .
62
                '); ' .
63
                'if (empty($__attributes["class"])) { ' .
64
                    'unset($__attributes["class"]); ' .
65
                '} ' .
66
            '} ' .
67
            '\\Jade\\Compiler::displayAttributes($__attributes, ' . var_export($this->quote, true) . ', ' . var_export($this->terse, true) . ');');
68
    }
69
70
    protected function getClassAttribute($value, &$classesCheck)
71
    {
72
        $statements = $this->createStatements($value);
73
        $value = is_array($statements[0]) ? $statements[0][0] : $statements[0];
74
        $classesCheck[] = '(is_array($_a = ' . $value . ') ? implode(" ", $_a) : $_a)';
75
76
        return $this->keepNullAttributes ? '' : 'null';
77
    }
78
79
    protected function getValueCode($escaped, $value, &$valueCheck)
80
    {
81
        if ($this->keepNullAttributes) {
82
            return $this->escapeIfNeeded($escaped, $value);
83
        }
84
85
        $valueCheck = $value;
86
87
        return $this->escapeIfNeeded($escaped, '$__value');
88
    }
89
90
    protected function getAttributeValue($escaped, $key, $value, &$classesCheck, &$valueCheck)
91
    {
92
        if ($this->isConstant($value)) {
93
            $value = trim($value, ' \'"');
94
95
            return $value === 'undefined' ? 'null' : $value;
96
        }
97
98
        $json = static::parseValue($value);
99
100
        if ($key === 'class') {
101
            return $json !== null && is_array($json)
102
                ? implode(' ', $json)
103
                : $this->getClassAttribute($value, $classesCheck);
104
        }
105
106
        return $this->getValueCode($escaped, $value, $valueCheck);
107
    }
108
109
    protected function escapeValueIfNeeded($value, $escaped, $valueCheck)
110
    {
111
        return is_null($valueCheck) && $escaped && !$this->keepNullAttributes
112
            ? $this->escapeValue($value)
113
            : $value;
114
    }
115
116
    protected function compileAttributeValue($key, $value, $attr, $valueCheck)
117
    {
118
        return $value === true || $attr['value'] === true
119
            ? $this->getBooleanAttributeDisplayCode($key)
120
            : ($value !== false && $attr['value'] !== false && $value !== 'null' && $value !== 'undefined'
121
                ? $this->getAttributeDisplayCode(
122
                    $key,
123
                    $this->escapeValueIfNeeded($value, $attr['escaped'], $valueCheck),
124
                    $valueCheck
125
                )
126
                : ''
127
            );
128
    }
129
130
    protected function getAttributeCode($attr, &$classes, &$classesCheck)
131
    {
132
        $key = trim($attr['name']);
133
134
        if ($key === '&attributes') {
135
            return $this->getAndAttributeCode($attr, $classes, $classesCheck);
136
        }
137
138
        $valueCheck = null;
139
        $value = trim($attr['value']);
140
141
        $value = $this->getAttributeValue($attr['escaped'], $key, $value, $classesCheck, $valueCheck);
142
143
        if ($key === 'class') {
144
            if ($value !== 'false' && $value !== 'null' && $value !== 'undefined') {
145
                array_push($classes, $value);
146
            }
147
148
            return '';
149
        }
150
151
        return $this->compileAttributeValue($key, $value, $attr, $valueCheck);
152
    }
153
154
    protected function getClassesCode(&$classes, &$classesCheck)
155
    {
156
        return trim($this->createCode(
157
            '$__classes = implode(" ", ' .
158
                'array_unique(explode(" ", (empty($__classes) ? "" : $__classes) . ' .
159
                    var_export(implode(' ', $classes), true) . ' . ' .
160
                    'implode(" ", array(' . implode(', ', $classesCheck) . ')) ' .
161
                ')) ' .
162
            ');'
163
        ));
164
    }
165
166
    protected function getClassesDisplayCode()
167
    {
168
        return trim($this->createCode(
169
            'if (!empty($__classes)) { ' .
170
                '?> ' . (isset($this->options['classAttribute'])
171
                    ? $this->options['classAttribute']
172
                    : 'class'
173
                ) . '=' . $this->quote . '<?php echo $__classes; ?>' . $this->quote . '<?php ' .
174
            '} ' .
175
            'unset($__classes); '
176
        ));
177
    }
178
179
    /**
180
     * @param array $attributes
181
     */
182
    protected function compileAttributes($attributes)
183
    {
184
        $items = '';
185
        $classes = array();
186
        $classesCheck = array();
187
188
        foreach ($attributes as $attr) {
189
            $items .= $this->getAttributeCode($attr, $classes, $classesCheck);
190
        }
191
192
        $items .= $this->getClassesCode($classes, $classesCheck);
193
194
        $this->buffer($items, false);
195
    }
196
}
197