Form   B
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Test Coverage

Coverage 23.53%

Importance

Changes 0
Metric Value
dl 0
loc 263
ccs 24
cts 102
cp 0.2353
rs 8.295
c 0
b 0
f 0
wmc 42

15 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 8 4
A input() 0 6 2
A button() 0 6 2
A select() 0 11 4
B attributesToHtml() 0 10 5
B box() 0 11 5
A setup() 0 5 1
A addTag() 0 4 1
A label() 0 7 2
A textarea() 0 4 1
B __call() 0 19 7
A open() 0 10 3
A submit() 0 3 1
A addAttr() 0 7 2
A init() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like Form 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.

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 Form, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace HakimCh\Form;
3
4
class Form
5
{
6
    /**
7
     * Submitted datas
8
     * @var array
9
     */
10
    public $datas = [];
11
12
    /**
13
     * Tag attributes
14
     * @var array
15
     */
16
    public $attributes = [];
17
18
    /**
19
     * Form action url
20
     * @var string
21
     */
22
    private $action = '';
23
24
    /**
25
     * Form CSRF token
26
     * @var string
27
     */
28
    private $token = '';
29
30
    /**
31
     * Class instance
32
     * @var object
33
     */
34
    private static $instance;
35
36
    /**
37
     * Class's Instance
38
     * @return object
39
     */
40
    public static function init()
41
    {
42
        if(is_null(self::$instance)) {
43
            self::$instance = new Form();
44
        }
45
        return self::$instance;
46
    }
47
48
    /**
49
     * Setup the class provided from a framework or script
50
     * @param array $datas Submitted data (GET, POST)
51
     * @param string $token CSRF token
52
     * @param string $action Url action
53
     */
54
    public function setup($datas=[], $token='', $action='')
55
    {
56
        $this->datas  = $datas;
57
        $this->token  = $token;
58
        $this->action = $action;
59
    }
60
61
    /**
62
     * Create Form tag
63
     * @param string $method
64
     * @param string $action form url
65
     * @return string
66
     */
67 1
    public function open($method = 'POST', $action = '')
68
    {
69 1
        if(empty($action)) {
70
            $action = $this->action;
71
        }
72 1
        $html = '<form action="'.$action.'" method="'.$method.'"'.$this->attributesToHtml().'>';
73 1
        if(!empty($this->token)) {
74
            $html .= $this->addAttr('value', $this->token)->input('token', 'hidden');
75
        }
76 1
        return $html;
77
    }
78
79
    /**
80
     * Create label
81
     * @param string|integer $value
82
     * @param boolean $required
83
     * @return string
84
     */
85
    public function label($value, $required = null)
86
    {
87
        $labelValue = ucfirst($value);
88
        if($required) {
89
            $labelValue .= ' <span class="required">*</span>';
90
        }
91
        return $this->addTag('label', $labelValue);
92
    }
93
94
    /**
95
     * Create Select tag
96
     * @param string $fieldName
97
     * @param array $options
98
     * @return string
99
     */
100
    public function select($fieldName, $options = [])
101
    {
102
        $fieldOptions = '';
103
        if(!empty($options)) {
104
            $fieldValue = $this->get($fieldName);
105
            foreach($options as $value => $text) {
106
                $selected = $fieldValue != $value ? '' : ' selected="selected"';
107
                $fieldOptions .= '<option value="'.$value.'"'.$selected.'>'.ucfirst($text).'</option>';
108
            }
109
        }
110
        return $this->addTag('select', $fieldOptions);
111
    }
112
113
    /**
114
     * Create Textarea tag
115
     * @param string $fieldName
116
     * @return string
117
     */
118
    public function textarea($fieldName)
119
    {
120
        $fieldValue = $this->get($fieldName);
121
        return $this->addTag('textarea', $fieldValue);
122
    }
123
124
    /**
125
     * Create submit button
126
     * @param string  $value field text
127
     * @param string|null $iconClass the icon class from (fontawsome, ionicons...)
128
     * @return string
129
     */
130
    public function button($value = 'Submit', $iconClass = null)
131
    {
132
        if($iconClass){
0 ignored issues
show
Bug Best Practice introduced by
The expression $iconClass of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
133
            $value .= ' <i class="'.$iconClass.'"></i>';
134
        }
135
        return $this->addTag('button', $value);
136
    }
137
138
    /**
139
     * Create submit button
140
     * @param string $value  Field value
141
     * @return string
142
     */
143
    public function submit($value = 'Submit')
144
    {
145
        return $this->addAttr('value', $value)->input('submit', 'submit');
146
    }
147
148
    /**
149
     * Add an attribute to the field
150
     * @param String|Array $key attribute name
151
     * @param Integer|String $value attribute value
152
     * @return Form
153
     */
154 3
    public function addAttr($key, $value = null)
155
    {
156 3
        if(is_array($key))
157 3
            $this->attributes += $key;
158
        else
159 2
            $this->attributes[$key] = $value;
160 3
        return $this;
161
    }
162
163
    /**
164
     * Get element by key from the user datas
165
     * @param string $key the field name
166
     * @param string $source source of datas (datas, files, attributes)
167
     * @return mixed
168
     */
169 2
    public function get($key = '', $source = 'datas')
170
    {
171 2
        if(property_exists($this, $source)) {
172 2
            $property = $this->$source;
173 2
            if(!empty($property) && array_key_exists($key, $property))
174 2
                return $property[$key];
175
        }
176
        return null;
177
    }
178
179
    /**
180
     * Create Input field
181
     * @param string $fieldName Field name
182
     * @param string $type field type (text, password...)
183
     * @return string
184
     */
185
    protected function input($fieldName, $type) {
186
        $value = $this->get($fieldName);
187
        if(!is_null($value)) {
188
            $this->attributes['value'] = $this->get($fieldName);
189
        }
190
        return '<input type="'.$type.'" name="'.$fieldName.'"'.$this->attributesToHtml().'>';
191
    }
192
193
    /**
194
     * Create a radio/checkbox field
195
     * @param string $fieldName field name
196
     * @param string $fieldLabel field label
197
     * @param string $type field type
198
     * @return string
199
     */
200
    protected function box($fieldName, $fieldLabel = '', $type = '')
201
    {
202
        $fieldValue = $this->get($fieldName);
203
        $value = $this->get('value', 'attrs');
204
        if($fieldValue && $value){
205
            $checked = is_array($fieldValue) ? array_key_exists($value, array_flip($fieldValue)) : $fieldValue == $value;
206
            if($checked){
207
                $this->attributes['checked'] = 'checked';
208
            }
209
        }
210
        return $this->input($fieldName, $type) . " " . $fieldLabel;
211
    }
212
213
    /**
214
     * Add an HTML Form tag
215
     * @param string $tagType Tag type (label, textarea, select...)
216
     * @param string|integer $tagContent Tag content or value
217
     * @return string
218
     */
219
    protected function addTag($tagType, $tagContent)
220
    {
221
        $attributes = $this->attributesToHtml();
222
        return '<'.$tagType.' '.$attributes.'>'.$tagContent.'</'.$tagType.'>';
223
    }
224
225
    /**
226
     * Generate field's attributes
227
     * @param string $html
228
     * @return string
229
     */
230 2
    private function attributesToHtml($html = '')
231
    {
232 2
        if(!empty($this->attributes)) {
233 1
            foreach($this->attributes as $key => $value) {
234 1
                $value = is_array($value) ? implode(' ', $value) : $value;
235 1
                $html .= is_numeric($key) ? $value.' ' : $key.'="'.$value.'" ';
236 1
            }
237 1
        }
238 2
        $this->attributes = [];
239 2
        return $html;
240
    }
241
242
    /**
243
     * Magic methods call
244
     * @param $tagName
245
     * @param $methodParams
246
     * @return string
247
     */
248
    public function __call($tagName, $methodParams)
249
    {
250
        $method = null;
251
        if(in_array($tagName, ['text','password','date','time','file','hidden','reset'])) {
252
            array_push($methodParams, $tagName);
253
            $method = "input";
254
        }
255
        elseif(in_array($tagName, ['checkbox','radio'])) {
256
            array_push($methodParams, $tagName);
257
            $method = "box";
258
        }
259
        elseif($tagName == 'close') {
260
            return '</form>';
261
        }
262
        elseif($tagName == 'reset') {
263
            $this->datas = [];
264
        }
265
        $handler = [$this, $method];
266
        return !is_null($method) && is_callable($handler) ? call_user_func_array($handler, $methodParams) : '';
267
    }
268
}
269