Completed
Push — master ( 004fa5...9844ae )
by Alexey
06:55
created

ActiveForm::__construct()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 29
Code Lines 22

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 29
rs 8.439
cc 6
eloc 22
nc 12
nop 2
1
<?php
2
3
/**
4
 * Active form
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
12
namespace Ui;
13
14
class ActiveForm extends \Object
15
{
16
    public $model = null;
17
    public $modelName = '';
18
    public $header = "";
19
    public $action = "";
20
    public $form = [];
21
    public $inputs = [];
22
    public $formName = 'noNameForm';
23
    public $requestFormName = '';
24
    public $requestFullFormName = '';
25
    public $parent = null;
26
27
    public function __construct($model, $form = [])
28
    {
29
        if (is_array($model)) {
30
            $this->form = $model;
31
            if (is_string($form)) {
32
                $this->formName = $form;
33
            }
34
        } else {
35
            $this->model = $model;
36
            $this->modelName = get_class($model);
37
            if (is_array($form)) {
38
                $this->form = $form;
39
            } else {
40
                $this->formName = $form;
41
                $this->form = \App::$cur->ui->getModelForm($this->modelName, $form);
42
                $this->inputs = $this->getInputs();
43
            }
44
        }
45
        $this->requestFormName = "ActiveForm_{$this->formName}";
46
        $modeName = $this->modelName;
47
48
        if (!empty($this->form['name'])) {
49
            $this->header = $this->form['name'];
50
        } elseif (!empty($modeName::$objectName)) {
51
            $this->header = $modeName::$objectName;
52
        } else {
53
            $this->header = $this->modelName;
54
        }
55
    }
56
57
    public function getInputs()
58
    {
59
        $inputs = !empty($this->form['inputs']) ? $this->form['inputs'] : [];
60
        $modelName = $this->modelName;
61
        foreach ($this->form['map'] as $row) {
62
            foreach ($row as $col) {
63
                if (!$col || !empty($inputs[$col])) {
64
                    continue;
65
                }
66
                if (strpos($col, 'form:') === 0) {
67
                    $colPath = explode(':', $col);
68
                    if ($this->model->{$colPath[1]}) {
69
                        $inputs[$col] = new ActiveForm($this->model->{$colPath[1]}, $colPath[2]);
70
                    } else {
71
                        $relOptions = $modelName::getRelation($colPath[1]);
72
                        if (!isset($this->model->_params[$modelName::index()])) {
73
                            $this->model->_params[$modelName::index()] = 0;
74
                        }
75
                        $relOptions['model']::fixPrefix($relOptions['col']);
76
                        $inputs[$col] = new ActiveForm(new $relOptions['model']([ $relOptions['col'] => &$this->model->_params[$modelName::index()]]), $colPath[2]);
77
                    }
78
                    $inputs[$col]->parent = $this;
79
                } elseif (!empty($modelName::$cols[$col])) {
80
                    $inputs[$col] = $modelName::$cols[$col];
81
                }
82
            }
83
        }
84
        return $inputs;
85
    }
86
87
    public function checkRequest($params = [], $ajax = false)
2 ignored issues
show
Coding Style introduced by
checkRequest uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
checkRequest uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
88
    {
89 View Code Duplication
        if (!$this->checkAccess()) {
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...
90
            $this->drawError('you not have access to "' . $this->modelName . '" manager with name: "' . $this->formName . '"');
0 ignored issues
show
Documentation introduced by
'you not have access to .... $this->formName . '"' is of type string, but the function expects a object<Ui\text>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
91
            return [];
92
        }
93
        $modelName = $this->modelName;
0 ignored issues
show
Unused Code introduced by
$modelName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
94
        $successId = 0;
95
        if (!empty($_POST[$this->requestFormName][$this->modelName])) {
96
            $request = $_POST[$this->requestFormName][$this->modelName];
97
            if ($this->model) {
98
                $presets = !empty($this->form['preset']) ? $this->form['preset'] : [];
99 View Code Duplication
                if (!empty($this->form['userGroupPreset'][\Users\User::$cur->group_id])) {
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...
100
                    $presets = array_merge($presets, $this->form['userGroupPreset'][\Users\User::$cur->group_id]);
101
                }
102
                $afterSave = [];
103
                $error = false;
104
                foreach ($this->inputs as $col => $param) {
105
                    if (!empty($presets[$col])) {
106
                        continue;
107
                    }
108
                    if (is_object($param)) {
109
                        $afterSave[] = $param;
110
                        continue;
111
                    }
112 View Code Duplication
                    if (!empty($this->form['userGroupReadonly'][\Users\User::$cur->group_id]) && in_array($col, $this->form['userGroupReadonly'][\Users\User::$cur->group_id])) {
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...
113
                        continue;
114
                    }
115
                    $inputClassName = '\Ui\ActiveForm\Input\\' . ucfirst($param['type']);
116
                    $input = new $inputClassName();
117
                    $input->activeForm = $this;
118
                    $input->activeFormParams = $params;
119
                    $input->modelName = $this->modelName;
120
                    $input->colName = $col;
121
                    $input->colParams = $param;
122
                    try {
123
                        $input->validate($request);
124
                        $input->parseRequest($request);
125
                    } catch (\Exception $exc) {
126
                        \Msg::add($exc->getMessage(), 'danger');
127
                        $error = true;
128
                    }
129
                }
130
                if (!$error) {
131
                    foreach ($presets as $col => $preset) {
132
                        if (!empty($preset['value'])) {
133
                            $this->model->$col = $preset['value'];
134
                        } elseif (!empty($preset['userCol'])) {
135
                            if (strpos($preset['userCol'], ':')) {
136
                                $rel = substr($preset['userCol'], 0, strpos($preset['userCol'], ':'));
137
                                $param = substr($preset['userCol'], strpos($preset['userCol'], ':') + 1);
138
                                $this->model->$col = \Users\User::$cur->$rel->$param;
139
                            } else {
140
                                $this->model->$col = \Users\User::$cur->{$preset['userCol']};
141
                            }
142
                        }
143
                    }
144
                    if (!$this->parent) {
145
                        if (!empty($this->form['successText'])) {
146
                            $text = $this->form['successText'];
147
                        } else {
148
                            $text = $this->model->pk() ? 'Изменения были успешно сохранены' : 'Новый элемент был успешно добавлен';
149
                        }
150
                        \Msg::add($text, 'success');
151
                    }
152
153
                    $this->model->save(!empty($params['dataManagerParams']) ? $params['dataManagerParams'] : []);
154
                    foreach ($afterSave as $form) {
155
                        $form->checkRequest();
156
                    }
157
                    if ($ajax) {
158
                        \Msg::show();
159
                    } elseif (!empty($_GET['redirectUrl'])) {
160
                        \Tools::redirect($_GET['redirectUrl']);
161
                    }
162
                    $successId = $this->model->pk();
163
                }
164
            }
165
            if (!is_array($params) && is_callable($params)) {
166
                $params($request);
167
            }
168
        }
169
        return $successId;
170
    }
171
172
    public function draw($params = [], $ajax = false)
173
    {
174 View Code Duplication
        if (!$this->checkAccess()) {
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...
175
            $this->drawError('you not have access to "' . $this->modelName . '" form with name: "' . $this->formName . '"');
0 ignored issues
show
Documentation introduced by
'you not have access to .... $this->formName . '"' is of type string, but the function expects a object<Ui\text>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
176
            return [];
177
        }
178
        $form = new Form(!empty($this->form['formOptions']) ? $this->form['formOptions'] : []);
179
        \App::$cur->view->widget('Ui\ActiveForm', ['form' => $form, 'activeForm' => $this, 'ajax' => $ajax, 'params' => $params]);
180
    }
181
182
    public function drawCol($colName, $options, $form, $params = [])
183
    {
184
        $modelName = $this->modelName;
0 ignored issues
show
Unused Code introduced by
$modelName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
185
        if (is_object($options)) {
186
            $options->draw();
187
        } else {
188
            $inputClassName = '\Ui\ActiveForm\Input\\' . ucfirst($options['type']);
189
            $input = new $inputClassName();
190
            $input->form = $form;
191
            $input->activeForm = $this;
192
            $input->activeFormParams = $params;
193
            $input->modelName = $this->modelName;
194
            $input->colName = $colName;
195
            $input->colParams = $options;
196
            $input->draw();
197
        }
198
        return true;
199
    }
200
201
    public static function getOptionsList($inputParams, $params = [], $modelName = false, $aditionalInputNamePrefix = 'aditional', $options = [])
202
    {
203
        $values = [];
204
        switch ($inputParams['source']) {
205
            case 'model':
206
                $values = $inputParams['model']::getList(['forSelect' => true]);
207
                break;
208
            case 'array':
209
                $values = $inputParams['sourceArray'];
210
                break;
211
            case 'method':
212
                if (!empty($inputParams['params'])) {
213
                    $values = call_user_func_array([\App::$cur->$inputParams['module'], $inputParams['method']], $inputParams['params']);
214
                } else {
215
                    $values = \App::$cur->$inputParams['module']->$inputParams['method']();
216
                }
217
                break;
218
            case 'relation':
219
                if (!$modelName) {
220
                    return [];
221
                }
222
                $relation = $modelName::getRelation($inputParams['relation']);
223 View Code Duplication
                if (!empty($params['dataManagerParams']['appType'])) {
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...
224
                    $options['appType'] = $params['dataManagerParams']['appType'];
225
                }
226
                $items = [];
227
                if (class_exists($relation['model'])) {
228
                    $filters = $relation['model']::managerFilters();
229
                    if (!empty($filters['getRows']['where'])) {
230
                        $options['where'][] = $filters['getRows']['where'];
231
                    }
232
                    if (!empty($relation['order'])) {
233
                        $options['order'] = $relation['order'];
234
                    }
235
                    if (!empty($inputParams['itemName'])) {
236
                        $options['itemName'] = $inputParams['itemName'];
237
                    }
238
                    $items = $relation['model']::getList($options);
239
                }
240
                if (!empty($params['noEmptyValue'])) {
241
                    $values = [];
242
                } else {
243
                    $values = [0 => 'Не задано'];
244
                }
245
                foreach ($items as $key => $item) {
246
                    if (!empty($inputParams['showCol'])) {
247
                        if (is_array($inputParams['showCol'])) {
248
                            switch ($inputParams['showCol']['type']) {
249
                                case 'staticMethod':
250
                                    $values[$key] = $inputParams['showCol']['class']::{$inputParams['showCol']['method']}($item);
251
                                    break;
252
                            }
253
                        } else {
254
                            $values[$key] = $item->$inputParams['showCol'];
255
                        }
256
                    } else {
257
                        $values[$key] = $item->name();
258
                    }
259
                }
260
                break;
261
        }
262
        foreach ($values as $key => $value) {
263
            if (is_array($value) && !empty($value['input']) && empty($value['input']['noprefix'])) {
264
                $values[$key]['input']['name'] = $aditionalInputNamePrefix . "[{$value['input']['name']}]";
265
            }
266
        }
267
        return $values;
268
    }
269
270
    /**
271
     * Draw error message
272
     * 
273
     * @param text $errorText
274
     */
275
    public function drawError($errorText)
276
    {
277
        echo $errorText;
278
    }
279
280
    /**
281
     * Check access cur user to form with name in param and $model
282
     * 
283
     * @return boolean
284
     */
285
    public function checkAccess()
286
    {
287
        if (empty($this->form)) {
288
            $this->drawError('"' . $this->modelName . '" form with name: "' . $this->formName . '" not found');
0 ignored issues
show
Documentation introduced by
'"' . $this->modelName ....ormName . '" not found' is of type string, but the function expects a object<Ui\text>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
289
            return false;
290
        }
291
        if (!empty($this->form['options']['access']['apps']) && !in_array(\App::$cur->name, $this->form['options']['access']['apps'])) {
292
            return false;
293
        }
294
        if ($this->formName == 'manager' && !\Users\User::$cur->isAdmin()) {
295
            return false;
296
        }
297
        if ($this->model && !empty($this->form['options']['access']['self']) && \Users\User::$cur->id == $this->model->user_id) {
298
            return true;
299
        }
300 View Code Duplication
        if (!empty($this->form['options']['access']['groups']) && !in_array(\Users\User::$cur->group_id, $this->form['options']['access']['groups'])) {
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...
301
            return false;
302
        }
303
        return true;
304
    }
305
306
}
307