Passed
Branchdevelop81 (4a63ec)
by Robin
02:48
created

AppCtrlCustomContainer::containers()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 66
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 43
c 1
b 0
f 1
dl 0
loc 66
rs 8.9208
cc 5
nc 12
nop 3

How to fix   Long Method   

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
/************************************************************************
4
 * COFY https://www.siforyou.com                                         *
5
 ************************************************************************
6
 * Copyright (c) 2023 by Si-4You ( https://www.siforyou.com )            *
7
 *                                                                      *
8
 * This file is part of Cofy.                                           *
9
 *                                                                      *
10
 * Cofy is free software; you can redistribute it and/or modify         *
11
 * it under the terms of the GNU General Public License as published by *
12
 * the Free Software Foundation; either version 2, or (at your option)  *
13
 * any later version.                                                   *
14
 *                                                                      *
15
 * This program is distributed in the hope that it will be useful, but  *
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of           *
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
18
 * See the  GNU General Public License for more details.                *
19
 *                                                                      *
20
 * You should have received a copy of the GNU General Public License    *
21
 * along with this program; if not, write to the Free Software          *
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,*
23
 * USA.                                                                 *
24
 ************************************************************************/
25
/**
26
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
27
 * @copyright Copyright (c) 2023 by SI-4YOU ({@link https://www.siforyou.com})
28
 */
29
30
namespace Capwelton\LibApp\Ctrl;
31
32
use Capwelton\LibApp\FuncApp;
33
use Capwelton\Widgets\Widgets\Layout\WidgetVBoxLayout;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Layout\WidgetVBoxLayout was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use Capwelton\Widgets\Widgets\Item\WidgetLink;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Item\WidgetLink was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
use Capwelton\LibApp\Ui\Page\AppPage;
36
use Capwelton\LibApp\Set\AppCustomContainer;
37
use Capwelton\LibApp\Set\AppCustomContainerSet;
38
use Capwelton\LibOrm\ORMRecord;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\ORMRecord was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
39
use Capwelton\LibOrm\Interfaces\ORMBoolInterface;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\Interfaces\ORMBoolInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
use Capwelton\Widgets\Widgets\Helpers\WidgetAction;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Helpers\WidgetAction was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
41
use Capwelton\Widgets\Widgets\Layout\WidgetLayout;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Layout\WidgetLayout was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
42
use Cofy\Utilities\Addon\BabCharset;
0 ignored issues
show
Bug introduced by
The type Cofy\Utilities\Addon\BabCharset was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
43
use Cofy\Utilities\Addon\BabSort;
0 ignored issues
show
Bug introduced by
The type Cofy\Utilities\Addon\BabSort was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
44
use Cofy\Utilities\Func\Icons\FuncIcons;
0 ignored issues
show
Bug introduced by
The type Cofy\Utilities\Func\Icons\FuncIcons was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
45
46
use function Cofy\Utilities\Addon\bab_convertStringFromDatabase;
0 ignored issues
show
introduced by
The function Cofy\Utilities\Addon\bab_convertStringFromDatabase was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
47
use function Cofy\Utilities\Addon\bab_isAjaxRequest;
0 ignored issues
show
introduced by
The function Cofy\Utilities\Addon\bab_isAjaxRequest was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
48
use function Cofy\Utilities\Addon\bab_toHtml;
0 ignored issues
show
introduced by
The function Cofy\Utilities\Addon\bab_toHtml was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
49
use function Cofy\Utilities\Addon\bab_Widgets;
0 ignored issues
show
introduced by
The function Cofy\Utilities\Addon\bab_Widgets was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
50
use function Cofy\Utilities\bab_json_encode;
0 ignored issues
show
introduced by
The function Cofy\Utilities\bab_json_encode was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
51
52
/**
53
 * This controller manages actions that can be performed on custom sections
54
 *
55
 * @method FuncApp App()
56
 * @method self proxy()
57
 * @method AppCustomContainerSet getRecordSet()
58
 */
59
class AppCtrlCustomContainer extends AppCtrlRecord
60
{
61
62
    /**
63
     * @param string $section
64
     * @param string $itemId
65
     * @return WidgetVBoxLayout|WidgetAction
66
     */
67
    public function availableDisplayFields($section = null, $itemId = null)
68
    {
69
        $W = bab_Widgets();
70
        $App = $this->App();
71
72
        $customSectionSet = $App->CustomContainerSet();
73
74
        $customSection = $customSectionSet->request($customSectionSet->id->is($section));
75
76
        $object = $customSection->object;
77
        $objectCtrl = $App->Controller()->$object(false);
78
79
        $allViewSections = $customSectionSet->select(
80
            $customSectionSet->all(
81
                $customSectionSet->view->is($customSection->view),
82
                $customSectionSet->object->is($customSection->object)
83
            )
84
        );
85
86
        $allViewFieldNames = array();
87
        foreach ($allViewSections as $viewSection) {
88
            $fields = $viewSection->getFields();
89
            foreach ($fields as $field) {
90
                $allViewFieldNames[$field['fieldname']] = $viewSection->view . ',' . $viewSection->rank . ',' . $viewSection->id;
91
            }
92
        }
93
94
        $box = $W->VBoxLayout($itemId);
95
96
        $box->addItem($W->Link($App->translate('Create new field'), $App->Controller()
97
            ->CustomField()
98
            ->add($customSection->object))
99
            ->setOpenMode(WidgetLink::OPEN_DIALOG_AND_RELOAD)
100
            ->addClass('widget-actionbutton', 'icon', FuncIcons::ACTIONS_LIST_ADD)
101
            ->setSizePolicy(FuncIcons::ICON_LEFT_SYMBOLIC));
102
103
        $availableFields = $objectCtrl->getAvailableDisplayFields();
104
105
        BabSort::asort($availableFields, 'description', BabSort::CASE_INSENSITIVE);
106
107
        foreach ($availableFields as $field) {
108
            $fieldName = $field['name'];
109
            $fieldDescription = $field['description'];
110
111
            $used = isset($allViewFieldNames[$fieldName]);
112
            $box->addItem($W->VBoxItems($W->Link($fieldDescription, $this->proxy()
0 ignored issues
show
Bug introduced by
$this->proxy()->saveDisp...d($section, $fieldName) of type true is incompatible with the type Widget_Action|bab_url|string expected by parameter $url of Func_Widgets::Link(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
            $box->addItem($W->VBoxItems($W->Link($fieldDescription, /** @scrutinizer ignore-type */ $this->proxy()
Loading history...
113
                ->saveDisplayField($section, $fieldName))
0 ignored issues
show
Bug introduced by
It seems like $section can also be of type string; however, parameter $section of Capwelton\LibApp\Ctrl\Ap...ner::saveDisplayField() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

113
                ->saveDisplayField(/** @scrutinizer ignore-type */ $section, $fieldName))
Loading history...
114
                ->addClass('widget-close-dialog', ($used ? 'widget-strong' : ''))
115
                ->setTitle($fieldName)
116
                ->setAjaxAction(), $W->Hidden()
117
                ->setName(array(
118
                    'sections',
119
                    $field['name']
120
                )))
121
                ->setSizePolicy('widget-list-element'));
122
        }
123
124
        $box->addClass('widget-3columns');
125
126
        $box->setReloadAction($this->proxy()->availableDisplayFields($section, $box->getId()));
127
128
        return $box;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $box returns the type Widget_VBoxLayout which is incompatible with the documented return type Capwelton\Widgets\Widget...Layout\WidgetVBoxLayout.
Loading history...
129
    }
130
131
    /**
132
     * @return AppPage|WidgetAction
133
     */
134
    public function addDisplayField($section = null, $filter = null)
135
    {
136
        $App = $this->App();
137
138
        $page = $App->Ui()->Page();
139
        $page->setTitle($App->translate('Available fields'));
140
141
        $box = $this->availableDisplayFields($section);
142
143
        $page->addItem($box);
144
        return $page;
145
    }
146
147
    /**
148
     * @param int $section
149
     * @param string $fieldName
150
     * @return AppPage|WidgetAction
151
     */
152
    public function editDisplayField($section, $fieldName)
153
    {
154
        $App = $this->App();
155
        $customSectionSet = $App->CustomContainerSet();
156
157
        $customSection = $customSectionSet->request($customSectionSet->id->is($section));
158
159
        $field = $customSection->getField($fieldName);
160
161
        if (! isset($field)) {
162
            return null;
163
        }
164
165
        $W = bab_Widgets();
166
167
        $object = $customSection->object;
168
        $objectCtrl = $App->Controller()->$object(false);
169
170
        $fieldName = $field['fieldname'];
171
        $params = $field['parameters'];
172
173
        $availableFields = $objectCtrl->getAvailableDisplayFields();
174
175
        $field = $availableFields[$fieldName];
176
        $fieldDescription = $field['description'];
177
        if (substr($fieldName, 0, 1) !== '_') {
178
            $fieldDescription = $App->translate($fieldDescription);
179
        }
180
181
        $Ui = $App->Ui();
182
        $page = $Ui->Page();
183
        $page->setTitle($fieldDescription);
184
185
        $editor = $Ui->BasicEditor();
186
        $editor->setHiddenValue('section', $section);
187
        $editor->setHiddenValue('fieldName', $fieldName);
188
189
        $box = $W->VBoxItems($W->LabelledWidget($App->translate('Type'), $W->Select()
190
            ->setName(array(
191
                'parameters',
192
                'type'
193
            ))
194
            ->addOption('', '')
195
            ->addOption('title1', $App->translate('Title 1'))
196
            ->addOption('title2', $App->translate('Title 2'))
197
            ->addOption('title3', $App->translate('Title 3'))), $W->LabelledWidget($App->translate('Label'), $W->LineEdit()
198
            ->setName(array(
199
                'parameters',
200
                'label'
201
            ))), $W->LabelledWidget($App->translate('Class'), $W->LineEdit()
202
            ->setName(array(
203
                'parameters',
204
                'classname'
205
            ))), $W->LabelledWidget($App->translate('Size policy'), $W->LineEdit()
206
            ->setName(array(
207
                'parameters',
208
                'sizePolicy'
209
            ))))
210
            ->setVerticalSpacing(1, 'em');
211
212
        $editor->setValues($params, array(
213
            'parameters'
214
        ));
215
216
        $editor->addItem($box);
217
218
        $editor->setSaveAction($this->proxy()->saveDisplayField());
219
220
        $editor->isAjax = true;
221
222
        $page->addItem($editor);
223
224
        return $page;
225
    }
226
227
    /**
228
     * @param int $section
229
     * @param string $fieldName
230
     * @return bool|WidgetAction
231
     */
232
    public function saveDisplayField($section = null, $fieldName = null, $parameters = null)
233
    {
234
        $set = $this->getRecordSet();
235
        $record = $set->request($set->id->is($section));
236
        $record->removeField($fieldName);
237
        $record->addField($fieldName, $parameters);
238
        $record->save();
239
240
        $this->addReloadSelector('.depends-custom-sections');
241
242
        return true;
243
    }
244
245
    /**
246
     * @param int $section
247
     * @param string $fieldName
248
     * @return bool|WidgetAction
249
     */
250
    public function removeDisplayField($section, $fieldName)
251
    {
252
        $set = $this->getRecordSet();
253
        $record = $set->request($set->id->is($section));
254
        $record->removeField($fieldName);
255
        $record->save();
256
        $this->addReloadSelector('.depends-custom-sections');
257
        return true;
258
    }
259
260
    /**
261
     * @param string $view
262
     * @param int $id
263
     * @param string $object
264
     * @return AppPage|WidgetAction
265
     */
266
    public function editContainer($view, $id = null, $object = null)
267
    {
268
        $App = $this->App();
269
        $W = bab_Widgets();
270
271
        $customSectionSet = $this->getRecordSet();
272
        if (isset($id)) {
273
            $record = $customSectionSet->request($id);
274
        } else {
275
            $record = $customSectionSet->newRecord();
276
            $record->object = $object;
277
        }
278
279
        $Ui = $App->Ui();
280
        $page = $Ui->Page();
281
282
        $page->setTitle($App->translate('Container'));
283
        $page->addClass('app-page-editor');
284
285
        $editor = $Ui->BasicEditor();
286
        $editor->setHiddenValue('data[view]', $view);
287
        if ($record->id) {
288
            $editor->setHiddenValue('data[id]', $record->id);
289
        }
290
        $editor->setName('data');
291
        $editor->addItem($W->Hidden()
292
            ->setName('object'));
293
294
        $editor->addItem($W->LabelledWidget($App->translate('Name'), $W->LineEdit()
295
            ->setName('name')));
296
297
        $editor->addItem($W->LabelledWidget($App->translate('Element position'), $W->NumberEdit()
298
            ->setMin(0)
299
            ->setName('rank')));
300
301
        $sizePolicyClassnames = array(
302
            'col-md-1' => '1',
303
            'col-md-2' => '2',
304
            'col-md-3' => '3',
305
            'col-md-4' => '4',
306
            'col-md-5' => '5',
307
            'col-md-6' => '6',
308
            'col-md-7' => '7',
309
            'col-md-8' => '8',
310
            'col-md-9' => '9',
311
            'col-md-10' => '10',
312
            'col-md-11' => '11',
313
            'col-md-12' => '12',
314
            'left-panel' => 'left',
315
            'right-panel' => 'right'
316
        );
317
318
        $editor->addItem($W->LabelledWidget($App->translate('Size policy'), $W->Select()
319
            ->addOptions($sizePolicyClassnames)
320
            ->setName('sizePolicy')));
321
        $editor->addItem($W->LabelledWidget($App->translate('Layout'), $W->Select()
322
            ->addOptions(AppCustomContainer::getLayouts())
323
            ->setName('layout')));
324
325
        $editor->addItem($W->LabelledWidget($App->translate('Class'), $W->LineEdit()
326
            ->setName('classname')));
327
328
        $editor->setValues($record->getFormOutputValues(), array(
329
            'data'
330
        ));
331
332
        $saveAction = $this->proxy()->save();
333
334
        $editor->addButton($W->SubmitButton(/*'save'*/)
335
            ->validate(true)
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type integer expected by parameter $validate of Widget_SubmitButton::validate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

335
            ->validate(/** @scrutinizer ignore-type */ true)
Loading history...
336
            ->setAction($saveAction)
0 ignored issues
show
Bug introduced by
$saveAction of type true is incompatible with the type Widget_Action|null expected by parameter $action of Widget_SubmitButton::setAction(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

336
            ->setAction(/** @scrutinizer ignore-type */ $saveAction)
Loading history...
337
            ->setAjaxAction()
338
            ->setLabel($App->translate('Save')));
339
340
        $editor->addButton($W->SubmitButton(/*'cancel'*/)
341
            ->addClass('widget-close-dialog')
342
            ->setLabel($App->translate('Cancel')));
343
344
        $page->addItem($editor);
345
346
        return $page;
347
    }
348
349
    /**
350
     * @param int $id
351
     * @return AppPage|WidgetAction
352
     */
353
    public function editVisibility($id = null)
354
    {
355
        $App = $this->App();
356
        $Ui = $App->Ui();
357
358
        $page = $Ui->Page();
359
360
        $page->setTitle($App->translate('Section visibility'));
361
        $page->addClass('app-page-editor');
362
363
        $recordSet = $this->getRecordSet();
364
        $record = $recordSet->request($id);
365
366
        $object = $record->object;
367
        if (empty($object)) {
368
            $object = $record->container()->object;
369
        }
370
        if (strpos($object, $App->classPrefix) !== false) {
371
            $object = str_replace($App->classPrefix, '', $object);
372
        }
373
        $object .= 'Set';
374
375
        /* @var $objectRecordSet AppRecordSet */
376
        $objectRecordSet = $App->$object();
377
378
        $editor = $Ui->CriteriaEditor($objectRecordSet->all());
379
        $editor->setHiddenValue('data[id]', $record->id);
380
        $editor->setName('data');
381
382
        $manySets = $objectRecordSet->getHasManyRelations();
383
        $oneSets = $objectRecordSet->getHasOneRelations();
384
385
        if (! empty($record->visibilityCriteria)) {
386
            $arrCriteria = json_decode($record->visibilityCriteria, true);
387
388
            $data = array();
389
            foreach ($arrCriteria as $fieldName => $operation) {
390
                $data['field'] = $fieldName;
391
                foreach ($operation as $condition => $value) {
392
                    $data['condition']['default'] = $condition;
393
                    $data['condition']['bool'] = $condition;
394
                    if (is_array($value)) {
395
                        foreach ($value as $key => $subValue) {
396
                            foreach ($manySets as $manyFieldName => $manyRelation) {
397
                                if ($key . 'Set' == $manyRelation->getForeignSetClassName()) {
398
                                    foreach ($subValue as $subFieldName => $subConditions) {
399
                                        if ($subFieldName === '_foreignField') {
400
                                            continue;
401
                                        }
402
                                        $data['field'] = "{$manyFieldName}/{$subFieldName}";
403
                                        foreach ($subConditions as $subCondition => $subConditionValue) {
404
                                            $data['condition']['default'] = $subCondition;
405
                                            $data['condition']['bool'] = $subCondition;
406
                                            $value = $subConditionValue;
407
                                        }
408
                                    }
409
                                    break;
410
                                }
411
                            }
412
                            foreach ($oneSets as $oneFieldName => $oneRelation) {
413
                                if ($key . 'Set' == $oneRelation->getForeignSetClassName()) {
414
                                    foreach ($subValue as $subFieldName => $subConditions) {
415
                                        if ($subFieldName === '_foreignField') {
416
                                            continue;
417
                                        }
418
                                        $data['field'] = "{$oneFieldName}/{$subFieldName}";
419
                                        foreach ($subConditions as $subCondition => $subConditionValue) {
420
                                            $data['condition']['default'] = $subCondition;
421
                                            $data['condition']['bool'] = $subCondition;
422
                                            $value = $subConditionValue;
423
                                        }
424
                                    }
425
                                    break;
426
                                }
427
                            }
428
                        }
429
                    }
430
                    $data['value'] = $value;
431
                }
432
            }
433
434
            $editor->setValues($data, array(
435
                'data'
436
            ));
437
        }
438
439
        $editor->setSaveAction($this->proxy()->saveVisibility());
440
        $editor->isAjax = bab_isAjaxRequest();
441
442
        $page->addItem($editor);
443
444
        return $page;
445
    }
446
447
    /**
448
     * {@inheritdoc}
449
     * @see AppController::save()
450
     * @return bool|WidgetAction
451
     */
452
    public function save($data = null)
453
    {
454
        parent::save($data);
455
456
        $this->addReloadSelector('.depends-custom-sections');
457
458
        return true;
459
    }
460
461
    protected function preSave(ORMRecord  &$record, $data)
462
    {
463
        parent::preSave($record, $data);
464
        if (! isset($record->id) || empty($record->id)) {
465
            $set = $record->getParentSet();
466
            $nbContainers = $set->select(
467
                $set->all(
468
                    $set->object->is($record->object),
469
                    $set->view->is($record->view)
470
                )
471
            )->count();
472
            $record->rank = $nbContainers + 1;
473
        }
474
    }
475
476
    /**
477
     * {@inheritdoc}
478
     * @see AppCtrlRecord::delete()
479
     * @return bool|WidgetAction
480
     */
481
    public function delete($id)
482
    {
483
        parent::delete($id);
484
485
        $this->addReloadSelector('.depends-custom-sections');
486
487
        return true;
488
    }
489
490
    /**
491
     * @param array $data
492
     * @return bool|WidgetAction
493
     */
494
    public function saveVisibility($data = null)
495
    {
496
        $App = $this->App();
497
498
        $recordSet = $this->getRecordSet();
499
        $record = $recordSet->request($data['id']);
500
501
        $object = $record->object;
502
        if (empty($object)) {
503
            $object = $record->container()->object;
504
        }
505
        if (strpos($object, $App->classPrefix) !== false) {
506
            $object = str_replace($App->classPrefix, '', $object);
507
        }
508
        $object .= 'Set';
509
510
        /* @var $objectRecordSet AppRecordSet */
511
        $objectRecordSet = $App->$object();
512
513
        $field = $data['field'];
514
        $condition = $data['condition'];
515
516
        if (strpos($field, '/') !== false) {
517
            // The selected field is a hasMany or a hasOne relation
518
            list($selectedRelation, $selectedField) = explode('/', $field);
519
            $classPrefix = $App->classPrefix;
520
521
            $manyRelations = $objectRecordSet->getHasManyRelations();
522
            foreach ($manyRelations as $manyRelation) {
523
                if ($selectedRelation != $manyRelation->getOwnerSetFieldName()) {
524
                    continue;
525
                }
526
                $foreignSetName = str_replace($classPrefix, '', $manyRelation->getForeignSetClassName());
527
                $foreignSet = $App->$foreignSetName();
528
529
                $visibilityCriteria = '';
530
531
                if ($foreignSet) {
532
                    $selectedManyField = $foreignSet->$selectedField;
533
534
                    if ($selectedManyField instanceof ORMBoolInterface) {
535
                        $condition = $condition['bool'];
536
                    } else {
537
                        $condition = $condition['default'];
538
                    }
539
540
                    $criteria = $objectRecordSet->id->in($selectedManyField->{$condition}($data['value']), $manyRelation->getForeignFieldName());
541
542
                    $visibilityCriteria = $criteria->toJson();
543
                }
544
                break;
545
            }
546
547
            $oneRelations = $objectRecordSet->getHasOneRelations();
548
            foreach ($oneRelations as $oneRelation) {
549
                /* @var $oneRelation ORMOneRelation*/
550
                if ($selectedRelation != $oneRelation->getOwnerSetFieldName()) {
551
                    continue;
552
                }
553
                $foreignSetClassName = $oneRelation->getForeignSetClassName();
554
                $foreignSetName = str_replace($classPrefix, '', $foreignSetClassName);
555
                $foreignSet = $App->$foreignSetName();
556
557
                $visibilityCriteria = '';
558
559
                if ($foreignSet) {
560
                    $selectedOneField = $foreignSet->$selectedField;
561
562
                    if ($selectedOneField instanceof ORMBoolInterface) {
563
                        $condition = $condition['bool'];
564
                    } else {
565
                        $condition = $condition['default'];
566
                    }
567
568
                    $criteria = $objectRecordSet->$selectedRelation()->$selectedField->{$condition}($data['value']);
569
                    $visibilityCriteria = $criteria->toJson();
570
                }
571
                break;
572
            }
573
        } else {
574
575
            $field = $objectRecordSet->$field;
576
577
            if ($field instanceof ORMBoolInterface) {
578
                $condition = $condition['bool'];
579
            } else {
580
                $condition = $condition['default'];
581
            }
582
583
            $visibilityCriteria = '';
584
585
            if (! empty($condition)) {
586
                $criteria = $field->{$condition}($data['value']);
587
                $visibilityCriteria = $criteria->toJson();
588
            }
589
        }
590
591
        $record->visibilityCriteria = $visibilityCriteria;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $visibilityCriteria does not seem to be defined for all execution paths leading up to this point.
Loading history...
592
593
        $record->save();
594
595
        $this->addReloadSelector('.depends-custom-sections');
596
597
        return true;
598
    }
599
600
    /**
601
     * @param string $view
602
     * @param string $itemId
603
     * @return WidgetLayout|WidgetAction
604
     */
605
    public function containers($object, $view, $itemId = null)
606
    {
607
        $W = bab_Widgets();
608
        $App = $this->App();
609
610
        $customContainerCtrl = $App->Controller()->CustomContainer();
611
        $customSectionCtrlNoProxy = $App->Controller()->CustomSection(false);
612
        $customSectionCtrl = $customSectionCtrlNoProxy->proxy();
613
614
        $customContainerSet = $App->CustomContainerSet();
615
        $customContainers = $customContainerSet->select(
616
            $customContainerSet->all(
617
                $customContainerSet->object->is($object),
618
                $customContainerSet->view->is($view)
619
            )
620
        );
621
        $customContainers->orderAsc($customContainerSet->rank);
622
623
        $containerBoxes = $W->Items();
624
        if (isset($itemId)) {
625
            $containerBoxes->setId($itemId);
626
        }
627
628
        foreach ($customContainers as $customContainer) {
629
630
            $menu = $W->HBoxItems($W->Link('', $customSectionCtrl->edit($customContainer->id))
631
                ->addClass('icon', FuncIcons::ACTIONS_LIST_ADD)
632
                ->setOpenMode(WidgetLink::OPEN_DIALOG), $W->Link('', $customContainerCtrl->editContainer($view, $customContainer->id))
633
                ->addClass('icon', FuncIcons::ACTIONS_DOCUMENT_EDIT)
634
                ->setOpenMode(WidgetLink::OPEN_DIALOG), $W->Link('', $customContainerCtrl->editVisibility($customContainer->id))
635
                ->addClass('icon', FuncIcons::ACTIONS_SET_ACCESS_RIGHTS)
636
                ->setOpenMode(WidgetLink::OPEN_DIALOG), $W->Link('', $customContainerCtrl->confirmDelete($customContainer->id))
637
                ->addClass('icon', FuncIcons::ACTIONS_EDIT_DELETE)
638
                ->setOpenMode(WidgetLink::OPEN_DIALOG)
639
                ->setDialogClass('box red'));
0 ignored issues
show
Bug introduced by
The method setDialogClass() does not exist on Widget_Link. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

639
                ->/** @scrutinizer ignore-call */ setDialogClass('box red'));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
640
            $menu->setSizePolicy(FuncIcons::ICON_LEFT_16);
641
642
            $hasVisibilityBox = $W->FlowItems()->addClass('widget-100');
643
            if (! empty($customContainer->visibilityCriteria)) {
644
                $hasVisibilityBox->addItem(
645
                    $W->HBoxItems(
646
                        $W->Label($App->translate('This container has a visibility condition'))
647
                    )->setSizePolicy('alert alert-warning widget-100pc')
648
                );
649
            }
650
651
            $containerBox = $W->VBoxItems(
652
                $menu,
653
                $hasVisibilityBox,
654
                $customSectionCtrlNoProxy->sections($customContainer->id)
655
            );
656
657
            $containerBoxes->addItem(
658
                $containerBox->setSizePolicy($customContainer->sizePolicy)->addClass($customContainer->classname)
659
            );
660
        }
661
662
        if (isset($itemId)) {
663
            $containerBoxes->setId($itemId);
664
        }
665
666
        $containerBoxes->setReloadAction($this->proxy()->containers($object, $view, $containerBoxes->getId()));
667
668
        $containerBoxes->addClass('depends-custom-sections');
669
670
        return $containerBoxes;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $containerBoxes returns the type Widget_Layout which is incompatible with the documented return type Capwelton\Widgets\Widget...ets\Layout\WidgetLayout.
Loading history...
671
    }
672
673
    /**
674
     * @param string $view
675
     * @return WidgetAction
676
     */
677
    public function exportContainers($object, $view)
678
    {
679
        $App = $this->App();
680
        $customContainerSet = $this->getRecordSet();
681
682
        $customContainers = $customContainerSet->select(
683
            $customContainerSet->all(
684
                $customContainerSet->view->is($view),
685
                $customContainerSet->object->is($object)
686
            )
687
        );
688
689
        $customSectionSet = $App->CustomSectionSet();
690
691
        $containersValues = array();
692
        foreach ($customContainers as $customContainer) {
693
            $values = $customContainer->getValues();
694
            unset($values['id']);
695
            unset($values['uuid']);
696
            unset($values['createdBy']);
697
            unset($values['createdOn']);
698
            unset($values['modifiedBy']);
699
            unset($values['modifiedOn']);
700
            unset($values['deletedBy']);
701
            unset($values['deletedOn']);
702
            unset($values['deleted']);
703
            $values['customSections'] = array();
704
            $customSections = $customSectionSet->select($customSectionSet->container->is($customContainer->id));
705
            foreach ($customSections as $customSection) {
706
                $customSectionValues = $customSection->getValues();
707
                unset($customSectionValues['id']);
708
                unset($customSectionValues['uuid']);
709
                unset($customSectionValues['createdBy']);
710
                unset($customSectionValues['createdOn']);
711
                unset($customSectionValues['modifiedBy']);
712
                unset($customSectionValues['modifiedOn']);
713
                unset($customSectionValues['deletedBy']);
714
                unset($customSectionValues['deletedOn']);
715
                unset($customSectionValues['deleted']);
716
                unset($customSectionValues['container']);
717
                $customSectionValues['fields'] = $customSection->getFields();
718
                $values['customSections'][] = $customSectionValues;
719
            }
720
            $containersValues[] = $values;
721
        }
722
723
        header('Content-type: application/json');
724
        header('Content-Disposition: attachment; filename="' . $object . '.' . ($view === '' ? 'default' : $view) . '.json"' . "\n");
725
        if (BabCharset::getIso() != BabCharset::UTF_8) {
726
            $containersValues = app_utf8Encode($containersValues);
727
        }
728
        $json = bab_json_encode($containersValues);
729
        $json = bab_convertStringFromDatabase($json, BabCharset::UTF_8);
730
731
        die($json);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
732
    }
733
734
    /**
735
     * @param string $view
736
     * @return AppPage|WidgetAction
737
     */
738
    public function importContainersConfirm($object, $view = '')
739
    {
740
        $App = $this->App();
741
        $Ui = $App->Ui();
742
        $W = bab_Widgets();
743
744
        $page = $Ui->Page();
745
746
        $page->setTitle($App->translate('Import containers layout'));
747
748
        $editor = $Ui->BasicEditor();
749
        $editor->setHiddenValue('object', $object);
750
        $editor->isAjax = true;
751
752
        $editor->addItem(
753
            $W->Label($App->translate('The existing view will be replaced'))->setSizePolicy('alert alert-danger')
754
        );
755
756
        $editor->addItem(
757
            $W->LabelledWidget(
758
                $App->translate('View layout name'),
759
                $W->LineEdit()->setValue($view),
760
                'view'
761
            )
762
        );
763
764
        $editor->addItem(
765
            $W->LabelledWidget(
766
                $App->translate('File'),
767
                $W->FilePicker(),
768
                'containersfile'
769
            )
770
        );
771
772
        $editor->setSaveAction($this->proxy()->importContainers());
773
774
        $page->addItem($editor);
775
776
        return $page;
777
    }
778
779
    /**
780
     * @param string $view
781
     * @param string $containersfile
782
     * @return bool|WidgetAction
783
     */
784
    public function importContainers($object = null, $view = null, $containersfile = null)
785
    {
786
        $this->requireSaveMethod();
787
        $App = $this->App();
788
        $W = bab_Widgets();
789
790
        $files = $W->FilePicker()->getFolder();
791
        $files->push('containersfile');
792
        $files->push($containersfile['uid']);
793
794
        $data = null;
795
        foreach ($files as $f) {
796
            $data = file_get_contents($f->toString());
797
            break;
798
        }
799
800
        if (! isset($data)) {
801
            $this->addError($App->translate('Unable to get file content'));
802
            return true;
803
        }
804
805
        $containersValues = json_decode($data, true);
806
807
        $customContainerSet = $App->CustomContainerSet();
808
        $customSectionSet = $App->CustomSectionSet();
809
810
        $customSectionSet->delete(
811
            $customSectionSet->container->in(
812
                $customSectionSet->all(
813
                    $customContainerSet->view->is($view),
814
                    $customContainerSet->object->is($object)
815
                ),
816
                'id'
817
            )
818
        );
819
        $customContainerSet->delete(
820
            $customContainerSet->all(
821
                $customContainerSet->view->is($view),
822
                $customContainerSet->object->is($object)
823
            )
824
        );
825
826
        foreach ($containersValues as $containerValues) {
827
            $customContainer = $customContainerSet->newRecord();
828
            $customContainer->setValues($containerValues);
829
            $customContainer->object = $object;
830
            $customContainer->view = $view;
831
            $customContainer->save();
832
            foreach ($containerValues['customSections'] as $sectionValues) {
833
                $customSection = $customSectionSet->newRecord();
834
                $sectionValues['fields'] = json_encode($sectionValues['fields']);
835
                $customSection->setValues($sectionValues);
836
                $customSection->object = $object;
837
                $customSection->view = $view;
838
                $customSection->container = $customContainer->id;
839
                $customSection->save();
840
            }
841
        }
842
843
        $this->addReloadSelector('.depends-custom-sections');
844
        return true;
845
    }
846
847
    /**
848
     * @param string $view
849
     * @return AppPage|WidgetAction
850
     */
851
    public function confirmDeleteContainers($object, $view)
852
    {
853
        $W = bab_Widgets();
854
        $App = $this->App();
855
        $Ui = $App->Ui();
856
857
        $page = $Ui->Page();
858
859
        $page->addClass('app-page-editor');
860
        $page->setTitle($App->translate('Delete view layout'));
861
862
        $form = $Ui->BasicEditor();
863
        $form->setName('data');
864
        $form->isAjax = true;
865
        $form->addItem($W->Title($App->translate('Confirm delete?'), 6));
866
        $form->addItem($W->Html(bab_toHtml($App->translate('It will not be possible to undo this deletion.'))));
867
868
        $confirmedAction = $this->proxy()->deleteContainers();
869
        $form->addItem($W->Hidden(null, 'object', $object));
870
        $form->addItem($W->Hidden(null, 'view', $view));
871
        $form->addButton($W->SubmitButton()
872
            ->setAjaxAction($confirmedAction)
0 ignored issues
show
Bug introduced by
$confirmedAction of type true is incompatible with the type Widget_Action|null expected by parameter $action of Widget_Widget::setAjaxAction(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

872
            ->setAjaxAction(/** @scrutinizer ignore-type */ $confirmedAction)
Loading history...
873
            ->setLabel($App->translate('Delete')));
874
        $form->addButton($W->SubmitButton()
875
            ->setLabel($App->translate('Cancel'))
876
            ->addClass('widget-close-dialog'));
877
        $page->addItem($form);
878
879
        return $page;
880
    }
881
882
    /**
883
     * @param string $view
884
     * @return bool|WidgetAction
885
     */
886
    public function deleteContainers($data = null)
887
    {
888
        $this->requireDeleteMethod();
889
        $App = $this->App();
890
        $customContainerSet = $App->CustomContainerSet();
891
        $customSectionSet = $App->CustomSectionSet();
892
893
        $containerCriteria = array(
894
            $customContainerSet->view->is($data['view']),
895
            $customContainerSet->object->is($data['object'])
896
        );
897
898
        $customSectionSet->delete($customSectionSet->container->in($customContainerSet->all($containerCriteria), 'id'));
899
900
        $customContainerSet->delete($customContainerSet->all($containerCriteria));
901
902
        $this->addToast($App->translate('The view layout has been deleted'));
903
        $this->addReloadSelector('.depends-custom-sections');
904
905
        return true;
906
    }
907
908
    /**
909
     * Display an user interface to edit containers associated to a specific object.
910
     *
911
     * @param string $object
912
     * @param string $view
913
     * @return AppPage|WidgetAction
914
     */
915
    public function editContainers($object, $view)
916
    {
917
        $App = $this->App();
918
        $W = bab_Widgets();
919
        $Ui = $App->Ui();
920
921
        $page = $Ui->Page();
922
923
        $page->setTitle(sprintf($App->translate('Edit view layout %s'), $view));
924
925
        $toolbar = $Ui->Toolbar();
926
927
        $toolbar->addItem($W->Link($App->translate('Delete view layout'), $this->proxy()
928
            ->confirmDeleteContainers($object, $view))
929
            ->addClass('widget-actionbutton', 'icon', FuncIcons::ACTIONS_EDIT_DELETE)
930
            ->setOpenMode(WidgetLink::OPEN_DIALOG)
931
            ->setDialogClass('box red'));
932
933
        $toolbar->addItem($W->Link($App->translate('Export view layout'), $this->proxy()
934
            ->exportContainers($object, $view))
935
            ->addClass('widget-actionbutton', 'icon', FuncIcons::ACTIONS_DOCUMENT_UPLOAD));
936
937
        $toolbar->addItem($W->Link($App->translate('Import view layout'), $this->proxy()
938
            ->importContainersConfirm($object, $view))
939
            ->addClass('widget-actionbutton', 'icon', FuncIcons::ACTIONS_DOCUMENT_DOWNLOAD)
940
            ->setOpenMode(WidgetLink::OPEN_DIALOG));
941
942
        $toolbar->addItem($W->Link($App->translate('Add a block'), $this->proxy()
943
            ->editContainer($view, null, $object))
944
            ->addClass('widget-actionbutton', 'icon', FuncIcons::ACTIONS_LIST_ADD)
945
            ->setOpenMode(WidgetLink::OPEN_DIALOG));
946
947
        $form = $this->containers($object, $view);
948
949
        $page->addItem($toolbar);
950
        $page->addItem($form);
951
952
        return $page;
953
    }
954
955
    /**
956
     * @return bool|WidgetAction
957
     */
958
    public function saveContainers($containers = null)
959
    {
960
        $customContainerSet = $this->getRecordSet();
961
962
        $containersFields = array();
963
        $containersRawFields = array();
964
965
        $rank = 0;
966
        $currentContainerId = 0;
967
        foreach (array_keys($containers) as $containerFieldId) {
968
969
            if (substr($containerFieldId, 0, 1) === '#') {
970
                $currentContainerId = substr($containerFieldId, 1);
971
972
                $customContainer = $customContainerSet->request($customContainerSet->id->is($currentContainerId));
973
974
                $containersFields[$currentContainerId] = array();
975
                $containersRawFields[$currentContainerId] = $customContainer->getRawFields();
976
977
                $customContainer->rank = $rank;
978
                $rank++;
979
                $customContainer->save();
980
                continue;
981
            }
982
983
            $containersFields[$currentContainerId][] = $containerFieldId;
984
        }
985
986
        foreach ($containersFields as $containerId => $containerFieldIds) {
987
            foreach ($containerFieldIds as $containerFieldId) {
988
                list($srcContainerId, $srcfieldId) = explode('.', $containerFieldId);
989
                if (! isset($containersRawFields[$srcContainerId][$srcfieldId])) {
990
                    return true;
991
                }
992
            }
993
        }
994
995
        foreach ($containersFields as $containerId => $containerFieldIds) {
996
            $newRawFields = array();
997
            foreach ($containerFieldIds as $containerFieldId) {
998
                list($srcContainerId, $srcfieldId) = explode('.', $containerFieldId);
999
                $newRawFields[] = $containersRawFields[$srcContainerId][$srcfieldId];
1000
            }
1001
1002
            $customContainer = $customContainerSet->request($customContainerSet->id->is($containerId));
1003
            $customContainer->fields = implode(',', $newRawFields);
1004
            $customContainer->save();
1005
        }
1006
1007
        $this->addReloadSelector('.depends-custom-containers');
1008
1009
        return true;
1010
    }
1011
}
1012