Passed
Branchfeature/useWidgetsNamespaces (54f503)
by Robin
04:17
created

AppCtrlCustomContainer::exportContainers()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 51
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 41
c 1
b 0
f 1
dl 0
loc 51
rs 8.9528
cc 5
nc 6
nop 2

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
// OVIDENTIA http://www.ovidentia.org
5
// Ovidentia is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 2, or (at your option)
8
// any later version.
9
//
10
// This program is distributed in the hope that it will be useful, but
11
// WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
// See the GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18
// USA.
19
// -------------------------------------------------------------------------
20
/**
21
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
22
 * @copyright Copyright (c) 2022 by SI4YOU ({@link https://www.siforyou.com})
23
 */
24
namespace Capwelton\LibApp\Ctrl;
25
26
use bab_charset;
27
use Capwelton\LibApp\Func_App;
28
use Capwelton\Widgets\Widgets\Form\WidgetForm;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Form\WidgetForm 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...
29
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...
30
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...
31
use Capwelton\LibApp\Ui\AppEditor;
32
use Capwelton\LibApp\Ui\Page\AppPage;
33
use Capwelton\LibApp\Set\AppRecordSet;
34
use Capwelton\LibApp\Set\AppCustomContainer;
35
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...
36
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...
37
use Capwelton\LibOrm\MySql\ORMOneRelation;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\MySql\ORMOneRelation 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...
38
39
/**
40
 * This controller manages actions that can be performed on custom sections
41
 *
42
 * @method Func_App App()
43
 * @method self proxy()
44
 */
45
class AppCtrlCustomContainer extends AppCtrlRecord
46
{
47
    
48
    /**
49
     * @param string $itemId
50
     * @return WidgetVBoxLayout
51
     */
52
    public function availableDisplayFields($section = null, $itemId = null)
53
    {
54
        $W = bab_Widgets();
55
        $App = $this->App();
56
        
57
        $customSectionSet = $App->CustomContainerSet();
58
        
59
        $customSection = $customSectionSet->request($customSectionSet->id->is($section));
60
        
61
        $object = $customSection->object;
62
        $objectCtrl = $App->Controller()->$object(false);
63
        
64
        $allViewSections = $customSectionSet->select($customSectionSet->view->is($customSection->view)
65
            ->_AND_($customSectionSet->object->is($customSection->object)));
66
        
67
        $allViewFieldNames = array();
68
        foreach ($allViewSections as $viewSection){
69
            $fields = $viewSection->getFields();
70
            foreach ($fields as $field){
71
                $allViewFieldNames[$field['fieldname']] = $viewSection->view . ',' . $viewSection->rank . ',' . $viewSection->id;
72
            }
73
        }
74
        
75
        $box = $W->VBoxItems();
76
        if(isset($itemId)){
77
            $box->setId($itemId);
78
        }
79
        
80
        $box->addItem($W->Link($App->translate('Create new field'), $App->Controller()
81
            ->CustomField()
82
            ->add($customSection->object))
0 ignored issues
show
Bug introduced by
The method add() does not exist on Capwelton\LibApp\Ctrl\AppController. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

82
            ->/** @scrutinizer ignore-call */ add($customSection->object))
Loading history...
83
            ->setOpenMode(WidgetLink::OPEN_DIALOG_AND_RELOAD)
84
            ->addClass('widget-actionbutton', 'icon', \Func_Icons::ACTIONS_LIST_ADD)
85
            ->setSizePolicy(\Func_Icons::ICON_LEFT_SYMBOLIC));
86
        
87
        $availableFields = $objectCtrl->getAvailableDisplayFields();
88
        
89
        \bab_Sort::asort($availableFields, 'description', \bab_Sort::CASE_INSENSITIVE);
90
        
91
        foreach ($availableFields as $field){
92
            $fieldName = $field['name'];
93
            $fieldDescription = $field['description'];
94
            
95
            $used = isset($allViewFieldNames[$fieldName]);
96
            $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

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

328
            ->validate(/** @scrutinizer ignore-type */ true)
Loading history...
329
            ->setAction($this->proxy()
0 ignored issues
show
Bug introduced by
$this->proxy()->save() 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

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

625
                ->/** @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...
626
            $menu->setSizePolicy(\Func_Icons::ICON_LEFT_16);
627
            
628
            $hasVisibilityBox = $W->FlowItems()->addClass('widget-100');
629
            if(! empty($customContainer->visibilityCriteria)){
630
                $hasVisibilityBox->addItem($W->HBoxItems($W->Label($App->translate('This container has a visibility condition')))
631
                    ->setSizePolicy('alert alert-warning widget-100pc'));
632
            }
633
            
634
            $containerBox = $W->VBoxItems($menu, $hasVisibilityBox, $customSectionCtrlNoProxy->sections($customContainer->id));
635
            
636
            $containerBoxes->addItem($containerBox->setSizePolicy($customContainer->sizePolicy)
637
                ->addClass($customContainer->classname));
638
        }
639
        
640
        if(isset($itemId)){
641
            $containerBoxes->setId($itemId);
642
        }
643
        
644
        $containerBoxes->setReloadAction($this->proxy()
645
            ->containers($object, $view, $containerBoxes->getId()));
646
        
647
        $containerBoxes->addClass('depends-custom-sections');
648
        
649
        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\Widgets\Form\WidgetForm.
Loading history...
650
    }
651
    
652
    /**
653
     * @param string $view
654
     */
655
    public function exportContainers($object, $view)
656
    {
657
        $App = $this->App();
658
        $customContainerSet = $App->CustomContainerSet();
659
        
660
        $customContainers = $customContainerSet->select($customContainerSet->view->is($view)
661
            ->_AND_($customContainerSet->object->is($object)));
662
        
663
        $customSectionSet = $App->CustomSectionSet();
664
        
665
        $containersValues = array();
666
        foreach ($customContainers as $customContainer){
667
            $values = $customContainer->getValues();
668
            unset($values['id']);
669
            unset($values['uuid']);
670
            unset($values['createdBy']);
671
            unset($values['createdOn']);
672
            unset($values['modifiedBy']);
673
            unset($values['modifiedOn']);
674
            unset($values['deletedBy']);
675
            unset($values['deletedOn']);
676
            unset($values['deleted']);
677
            $values['customSections'] = array();
678
            $customSections = $customSectionSet->select($customSectionSet->container->is($customContainer->id));
679
            foreach ($customSections as $customSection){
680
                $customSectionValues = $customSection->getValues();
681
                unset($customSectionValues['id']);
682
                unset($customSectionValues['uuid']);
683
                unset($customSectionValues['createdBy']);
684
                unset($customSectionValues['createdOn']);
685
                unset($customSectionValues['modifiedBy']);
686
                unset($customSectionValues['modifiedOn']);
687
                unset($customSectionValues['deletedBy']);
688
                unset($customSectionValues['deletedOn']);
689
                unset($customSectionValues['deleted']);
690
                unset($customSectionValues['container']);
691
                $customSectionValues['fields'] = $customSection->getFields();
692
                $values['customSections'][] = $customSectionValues;
693
            }
694
            $containersValues[] = $values;
695
        }
696
        
697
        header('Content-type: application/json');
698
        header('Content-Disposition: attachment; filename="' . $object . '.' . ($view === '' ? 'default' : $view) . '.json"' . "\n");
699
        if(bab_charset::getIso() != bab_charset::UTF_8){
700
            $containersValues = app_utf8Encode($containersValues);
701
        }
702
        $json = bab_json_encode($containersValues);
703
        $json = bab_convertStringFromDatabase($json, \bab_charset::UTF_8);
704
        
705
        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...
706
    }
707
    
708
    /**
709
     * @param string $view
710
     * @return AppPage
711
     */
712
    public function importContainersConfirm($object, $view = '')
713
    {
714
        $App = $this->App();
715
        $W = bab_Widgets();
716
        
717
        $page = $App->Ui()->Page();
718
        
719
        $page->setTitle($App->translate('Import containers layout'));
720
        
721
        $editor = new AppEditor($App);
722
        $editor->setHiddenValue('tg', $App->controllerTg);
723
        $editor->setHiddenValue('object', $object);
724
        $editor->isAjax = true;
725
        
726
        $editor->addItem($W->Label($App->translate('The existing view will be replaced'))
727
            ->setSizePolicy('alert alert-danger'));
728
        
729
        $editor->addItem($W->LabelledWidget($App->translate('View layout name'), $W->LineEdit()
730
            ->setValue($view), 'view'));
731
        
732
        $editor->addItem($W->LabelledWidget($App->translate('File'), $W->FilePicker(), 'containersfile'));
733
        
734
        $editor->setSaveAction($this->proxy()
735
            ->importContainers());
736
        
737
        $page->addItem($editor);
738
        
739
        return $page;
740
    }
741
    
742
    /**
743
     * @param string $view
744
     * @param string $containersfile
745
     * @return bool
746
     */
747
    public function importContainers($object = null, $view = null, $containersfile = null)
748
    {
749
        $this->requireSaveMethod();
750
        $App = $this->App();
751
        $W = bab_Widgets();
752
        
753
        $files = $W->FilePicker()->getFolder();
754
        $files->push('containersfile');
755
        $files->push($containersfile['uid']);
756
        
757
        $data = null;
758
        foreach ($files as $f){
759
            $data = file_get_contents($f->toString());
760
            break;
761
        }
762
        
763
        if(! isset($data)){
764
            $this->addError($App->translate('Unable to get file content'));
765
            return true;
766
        }
767
        
768
        $containersValues = json_decode($data, true);
769
        
770
        $App = $this->App();
771
        $customContainerSet = $App->CustomContainerSet();
772
        $customSectionSet = $App->CustomSectionSet();
773
        
774
        $customSectionSet->delete($customSectionSet->container->in($customContainerSet->view->is($view)
775
            ->_AND_($customContainerSet->object->is($object)), 'id'));
776
        $customContainerSet->delete($customContainerSet->view->is($view)
777
            ->_AND_($customContainerSet->object->is($object)));
778
        
779
        foreach ($containersValues as $containerValues){
780
            $customContainer = $customContainerSet->newRecord();
781
            $customContainer->setValues($containerValues);
782
            $customContainer->object = $object;
783
            $customContainer->view = $view;
784
            $customContainer->save();
785
            foreach ($containerValues['customSections'] as $sectionValues){
786
                $customSection = $customSectionSet->newRecord();
787
                $sectionValues['fields'] = json_encode($sectionValues['fields']);
788
                $customSection->setValues($sectionValues);
789
                $customSection->object = $object;
790
                $customSection->view = $view;
791
                $customSection->container = $customContainer->id;
792
                $customSection->save();
793
            }
794
        }
795
        
796
        $this->addReloadSelector('.depends-custom-sections');
797
        return true;
798
    }
799
    
800
    /**
801
     * @param string $view
802
     * @return bool
803
     */
804
    public function confirmDeleteContainers($object, $view)
805
    {
806
        $W = bab_Widgets();
807
        $App = $this->App();
808
        $Ui = $App->Ui();
809
        
810
        $page = $Ui->Page();
811
        
812
        $page->addClass('app-page-editor');
813
        $page->setTitle($App->translate('Delete view layout'));
814
        
815
        $form = new AppEditor($App);
816
        $form->setName('data');
817
        $form->isAjax = true;
818
        $form->setHiddenValue('tg', $App->controllerTg);
819
        $form->addItem($W->Title($App->translate('Confirm delete?'), 6));
820
        $form->addItem($W->Html(bab_toHtml($App->translate('It will not be possible to undo this deletion.'))));
821
        
822
        $confirmedAction = $this->proxy()->deleteContainers();
823
        $form->addItem($W->Hidden(null, 'object', $object));
824
        $form->addItem($W->Hidden(null, 'view', $view));
825
        $form->addButton($W->SubmitButton()
826
            ->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

826
            ->setAjaxAction(/** @scrutinizer ignore-type */ $confirmedAction)
Loading history...
827
            ->setLabel($App->translate('Delete')));
828
        $form->addButton($W->SubmitButton()
829
            ->setLabel($App->translate('Cancel'))
830
            ->addClass('widget-close-dialog'));
831
        $page->addItem($form);
832
        
833
        return $page;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $page returns the type Capwelton\LibApp\Ui\Page\AppPage which is incompatible with the documented return type boolean.
Loading history...
834
    }
835
    
836
    /**
837
     * @param string $view
838
     * @return bool
839
     */
840
    public function deleteContainers($data = null)
841
    {
842
        $this->requireDeleteMethod();
843
        $App = $this->App();
844
        $customContainerSet = $App->CustomContainerSet();
845
        $customSectionSet = $App->CustomSectionSet();
846
        
847
        $containerCriteria = array(
848
            $customContainerSet->view->is($data['view']),
849
            $customContainerSet->object->is($data['object'])
850
        );
851
        
852
        $customSectionSet->delete($customSectionSet->container->in($customContainerSet->all($containerCriteria), 'id'));
853
        
854
        $customContainerSet->delete($customContainerSet->all($containerCriteria));
855
        
856
        $this->addToast($App->translate('The view layout has been deleted'));
857
        $this->addReloadSelector('.depends-custom-sections');
858
        
859
        return true;
860
    }
861
    
862
    /**
863
     * Display an user interface to edit containers associated to a specific object.
864
     *
865
     * @param string $object
866
     * @param string $view
867
     * @return AppPage
868
     */
869
    public function editContainers($object, $view)
870
    {
871
        $App = $this->App();
872
        $W = bab_Widgets();
873
        $Ui = $App->Ui();
874
        
875
        $page = $Ui->Page();
876
        
877
        $page->setTitle(sprintf($App->translate('Edit view layout %s'), $view));
878
        
879
        $toolbar = $Ui->Toolbar();
880
        
881
        $toolbar->addItem($W->Link($App->translate('Delete view layout'), $this->proxy()
882
            ->confirmDeleteContainers($object, $view))
883
            ->addClass('widget-actionbutton', 'icon', \Func_Icons::ACTIONS_EDIT_DELETE)
884
            ->setOpenMode(WidgetLink::OPEN_DIALOG)
885
            ->setDialogClass('box red'));
886
        
887
        $toolbar->addItem($W->Link($App->translate('Export view layout'), $this->proxy()
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->proxy()->exportContainers($object, $view) targeting Capwelton\LibApp\Ctrl\Ap...ner::exportContainers() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
888
            ->exportContainers($object, $view))
889
            ->addClass('widget-actionbutton', 'icon', \Func_Icons::ACTIONS_DOCUMENT_UPLOAD));
890
        
891
        $toolbar->addItem($W->Link($App->translate('Import view layout'), $this->proxy()
892
            ->importContainersConfirm($object, $view))
893
            ->addClass('widget-actionbutton', 'icon', \Func_Icons::ACTIONS_DOCUMENT_DOWNLOAD)
894
            ->setOpenMode(WidgetLink::OPEN_DIALOG));
895
        
896
        $toolbar->addItem($W->Link($App->translate('Add a block'), $this->proxy()
897
            ->edit($view, null, $object))
898
            ->addClass('widget-actionbutton', 'icon', \Func_Icons::ACTIONS_LIST_ADD)
899
            ->setOpenMode(WidgetLink::OPEN_DIALOG));
900
        
901
        $form = $this->containers($object, $view);
902
        
903
        $page->addItem($toolbar);
904
        $page->addItem($form);
905
        
906
        return $page;
907
    }
908
    
909
    public function saveContainers($containers = null)
910
    {
911
        $App = $this->App();
912
        $customContainerSet = $App->CustomContainerSet();
913
        
914
        $containersFields = array();
915
        $containersRawFields = array();
916
        
917
        $rank = 0;
918
        $currentContainerId = 0;
919
        foreach (array_keys($containers) as $containerFieldId){
920
            
921
            if(substr($containerFieldId, 0, 1) === '#'){
922
                $currentContainerId = substr($containerFieldId, 1);
923
                
924
                $customContainer = $customContainerSet->request($customContainerSet->id->is($currentContainerId));
925
                
926
                $containersFields[$currentContainerId] = array();
927
                $containersRawFields[$currentContainerId] = $customContainer->getRawFields();
928
                
929
                $customContainer->rank = $rank;
930
                $rank ++;
931
                $customContainer->save();
932
                continue;
933
            }
934
            
935
            $containersFields[$currentContainerId][] = $containerFieldId;
936
        }
937
        
938
        foreach ($containersFields as $containerId => $containerFieldIds){
939
            foreach ($containerFieldIds as $containerFieldId){
940
                list ($srcContainerId, $srcfieldId) = explode('.', $containerFieldId);
941
                if(! isset($containersRawFields[$srcContainerId][$srcfieldId])){
942
                    return true;
943
                }
944
            }
945
        }
946
        
947
        foreach ($containersFields as $containerId => $containerFieldIds){
948
            $newRawFields = array();
949
            foreach ($containerFieldIds as $containerFieldId){
950
                list ($srcContainerId, $srcfieldId) = explode('.', $containerFieldId);
951
                $newRawFields[] = $containersRawFields[$srcContainerId][$srcfieldId];
952
            }
953
            
954
            $customContainer = $customContainerSet->request($customContainerSet->id->is($containerId));
955
            $customContainer->fields = implode(',', $newRawFields);
956
            $customContainer->save();
957
        }
958
        
959
        $this->addReloadSelector('.depends-custom-containers');
960
        
961
        return true;
962
    }
963
}
964