Completed
Push — master ( f81666...55a9f3 )
by Alexey
05:42
created

ActiveForm::drawCol()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 17
rs 9.4285
cc 2
eloc 14
nc 2
nop 4
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
    /**
28
     * 
29
     * @param array|\Model $model
30
     * @param array|string $form
31
     */
32
    public function __construct($model, $form = '')
33
    {
34
        if (is_array($model)) {
35
            $this->form = $model;
36
            if (is_string($form)) {
37
                $this->formName = $form;
38
            }
39
        } else {
40
            $this->model = $model;
41
            $this->modelName = get_class($model);
42
            if (is_array($form)) {
43
                if (empty($form)) {
44
                    throw new \Exception('empty form');
45
                }
46
                $this->form = $form;
47
            } else {
48
                $this->formName = $form;
49
                $this->form = \App::$cur->ui->getModelForm($this->modelName, $form);
50
                if (empty($this->form)) {
51
                    throw new \Exception('empty form');
52
                }
53
                $this->inputs = $this->getInputs();
54
            }
55
        }
56
        $this->requestFormName = "ActiveForm_{$this->formName}";
57
        $modeName = $this->modelName;
58
59
        if (!empty($this->form['name'])) {
60
            $this->header = $this->form['name'];
61
        } elseif (!empty($modeName::$objectName)) {
62
            $this->header = $modeName::$objectName;
63
        } else {
64
            $this->header = $this->modelName;
65
        }
66
    }
67
68
    public function getInputs()
69
    {
70
        $inputs = !empty($this->form['inputs']) ? $this->form['inputs'] : [];
71
        $modelName = $this->modelName;
72
        foreach ($this->form['map'] as $row) {
73
            foreach ($row as $col) {
74
                if (!$col || !empty($inputs[$col])) {
75
                    continue;
76
                }
77
                if (strpos($col, 'form:') === 0) {
78
                    $colPath = explode(':', $col);
79
                    if ($this->model->{$colPath[1]}) {
80
                        $inputs[$col] = new ActiveForm($this->model->{$colPath[1]}, $colPath[2]);
81
                    } else {
82
                        $relOptions = $modelName::getRelation($colPath[1]);
83
                        if (!isset($this->model->_params[$modelName::index()])) {
84
                            $this->model->_params[$modelName::index()] = 0;
85
                        }
86
                        $relOptions['model']::fixPrefix($relOptions['col']);
87
                        $inputs[$col] = new ActiveForm(new $relOptions['model']([ $relOptions['col'] => &$this->model->_params[$modelName::index()]]), $colPath[2]);
88
                    }
89
                    $inputs[$col]->parent = $this;
90
                } elseif (!empty($modelName::$cols[$col])) {
91
                    $inputs[$col] = $modelName::$cols[$col];
92
                }
93
            }
94
        }
95
        return $inputs;
96
    }
97
98
    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...
99
    {
100 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...
101
            $this->drawError('you not have access to "' . $this->modelName . '" manager with name: "' . $this->formName . '"');
102
            return [];
103
        }
104
        $successId = 0;
105
        if (!empty($_POST[$this->requestFormName][$this->modelName])) {
106
            $request = $_POST[$this->requestFormName][$this->modelName];
107
            if ($this->model) {
108
                $presets = !empty($this->form['preset']) ? $this->form['preset'] : [];
109 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...
110
                    $presets = array_merge($presets, $this->form['userGroupPreset'][\Users\User::$cur->group_id]);
111
                }
112
                $afterSave = [];
113
                $error = false;
114
                foreach ($this->inputs as $col => $param) {
115
                    if (!empty($presets[$col])) {
116
                        continue;
117
                    }
118
                    if (is_object($param)) {
119
                        $afterSave[] = $param;
120
                        continue;
121
                    }
122 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...
123
                        continue;
124
                    }
125
                    $inputClassName = '\Ui\ActiveForm\Input\\' . ucfirst($param['type']);
126
                    $input = new $inputClassName();
127
                    $input->activeForm = $this;
128
                    $input->activeFormParams = $params;
129
                    $input->modelName = $this->modelName;
130
                    $input->colName = $col;
131
                    $input->colParams = $param;
132
                    try {
133
                        $input->validate($request);
134
                        $input->parseRequest($request);
135
                    } catch (\Exception $exc) {
136
                        \Msg::add($exc->getMessage(), 'danger');
137
                        $error = true;
138
                    }
139
                }
140
                if (!$error) {
141
                    foreach ($presets as $col => $preset) {
142
                        if (!empty($preset['value'])) {
143
                            $this->model->$col = $preset['value'];
144
                        } elseif (!empty($preset['userCol'])) {
145
                            if (strpos($preset['userCol'], ':')) {
146
                                $rel = substr($preset['userCol'], 0, strpos($preset['userCol'], ':'));
147
                                $param = substr($preset['userCol'], strpos($preset['userCol'], ':') + 1);
148
                                $this->model->$col = \Users\User::$cur->$rel->$param;
149
                            } else {
150
                                $this->model->$col = \Users\User::$cur->{$preset['userCol']};
151
                            }
152
                        }
153
                    }
154
                    if (!$this->parent) {
155
                        if (!empty($this->form['successText'])) {
156
                            $text = $this->form['successText'];
157
                        } else {
158
                            $text = $this->model->pk() ? 'Изменения были успешно сохранены' : 'Новый элемент был успешно добавлен';
159
                        }
160
                        \Msg::add($text, 'success');
161
                    }
162
163
                    $this->model->save(!empty($params['dataManagerParams']) ? $params['dataManagerParams'] : []);
164
                    foreach ($afterSave as $form) {
165
                        $form->checkRequest();
166
                    }
167
                    if ($ajax) {
168
                        \Msg::show();
169
                    } elseif (!empty($_GET['redirectUrl'])) {
170
                        \Tools::redirect($_GET['redirectUrl']);
171
                    }
172
                    $successId = $this->model->pk();
173
                }
174
            }
175
            if (!is_array($params) && is_callable($params)) {
176
                $params($request);
177
            }
178
        }
179
        return $successId;
180
    }
181
182
    public function draw($params = [], $ajax = false)
183
    {
184 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...
185
            $this->drawError('you not have access to "' . $this->modelName . '" form with name: "' . $this->formName . '"');
186
            return [];
187
        }
188
        $form = new Form(!empty($this->form['formOptions']) ? $this->form['formOptions'] : []);
189
        \App::$cur->view->widget('Ui\ActiveForm', ['form' => $form, 'activeForm' => $this, 'ajax' => $ajax, 'params' => $params]);
190
    }
191
192
    public function drawCol($colName, $options, $form, $params = [])
193
    {
194
        if (is_object($options)) {
195
            $options->draw();
196
        } else {
197
            $inputClassName = '\Ui\ActiveForm\Input\\' . ucfirst($options['type']);
198
            $input = new $inputClassName();
199
            $input->form = $form;
200
            $input->activeForm = $this;
201
            $input->activeFormParams = $params;
202
            $input->modelName = $this->modelName;
203
            $input->colName = $colName;
204
            $input->colParams = $options;
205
            $input->draw();
206
        }
207
        return true;
208
    }
209
210
    public static function getOptionsList($inputParams, $params = [], $modelName = '', $aditionalInputNamePrefix = 'aditional', $options = [])
211
    {
212
        $values = [];
213
        switch ($inputParams['source']) {
214
            case 'model':
215
                $values = $inputParams['model']::getList(['forSelect' => true]);
216
                break;
217
            case 'array':
218
                $values = $inputParams['sourceArray'];
219
                break;
220
            case 'method':
221
                if (!empty($inputParams['params'])) {
222
                    $values = call_user_func_array([\App::$cur->$inputParams['module'], $inputParams['method']], $inputParams['params']);
223
                } else {
224
                    $values = \App::$cur->$inputParams['module']->$inputParams['method']();
225
                }
226
                break;
227
            case 'relation':
228
                if (!$modelName) {
229
                    return [];
230
                }
231
                $relation = $modelName::getRelation($inputParams['relation']);
232 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...
233
                    $options['appType'] = $params['dataManagerParams']['appType'];
234
                }
235
                $items = [];
236
                if (class_exists($relation['model'])) {
237
                    $filters = $relation['model']::managerFilters();
238
                    if (!empty($filters['getRows']['where'])) {
239
                        $options['where'][] = $filters['getRows']['where'];
240
                    }
241
                    if (!empty($relation['order'])) {
242
                        $options['order'] = $relation['order'];
243
                    }
244
                    if (!empty($inputParams['itemName'])) {
245
                        $options['itemName'] = $inputParams['itemName'];
246
                    }
247
                    $items = $relation['model']::getList($options);
248
                }
249
                if (!empty($params['noEmptyValue'])) {
250
                    $values = [];
251
                } else {
252
                    $values = [0 => 'Не задано'];
253
                }
254
                foreach ($items as $key => $item) {
255
                    if (!empty($inputParams['showCol'])) {
256
                        if (is_array($inputParams['showCol'])) {
257
                            switch ($inputParams['showCol']['type']) {
258
                                case 'staticMethod':
259
                                    $values[$key] = $inputParams['showCol']['class']::{$inputParams['showCol']['method']}($item);
260
                                    break;
261
                            }
262
                        } else {
263
                            $values[$key] = $item->$inputParams['showCol'];
264
                        }
265
                    } else {
266
                        $values[$key] = $item->name();
267
                    }
268
                }
269
                break;
270
        }
271
        foreach ($values as $key => $value) {
272
            if (is_array($value) && !empty($value['input']) && empty($value['input']['noprefix'])) {
273
                $values[$key]['input']['name'] = $aditionalInputNamePrefix . "[{$value['input']['name']}]";
274
            }
275
        }
276
        return $values;
277
    }
278
279
    /**
280
     * Draw error message
281
     * 
282
     * @param string $errorText
283
     */
284
    public function drawError($errorText)
285
    {
286
        echo $errorText;
287
    }
288
289
    /**
290
     * Check access cur user to form with name in param and $model
291
     * 
292
     * @return boolean
293
     */
294
    public function checkAccess()
295
    {
296
        if (empty($this->form)) {
297
            $this->drawError('"' . $this->modelName . '" form with name: "' . $this->formName . '" not found');
298
            return false;
299
        }
300
        if (!empty($this->form['options']['access']['apps']) && !in_array(\App::$cur->name, $this->form['options']['access']['apps'])) {
301
            return false;
302
        }
303
        if ($this->formName == 'manager' && !\Users\User::$cur->isAdmin()) {
304
            return false;
305
        }
306
        if ($this->model && !empty($this->form['options']['access']['self']) && \Users\User::$cur->id == $this->model->user_id) {
307
            return true;
308
        }
309 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...
310
            return false;
311
        }
312
        return true;
313
    }
314
315
}
316