Passed
Pull Request — master ( #1 )
by Robin
02:24
created

app_TableModelView   F

Complexity

Total Complexity 63

Size/Duplication

Total Lines 589
Duplicated Lines 0 %

Importance

Changes 10
Bugs 3 Features 0
Metric Value
eloc 265
c 10
b 3
f 0
dl 0
loc 589
rs 3.36
wmc 63

15 Methods

Rating   Name   Duplication   Size   Complexity  
A setApp() 0 4 1
A isFilterFieldSpecified() 0 20 6
A handleFilterLabel() 0 13 2
A getSearchItem() 0 5 1
C getAdvancedFilterForm() 0 210 13
C advancedFilterPanel() 0 59 11
A handleAdvancedFilterFields() 0 2 1
A getRecordControllerProxy() 0 6 2
A __construct() 0 4 1
A App() 0 13 3
A addCustomFields() 0 12 2
A getRecordController() 0 3 1
B handleFilterInputWidget() 0 39 6
C filterPanel() 0 58 12
A setRecordController() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like app_TableModelView often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use app_TableModelView, and based on these observations, apply Extract Interface, too.

1
<?php
2
//-------------------------------------------------------------------------
3
// OVIDENTIA http://www.ovidentia.org
4
// Ovidentia is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 2, or (at your option)
7
// any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
// See the GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17
// USA.
18
//-------------------------------------------------------------------------
19
/**
20
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
21
 * @copyright Copyright (c) 2009 by CANTICO ({@link http://www.cantico.fr})
22
 */
23
24
bab_Widgets()->includePhpClass('widget_Form');
25
bab_Widgets()->includePhpClass('widget_Frame');
26
bab_Widgets()->includePhpClass('widget_InputWidget');
27
bab_Widgets()->includePhpClass('widget_TableModelView');
28
29
require_once dirname(__FILE__) . '/ui.helpers.php';
30
31
/**
32
 * @return Widget_Form
33
 *
34
 *
35
 * @method self     setReadOnly($flag = true)
36
 * @method boolean  isReadOnly()
37
 * @method boolean  getReadOnly()
38
 * @method self     colon($colon = true)
39
 * @method boolean  isColon()
40
 * @method self     setHiddenValue($name, $value)
41
 * @method string   getHiddenValue($name)
42
 * @method array    getHiddenFields()
43
 * @method self     setHiddenValues($basename, $values)
44
 * @method Widget_InputWidget[] getFields($parent = null)
45
 * @method mixed    getValue($namePath)
46
 * @method self     setValue($namePath, $value)
47
 * @method self     setValues($row, $namePathBase = array())
48
 * @method array    getValues()
49
 * @method self     setAnchor($anchorname)
50
 * @method self     setSelfPageHiddenFields()
51
 * @method boolean  testMandatory()
52
 * @method self     checkUnsaved($check, $unsavedMessage)
53
 * @method self     setValidateAction(Widget_Action $action = null)
54
 * @method array    getClasses()
55
 * @method array    getFullName()
56
 * @method string   getName()
57
 * @method string   display(Widget_Canvas $canvas)
58
 * @method self     addClass($className)
59
 */
60
class app_Editor extends app_UiObject
61
{
62
    /**
63
     * @var Widget_Form $item
64
     */
65
    protected $item = null;
66
67
    /**
68
     * @var app_Record
69
     */
70
    protected $record;
71
72
    protected $ctrl;
73
74
    protected $saveAction;
75
    protected $saveLabel;
76
77
    protected $cancelAction;
78
    protected $cancelLabel;
79
80
    /**
81
     * @var Func_Widgets
82
     */
83
    protected $widgets;
84
85
    protected $buttonsLayout;
86
87
    /**
88
     * @var Widget_Layout
89
     */
90
    protected $innerLayout;
91
92
    protected $failedAction = null;
93
    protected $successAction = null;
94
95
    /**
96
     * @var Widget_Section[]
97
     */
98
    protected $sections = array();
99
100
101
    public $isAjax = false;
102
103
    /**
104
     *
105
     * @var array
106
     */
107
    private $tmp_values;
108
109
110
    /**
111
     * @param	Func_App		$app
112
     * @param 	Widget_Layout 	$layout		The layout that will manage how widgets are displayed in this form.
113
     * @param 	string 			$id			The item unique id.
114
     */
115
    public function __construct(Func_App $app, $id = null, Widget_Layout $layout = null)
116
    {
117
        parent::__construct($app);
118
         // We simulate inheritance from Widget_VBoxLayout.
119
        $W = $this->widgets = bab_Widgets();
120
121
        $this->buttonsLayout = $this->buttonsLayout();
122
123
        if (!isset($layout)) {
124
            $this->innerLayout = $W->VBoxLayout();
125
            $this->innerLayout->setVerticalSpacing(1, 'em');
126
        } else {
127
            $this->innerLayout = $layout;
128
        }
129
130
        $this->innerLayout->addClass('app-loading-box'); // javascript can add the app-loading-on class to this container to show ajax loading progress in the form
131
132
        $layout = $W->VBoxItems(
133
            $this->innerLayout,
134
            $this->buttonsLayout
135
        );
136
137
        // We simulate inheritance from Widget_Form.
138
        $this->setInheritedItem($W->Form($id, $layout));
139
        if (isset($this->tmp_values)) {
140
            $this->setValues($this->tmp_values[0], $this->tmp_values[1]);
141
        }
142
143
        $this->setFormStyles();
144
        $this->prependFields();
145
146
    }
147
148
149
    /**
150
     * @return Widget_Layout
151
     */
152
    protected function buttonsLayout()
153
    {
154
        $W = bab_Widgets();
155
        return $W->HBoxLayout()
156
            ->setSizePolicy('widget-form-buttons')
157
            ->setHorizontalSpacing(1, 'em');
158
    }
159
160
161
162
    protected function setFormStyles()
163
    {
164
        $this->addClass('app-editor');
165
    }
166
167
168
    /**
169
     * Set record and values to editor
170
     * @see app_Editor::getRecord()
171
     *
172
     * @param app_Record $record
173
     *
174
     * @return self
175
     */
176
    public function setRecord(app_Record $record)
177
    {
178
        $this->record = $record;
179
180
        if ($name = $this->getName()) {
181
            $values = $record->getFormOutputValues();
182
183
            $this->setValues($values, array($name));
184
        }
185
186
        return $this;
187
    }
188
189
    /**
190
     * @return app_Record
191
     */
192
    protected function getRecord()
193
    {
194
        return $this->record;
195
    }
196
197
198
    /**
199
     * @return app_RecordSet
200
     */
201
    protected function getRecordSet()
202
    {
203
        if ($this->record) {
204
            return $this->record->getParentSet();
205
        }
206
        return null;
207
    }
208
209
210
    public function setValues($row, $namePathBase = array())
211
    {
212
        if (isset($this->item)) {
213
            return $this->item->setValues($row, $namePathBase);
214
        } else {
215
            $this->tmp_values = array($row, $namePathBase);
216
            return true;
217
        }
218
    }
219
220
    /**
221
     *
222
     * @return app_Editor
223
     */
224
    public function setController($ctrl)
225
    {
226
        $this->ctrl = $ctrl;
227
        return $this;
228
    }
229
230
231
    /**
232
     *
233
     * @return app_Editor
234
     */
235
    public function setSaveAction($saveAction, $saveLabel = null)
236
    {
237
        $this->saveAction = $saveAction;
238
        $this->saveLabel = $saveLabel;
239
        return $this;
240
    }
241
242
    public function setSuccessAction($successAction)
243
    {
244
        $this->successAction = $successAction;
245
        return $this;
246
    }
247
248
    public function setFailedAction($failedAction)
249
    {
250
        $this->failedAction = $failedAction;
251
        return $this;
252
    }
253
254
    /**
255
     *
256
     * @return app_Editor
257
     */
258
    public function setCancelAction($cancelAction, $cancelLabel = null)
259
    {
260
        $this->cancelAction = $cancelAction;
261
        $this->cancelLabel = $cancelLabel;
262
        return $this;
263
    }
264
265
266
267
    /**
268
     * Adds a button to button box of the form.
269
     *
270
     * @param Widget_Item $button
271
     * @param Widget_Action $action
272
     *
273
     * @return self
274
     */
275
    public function addButton(Widget_Item $button, Widget_Action $action = null)
276
    {
277
        $this->buttonsLayout->addItem($button);
278
        if (isset($action)) {
279
            $button->setAction($action);
0 ignored issues
show
Bug introduced by
The method setAction() does not exist on Widget_Item. It seems like you code against a sub-type of Widget_Item such as Widget_SimpleTreeView or Widget_Link or Widget_Dockable or Widget_SubmitButton or Widget_Tab. ( Ignorable by Annotation )

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

279
            $button->/** @scrutinizer ignore-call */ 
280
                     setAction($action);
Loading history...
280
        }
281
282
        return $this;
283
    }
284
285
286
    /**
287
     * Adds an item to the top part of the form.
288
     *
289
     * @return app_Editor
290
     */
291
    public function addItem(Widget_Displayable_Interface $item = null, $position = null)
292
    {
293
        $this->innerLayout->addItem($item, $position);
0 ignored issues
show
Unused Code introduced by
The call to Widget_Layout::addItem() has too many arguments starting with $position. ( Ignorable by Annotation )

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

293
        $this->innerLayout->/** @scrutinizer ignore-call */ 
294
                            addItem($item, $position);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
294
295
        return $this;
296
    }
297
298
    /**
299
     *
300
     *
301
     */
302
    protected function appendButtons()
303
    {
304
        $W = $this->widgets;
305
        $App = $this->App();
306
307
        if (isset($this->saveAction)) {
308
            $saveLabel = isset($this->saveLabel) ? $this->saveLabel : $App->translate('Save');
309
            $submitButton = $W->SubmitButton();
310
            $submitButton->validate()
311
                ->setAction($this->saveAction)
312
                ->setFailedAction($this->failedAction)
313
                ->setSuccessAction($this->successAction)
314
                ->setLabel($saveLabel);
315
            if ($this->isAjax) {
316
                $submitButton->setAjaxAction();
317
            }
318
            $this->addButton($submitButton);
319
        }
320
321
        if (isset($this->cancelAction)) {
322
            $cancelLabel = isset($this->cancelLabel) ? $this->cancelLabel : $App->translate('Cancel');
323
            $this->addButton(
324
                $W->SubmitButton(/*'cancel'*/)
325
                     ->addClass('widget-close-dialog')
326
                    ->setAction($this->cancelAction)
327
                      ->setLabel($cancelLabel)
328
            );
329
        }
330
    }
331
332
    /**
333
     * Fields that will appear at the beginning of the form.
334
     *
335
     */
336
    protected function prependFields()
337
    {
338
339
    }
340
341
342
    /**
343
     * Fields that will appear at the end of the form.
344
     *
345
     */
346
    protected function appendFields()
347
    {
348
349
    }
350
351
352
    /**
353
     * Adds an item with a label and a description to the form.
354
     *
355
     * @param string                       $labelText
356
     * @param Widget_Displayable_Interface $item
357
     * @param string                       $fieldName
358
     * @param string                       $description
359
     * @param string						$suffix		 suffix for input field, example : unit
360
     *
361
     * @return Widget_LabelledWidget
362
     */
363
    public function labelledField($labelText, Widget_Displayable_Interface $item, $fieldName = null, $description = null, $suffix = null)
364
    {
365
        $W = $this->widgets;
366
        return $W->LabelledWidget($labelText, $item, $fieldName, $description, $suffix);
367
    }
368
369
370
    /**
371
     * Creates section in the editor.
372
     * If a section with the same header text (title) was already
373
     * created it is replaced by an empty section.
374
     *
375
     * @param string $headerText
376
     * @return Widget_Section
377
     */
378
    protected function createSection($headerText, $layout = null)
379
    {
380
        $W = bab_Widgets();
381
        if (!isset($layout)) {
382
            $layout = $W->VBoxLayout()->setVerticalSpacing(1, 'em');
383
        }
384
        $this->sections[$headerText] = $W->Section(
385
            $headerText,
386
            $layout
387
        )->setFoldable(true);
388
389
        return $this->sections[$headerText];
390
    }
391
392
    /**
393
     * Retrieves a section in the editor.
394
     *
395
     * @param string $headerText
396
     * @return Widget_Section
397
     */
398
    protected function getSection($headerText)
399
    {
400
        if (!isset($this->sections[$headerText])) {
401
            return null;
402
        }
403
        return $this->sections[$headerText];
404
    }
405
406
407
    /**
408
     * Returns the list of sections created via createSection().
409
     *
410
     * @return Widget_Section[]
411
     */
412
    public function getSections()
413
    {
414
        return $this->sections;
415
    }
416
417
418
    /**
419
     *
420
     */
421
    public function display(Widget_Canvas $canvas)
422
    {
423
        $this->appendFields();
424
        $this->appendButtons();
425
426
        return parent::display($canvas);
427
    }
428
}
429
430
431
class app_Toolbar extends Widget_Frame
432
{
433
    public $local = false;
434
435
    public function __construct($id = null, Widget_Layout $layout = null)
436
    {
437
        if (!isset($layout)) {
438
            $W = bab_Widgets();
439
            $layout = $W->FlowLayout()->setHorizontalSpacing(1, 'em');
440
            $layout->setVerticalAlign('top');
441
        }
442
443
        parent::__construct($id, $layout);
444
    }
445
446
    /**
447
     *
448
     * @param string		 	$labelText
449
     * @param string			$iconName
450
     * @param Widget_Action		$action
451
     * @param string			$id
452
     * @return app_Toolbar
453
     */
454
    public function addButton($labelText = null, $iconName = null, $action = null, $id = null)
455
    {
456
        $W = bab_Widgets();
457
        $button = $W->Link($labelText, $action, $id);
458
        if (isset($iconName)) {
459
            $button->addClass('icon', $iconName);
460
        }
461
462
        $this->addItem($button);
463
464
        return $this;
465
    }
466
467
468
    public function addInstantForm(Widget_Displayable_Interface $form, $labelText = null, $iconName = null, $action = null, $id = null)
469
    {
470
        $W = bab_Widgets();
471
        if (isset($iconName)) {
472
            $content = $W->Icon($labelText, $iconName);
473
        } else {
474
            $content = $labelText;
475
        }
476
        $button = $W->Link($content, $action, $id);
477
478
        $this->addItem(
479
            $W->VBoxItems(
480
                $button->addClass('widget-instant-button'),
481
                $form->addClass('widget-instant-form')
482
            )->addClass('widget-instant-container')
483
        );
484
485
        if ($form->getTitle() === null) {
486
            $form->setTitle($labelText);
487
        }
488
489
490
        return $this;
491
492
    }
493
494
495
    public function display(Widget_Canvas $canvas)
496
    {
497
        if (!$this->local) {
498
            $this->addClass('widget-toolbar');
499
        } else {
500
            $this->addClass('app-toolbar');
501
        }
502
        $this->addClass(Func_Icons::ICON_LEFT_16);
503
504
        return parent::display($canvas);
505
    }
506
507
}
508
509
510
511
512
class app_RecordEditor extends app_Editor
513
{
514
515
    /**
516
     * @var app_RecordSet
517
     */
518
    public $recordSet = null;
519
520
    /**
521
     * Creates section in the editor.
522
     * If a section with the same header text (title) was already
523
     * created it is replaced by an empty section.
524
     *
525
     * @param string $headerText
526
     * @return Widget_Section
527
     */
528
    protected function addSection($id, $headerText, $layout = null)
529
    {
530
        $W = bab_Widgets();
531
        if (!isset($layout)) {
532
            $layout = $W->VBoxLayout()->setVerticalSpacing(1, 'em');
533
        }
534
        $this->sections[$id] = $W->Section(
535
            $headerText,
536
            $layout
537
            )->setFoldable(true);
538
539
            return $this->sections[$id];
540
    }
541
542
543
    /**
544
     * Retrieves a section in the editor.
545
     *
546
     * @param string $headerText
547
     * @return Widget_Section
548
     */
549
    protected function getSection($id)
550
    {
551
        if (!isset($this->sections[$id])) {
552
            return null;
553
        }
554
        return $this->sections[$id];
555
    }
556
557
558
    /**
559
     * @param string $textLabel
560
     * @param mixed $value
561
     * @return Widget_Displayable_Interface
562
     */
563
    public function labelledWidget($textLabel, $value, app_CustomSection $section = null)
564
    {
565
        $W = bab_Widgets();
566
567
        if ($value instanceof Widget_Displayable_Interface) {
568
            $widget = $value;
569
        } else {
570
            $widget = $W->Label($value);
571
        }
572
573
        if (isset($section)) {
574
            if ($textLabel === '__') {
575
                $fieldLayout = app_CustomSection::FIELDS_LAYOUT_NO_LABEL;
576
            } else {
577
                $fieldLayout = $section->fieldsLayout;
578
            }
579
            switch ($fieldLayout) {
580
                case app_CustomSection::FIELDS_LAYOUT_HORIZONTAL_LABEL:
581
                    return $W->FlowItems(
582
                        $W->Label($textLabel)->addClass('crm-horizontal-display-label', 'widget-strong')
583
                            ->setSizePolicy('widget-25pc'),
584
                        $widget->setSizePolicy('widget-75pc')
585
                    )->addClass('widget-labelled-widget')
586
                    ->setHorizontalSpacing(1, 'ex')
587
                    ->setVerticalAlign('top');
588
589
                case app_CustomSection::FIELDS_LAYOUT_WIDE_HORIZONTAL_LABEL:
590
                    return $W->FlowItems(
591
                        $W->Label($textLabel)->addClass('crm-horizontal-display-label', 'widget-strong')
592
                            ->setSizePolicy('widget-50pc'),
593
                        $widget
594
                    )->addClass('widget-labelled-widget')
595
                    ->setHorizontalSpacing(1, 'ex')
596
                    ->setVerticalAlign('top');
597
598
                case app_CustomSection::FIELDS_LAYOUT_NO_LABEL:
599
                    return $widget;
600
601
                case app_CustomSection::FIELDS_LAYOUT_VERTICAL_LABEL:
602
                default:
603
                    return $W->LabelledWidget($textLabel, $widget);
604
            }
605
        }
606
    }
607
608
609
    function labelledWidgetOptional($textLabel, $displayedValue, $value = null, app_CustomSection $section = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
610
    {
611
        if (!isset($value)) {
612
            $value = $displayedValue;
613
        }
614
        if (!isset($value) || is_numeric($value) && $value == 0 || is_string($value) && trim($value) == '' || ($value instanceof Widget_Layout && count($value->getItems()) <= 0)) {
615
            return null;
616
        }
617
        return $this->labelledWidget($textLabel, $displayedValue, $section);
618
    }
619
620
621
622
    protected function fieldOutput($field, $record, $fieldName)
623
    {
624
        if ($field instanceof ORM_CurrencyField) {
625
            $App = $this->App();
626
            $value = $App->shortFormatWithUnit($this->record->$fieldName, $App->translate('_euro_'));
627
        } else {
628
            $value = $field->output($this->record->$fieldName);
629
        }
630
        if (is_array($value)) {
631
            $value = implode(', ', $value);
632
        }
633
        return $value;
634
    }
635
636
637
    protected function getValueItem($customSection, $displayField, $label, $value)
638
    {
639
        return $this->labelledWidget(
640
            $label,
641
            //            $item,
642
            $value,
643
            $customSection
644
        );
645
    }
646
647
648
    protected function addSections($view)
649
    {
650
        $App = $this->App();
651
        $W = bab_Widgets();
652
653
654
        $this->addItem($W->Hidden()->setName('id'));
655
656
        $recordClassName = $this->record->getClassName();
657
658
        $customSectionSet = $App->CustomSectionSet();
659
        $conditions = array(
660
            $customSectionSet->object->is($recordClassName),
661
            $customSectionSet->view->is($view)
662
        );
663
664
        $customSections = $customSectionSet->select(
665
            $customSectionSet->all($conditions)
666
            );
667
        $customSections->orderAsc($customSectionSet->rank);
668
669
        $currentColumn = 0;
670
        $nbCol = 0;
671
672
        $row = $W->Items()->setSizePolicy('row');
673
        foreach ($customSections as $customSection) {
674
675
            if (isset($this->record) && !$customSection->isVisibleForRecord($this->record)) {
676
                continue;
677
            }
678
679
            list(, , $nbCol) = explode('-', $customSection->sizePolicy);
680
681
            if ($currentColumn + $nbCol > 12) {
682
                $this->addItem($row);
683
                $row = $W->Items()->setSizePolicy('row');
684
                $currentColumn = 0;
685
            }
686
            $currentColumn += $nbCol;
687
688
            $section = $this->getSection($customSection->id);
689
            if (!isset($section)) {
690
                $section = $this->addSection($customSection->id, $customSection->name);
691
                $section->addClass($customSection->classname);
692
                $section->setSizePolicy($customSection->sizePolicy);
693
694
                $section->setFoldable($customSection->foldable, $customSection->folded);
695
                $row->addItem($section);
696
            }
697
698
            $displayFields = $customSection->getFields();
699
700
            foreach ($displayFields as $displayField) {
701
                $widget = null;
702
                $item = null;
703
                $displayFieldName = $displayField['fieldname'];
704
                $parameters = $displayField['parameters'];
705
                $classname = isset($parameters['classname']) ? $parameters['classname'] : '';
706
                $label = isset($parameters['label']) && $parameters['label'] !== '__' ? $parameters['label'] : '';
707
                $displayFieldMethod = '_' . $displayFieldName;
708
709
                if (method_exists($this, $displayFieldMethod)) {
710
                    $widget = $this->$displayFieldMethod($customSection, $label);
711
                    $item = $widget;
712
                } elseif ($this->recordSet->fieldExist($displayFieldName)) {
713
                    $field = $this->recordSet->getField($displayFieldName);
714
                    if ($label === '') {
715
                        $label = $field->getDescription();
716
                        if (substr($displayFieldName, 0, 1) !== '_') {
717
                            $label = $App->translate($label);
718
                        }
719
                    }
720
                    $widget = $field->getWidget();
721
                    if ($widget instanceof Widget_TextEdit || $widget instanceof Widget_Select) {
722
                        $widget->addClass('widget-100pc');
723
                    }
724
                    $item = $this->getValueItem($customSection, $displayField, $label, $widget);
725
                }
726
727
                if ($item) {
728
                    $item->addClass($classname);
729
                    $section->addItem($item);
730
                }
731
            }
732
        }
733
734
        if ($currentColumn + $nbCol > 0) {
735
            $this->addItem($row);
736
        }
737
    }
738
739
    public function sectionContent($customSectionId)
740
    {
741
        $App = $this->App();
742
743
        $customSectionSet = $App->CustomSectionSet();
744
        $customSection = $customSectionSet->get($customSectionId);
745
746
        if (isset($this->record) && !$customSection->isVisibleForRecord($this->record)) {
747
            return null;
748
        }
749
750
        $W = bab_Widgets();
751
752
        $section = $W->VBoxLayout()->setVerticalSpacing(1, 'em');
753
754
        $displayFields = $customSection->getFields();
755
756
        $customSection->fieldsLayout = app_CustomSection::FIELDS_LAYOUT_HORIZONTAL_LABEL;
757
758
        foreach ($displayFields as $displayField) {
759
            $widget = null;
760
            $item = null;
761
            $displayFieldName = $displayField['fieldname'];
762
            $parameters = $displayField['parameters'];
763
            $classname = isset($parameters['classname']) ? $parameters['classname'] : '';
764
            $label = isset($parameters['label']) && $parameters['label'] !== '__' ? $parameters['label'] : '';
765
            $displayFieldMethod = '_' . $displayFieldName;
766
767
            if (method_exists($this, $displayFieldMethod)) {
768
                $widget = $this->$displayFieldMethod($customSection, $label);
769
                $item = $widget;
770
            } elseif ($this->recordSet->fieldExist($displayFieldName)) {
771
                $field = $this->recordSet->getField($displayFieldName);
772
                if ($label === '') {
773
                    $label = $field->getDescription();
774
                    if (substr($displayFieldName, 0, 1) !== '_') {
775
                        $label = $App->translate($label);
776
                    }
777
                }
778
                $widget = $field->getWidget();
779
                if ($widget instanceof Widget_TextEdit) {
780
                    $widget->addClass('widget-100pc widget-autoresize');
781
782
                }
783
                if ($widget instanceof Widget_Select) {
784
                    $widget->addClass('widget-100pc');
785
                }
786
                $item = $this->getValueItem($customSection, $displayField, $label, $widget);
787
            }
788
789
            if ($item) {
790
                $item->addClass($classname);
791
                $section->addItem($item);
792
            }
793
        }
794
795
        return $section;
796
    }
797
}
798
799
800
801
802
803
/**
804
 * A record frame is a frame displaying information about a app record.
805
 *
806
 * @since 1.0.40
807
 */
808
class app_RecordFrame extends app_UiObject // extends Widget_Frame
809
{
810
    /**
811
     * @var Widget_Section[]
812
     */
813
    protected $sections = array();
814
815
    /**
816
     * @var app_Record
817
     */
818
    protected $record = null;
819
820
    /**
821
     * @var app_RecordSet
822
     */
823
    protected $recordSet = null;
824
825
826
    /**
827
     * @param Func_App      $app
828
     * @param app_Record    $record
829
     * @param string        $id
830
     * @param Widget_Layout $layout
831
     */
832
    public function __construct(Func_App $app, app_Record $record, $id = null, Widget_Layout $layout = null)
833
    {
834
        parent::__construct($app);
835
836
        $W = bab_Widgets();
837
        $this->setInheritedItem($W->Frame($id, $layout));
838
    }
839
840
841
    /**
842
     * Creates section in the editor.
843
     * If a section with the same header text (title) was already
844
     * created it is replaced by an empty section.
845
     *
846
     * @param string $headerText
847
     * @return Widget_Section
848
     */
849
    protected function addSection($id, $headerText, $layout = null)
850
    {
851
        $W = bab_Widgets();
852
        if (!isset($layout)) {
853
            $layout = $W->VBoxLayout()->setVerticalSpacing(0.6, 'em');
0 ignored issues
show
Bug introduced by
0.6 of type double is incompatible with the type integer expected by parameter $spacing of Widget_Layout::setVerticalSpacing(). ( Ignorable by Annotation )

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

853
            $layout = $W->VBoxLayout()->setVerticalSpacing(/** @scrutinizer ignore-type */ 0.6, 'em');
Loading history...
854
        }
855
        $this->sections[$id] = $W->Section(
856
            $headerText,
857
            $layout
858
        )->setFoldable(true);
859
860
        return $this->sections[$id];
861
    }
862
863
864
    /**
865
     * Retrieves a section in the editor.
866
     *
867
     * @param string $headerText
868
     * @return Widget_Section
869
     */
870
    protected function getSection($id)
871
    {
872
        if (!isset($this->sections[$id])) {
873
            return null;
874
        }
875
        return $this->sections[$id];
876
    }
877
878
879
    /**
880
     * @param string $textLabel
881
     * @param Widget_Displayable_Interface|string $value
882
     * @param app_CustomSection $section
883
     * @return Widget_Displayable_Interface
884
     */
885
    public function labelledWidget($textLabel, $value, app_CustomSection $section = null)
886
    {
887
        $W = bab_Widgets();
888
889
        if ($value instanceof Widget_Displayable_Interface) {
890
            $widget = $value;
891
        } else {
892
            $widget = $W->Label($value);
893
        }
894
895
        if (isset($section)) {
896
            if ($textLabel === '__') {
897
                $fieldLayout = app_CustomSection::FIELDS_LAYOUT_NO_LABEL;
898
            } else {
899
                $fieldLayout = $section->fieldsLayout;
900
            }
901
            switch ($fieldLayout) {
902
                case app_CustomSection::FIELDS_LAYOUT_HORIZONTAL_LABEL:
903
                    return $W->FlowItems(
904
                    $W->Label($textLabel)->addClass('app-horizontal-display-label', 'widget-strong')
905
                        ->setSizePolicy('widget-25pc'),
906
                    $widget->setSizePolicy('widget-75pc')
907
                )->addClass('widget-labelled-widget')
908
                ->setHorizontalSpacing(1, 'ex')
909
                ->setVerticalAlign('top');
910
911
                case app_CustomSection::FIELDS_LAYOUT_WIDE_HORIZONTAL_LABEL:
912
                    return $W->FlowItems(
913
                    $W->Label($textLabel)->addClass('app-horizontal-display-label', 'widget-strong')
914
                        ->setSizePolicy('widget-50pc'),
915
                    $widget->setSizePolicy('widget-50pc')
916
                )->addClass('widget-labelled-widget')
917
                ->setHorizontalSpacing(1, 'ex')
918
                ->setVerticalAlign('top');
919
920
                case app_CustomSection::FIELDS_LAYOUT_VERY_WIDE_HORIZONTAL_LABEL:
921
                    return $W->FlowItems(
922
                    $W->Label($textLabel)->addClass('app-horizontal-display-label', 'widget-strong')
923
                        ->setSizePolicy('widget-75pc'),
924
                    $widget->setSizePolicy('widget-25pc')
925
                )->addClass('widget-labelled-widget')
926
                ->setHorizontalSpacing(1, 'ex')
927
                ->setVerticalAlign('top');
928
929
930
                case app_CustomSection::FIELDS_LAYOUT_NO_LABEL:
931
                    return $widget;
932
933
                case app_CustomSection::FIELDS_LAYOUT_VERTICAL_LABEL:
934
                default:
935
                    return $W->LabelledWidget($textLabel, $widget);
936
            }
937
        }
938
    }
939
940
941
    /**
942
     *
943
     * @param string $textLabel
944
     * @param mixed $displayedValue
945
     * @param mixed $value
946
     * @param app_CustomSection $section
947
     * @return Widget_Displayable_Interface|null
948
     */
949
    public function labelledWidgetOptional($textLabel, $displayedValue, $value = null, app_CustomSection $section = null)
950
    {
951
        if (!isset($value)) {
952
            $value = $displayedValue;
953
        }
954
        if (!isset($value) || is_numeric($value) && $value == 0 || is_string($value) && trim($value) == '' || ($value instanceof Widget_Layout && count($value->getItems()) <= 0)) {
955
            return null;
956
        }
957
        $labelledWidget = $this->labelledWidget($textLabel, $displayedValue, $section);
958
        return $labelledWidget;
959
    }
960
961
962
    /**
963
     *
964
     * @param ORM_Field $field
965
     * @param ORM_Record $record
966
     * @param string $fieldName
967
     * @return mixed
968
     */
969
    protected function fieldOutput($field, $record, $fieldName)
970
    {
971
        if ($field instanceof ORM_CurrencyField) {
972
            $App = $this->App();
973
            $value = $App->shortFormatWithUnit($this->record->$fieldName, $App->translate('_euro_'));
974
        } else {
975
            $value = $field->output($this->record->$fieldName);
976
        }
977
        if (is_array($value)) {
978
            $value = implode(', ', $value);
979
        }
980
        return $value;
981
    }
982
983
984
    /**
985
     *
986
     * @param app_CustomSection $customSection
987
     * @param array $displayField
988
     * @param string $textLabel
989
     * @param Widget_Displayable_Interface|string $value
990
     * @return Widget_Displayable_Interface
991
     */
992
    protected function getValueItem(app_CustomSection $customSection, $displayField, $textLabel, $value)
993
    {
994
        if ($value instanceof Widget_Displayable_Interface) {
995
            return $value;
996
        }
997
        $W = bab_Widgets();
998
        $parameters = $displayField['parameters'];
999
        if (isset($parameters['type'])) {
1000
            if ($parameters['type'] === 'title1') {
1001
                $item = $W->Title($value, 1);
1002
            } elseif ($parameters['type'] === 'title2') {
1003
                $item = $W->Title($value, 2);
1004
            } elseif ($parameters['type'] === 'title3') {
1005
                $item = $W->Title($value, 3);
1006
            } else {
1007
                $item = $W->Label($value);
1008
            }
1009
        } else {
1010
            $item = $W->Label($value);
1011
        }
1012
        $labelledWidgetOptional = $this->labelledWidget( //Optional(
1013
            $textLabel,
1014
            $item,
1015
//            $value,
1016
            $customSection
1017
        );
1018
1019
        if (isset($labelledWidgetOptional)) {
1020
            $labelledWidgetOptional->addClass($displayField['fieldname']);
1021
        }
1022
1023
        return $labelledWidgetOptional;
1024
    }
1025
1026
1027
    /**
1028
     * @param string $view
1029
     */
1030
    protected function addSections($view)
1031
    {
1032
        $App = $this->App();
1033
        $W = bab_Widgets();
1034
1035
        $recordClassName = $this->record->getClassName();
1036
1037
        $customSectionSet = $App->CustomSectionSet();
1038
        $customSections = $customSectionSet->select(
1039
            $customSectionSet->object->is($recordClassName)->_AND_(
1040
                $customSectionSet->view->is($view)
1041
            )
1042
        );
1043
        $customSections->orderAsc($customSectionSet->rank);
1044
1045
        $currentColumn = 0;
1046
        $nbCol = 0;
1047
        $row = $W->Items()->setSizePolicy('row');
1048
        foreach ($customSections as $customSection) {
1049
1050
            list(, , $nbCol) = explode('-', $customSection->sizePolicy);
1051
1052
            if ($currentColumn + $nbCol > 12) {
1053
                $this->addItem($row);
0 ignored issues
show
Bug introduced by
The method addItem() does not exist on app_RecordFrame. 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

1053
                $this->/** @scrutinizer ignore-call */ 
1054
                       addItem($row);
Loading history...
1054
                $row = $W->Items()->setSizePolicy('row');
1055
                $currentColumn = 0;
1056
            }
1057
            $currentColumn += $nbCol;
1058
1059
            $section = $this->getSection($customSection->id);
1060
            if (!isset($section)) {
1061
                $section = $this->addSection($customSection->id, $customSection->name);
1062
                $section->addClass($customSection->classname);
1063
                $section->setSizePolicy($customSection->sizePolicy);
1064
1065
                $section->setFoldable($customSection->foldable, $customSection->folded);
1066
                $row->addItem($section);
1067
            }
1068
1069
            $displayFields = $customSection->getFields();
1070
1071
            foreach ($displayFields as $displayField) {
1072
                $value = null;
1073
                $displayFieldName = $displayField['fieldname'];
1074
                $parameters = $displayField['parameters'];
1075
                $classname = isset($parameters['classname']) ? $parameters['classname'] : '';
1076
                $label = isset($parameters['label']) ? $parameters['label'] : '';
1077
                $displayFieldMethod = '_' . $displayFieldName;
1078
1079
                if (method_exists($this, $displayFieldMethod)) {
1080
                    $value = $this->$displayFieldMethod($customSection, $label);
1081
                } elseif ($this->recordSet->fieldExist($displayFieldName)) {
1082
                    $field = $this->recordSet->getField($displayFieldName);
1083
                    if ($label === '') {
1084
                        $label = $field->getDescription();
1085
                        if (substr($displayFieldName, 0, 1) !== '_') {
1086
                            $label = $App->translate($label);
1087
                        }
1088
                    }
1089
                    $value = $this->fieldOutput($field, $this->record, $displayFieldName);
1090
                }
1091
1092
                if (isset($value)) {
1093
                    $item = $this->getValueItem($customSection, $displayField, $label, $value);
1094
                    if ($item) {
1095
                        $item->addClass($classname);
1096
                        $section->addItem($item);
1097
                    }
1098
                }
1099
            }
1100
        }
1101
1102
        if ($currentColumn + $nbCol > 0) {
1103
            $this->addItem($row);
1104
        }
1105
    }
1106
}
1107
1108
1109
1110
1111
1112
1113
1114
1115
/**
1116
 * Table model view with App() method
1117
 *
1118
 *
1119
 */
1120
class app_TableModelView extends widget_TableModelView
1121
{
1122
1123
    /**
1124
     * Filter form reset button
1125
     */
1126
    protected $reset = null;
1127
1128
1129
    /**
1130
     * @var Func_App
1131
     */
1132
    private $app = null;
1133
1134
1135
    /**
1136
     * @var app_CtrlRecord
1137
     */
1138
    protected $recordController = null;
1139
1140
    /**
1141
     * @var app_CtrlRecord
1142
     */
1143
    protected $recordControllerProxy = null;
1144
1145
    /**
1146
     * @param Func_App $app
1147
     * @param string $id
1148
     */
1149
    public function __construct(Func_App $app = null, $id = null)
1150
    {
1151
        parent::__construct($id);
1152
        $this->setApp($app);
1153
    }
1154
1155
    /**
1156
     * Forces the Func_App object to which this object is 'linked'.
1157
     *
1158
     * @param Func_App	$app
1159
     * @return self
1160
     */
1161
    public function setApp(Func_App $app = null)
1162
    {
1163
        $this->app = $app;
1164
        return $this;
1165
    }
1166
1167
    /**
1168
     * Get App object to use with this SET
1169
     *
1170
     * @return Func_App
1171
     */
1172
    public function App()
1173
    {
1174
        if (!isset($this->app)) {
1175
            // If the app object was not specified (through the setApp() method)
1176
            // we try to select one according to the classname prefix.
1177
            list($prefix) = explode('_', get_class($this));
1178
            $functionalityName = ucwords($prefix);
1179
            $this->app = @bab_functionality::get('App/' . $functionalityName);
0 ignored issues
show
Documentation Bug introduced by
@bab_functionality::get(...' . $functionalityName) is of type bab_functionality, but the property $app was declared to be of type Func_App. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
1180
            if (!$this->app) {
1181
                $this->app = @bab_functionality::get('App');
1182
            }
1183
        }
1184
        return $this->app;
1185
    }
1186
1187
1188
1189
	protected function addCustomFields(app_RecordSet $recordSet)
1190
	{
1191
		$customFields = $recordSet->getCustomFields();
1192
1193
        foreach ($customFields as $customField) {
1194
            $fieldname = $customField->fieldname;
1195
            $this->addColumn(
1196
                widget_TableModelViewColumn($recordSet->$fieldname, $customField->name)
1197
                  ->setSortable(true)
1198
                  ->setExportable(true)
1199
                  ->setSearchable($customField->searchable)
0 ignored issues
show
Bug Best Practice introduced by
The property searchable does not exist on app_CustomField. Since you implemented __get, consider adding a @property annotation.
Loading history...
1200
				  ->setVisible($customField->visible)
0 ignored issues
show
Bug Best Practice introduced by
The property visible does not exist on app_CustomField. Since you implemented __get, consider adding a @property annotation.
Loading history...
1201
            );
1202
        }
1203
	}
1204
1205
1206
    /**
1207
     * Get a generic filter panel
1208
     * Use setPageLength to define the default number of items per page
1209
     *
1210
     * @param	array	$filter		Filter values
1211
     * @param	string	$name		filter form name
1212
     * @param	string	$anchor		anchor in destination page of filter, the can be a Widget_Tab id
1213
     *
1214
     * @return Widget_Filter
1215
     */
1216
    public function filterPanel($filter = null, $name = null)
1217
    {
1218
        $W = bab_Widgets();
1219
1220
        $filterPanel = $W->Filter();
1221
        $filterPanel->setLayout($W->VBoxLayout());
1222
        if (isset($name)) {
1223
            $filterPanel->setName($name);
1224
        }
1225
1226
        $pageLength = $this->getPageLength();
1227
        if (null === $pageLength) {
0 ignored issues
show
introduced by
The condition null === $pageLength is always false.
Loading history...
1228
            $pageLength = 15;
1229
        }
1230
1231
        $pageNumber = $this->getCurrentPage();
1232
        if (null === $pageNumber) {
0 ignored issues
show
introduced by
The condition null === $pageNumber is always false.
Loading history...
1233
            $pageNumber = 0;
1234
        }
1235
1236
        $this->setPageLength(isset($filter['pageSize']) ? $filter['pageSize'] : $pageLength);
1237
        $this->setCurrentPage(isset($filter['pageNumber']) ? $filter['pageNumber'] : $pageNumber);
1238
1239
        if (isset($name)) {
1240
            $this->sortParameterName = $name . '[filter][sort]';
1241
        } else {
1242
            $this->sortParameterName = 'filter[sort]';
1243
        }
1244
1245
        if (isset($filter['sort'])) {
1246
            $this->setSortField($filter['sort']);
1247
        } elseif (!isset($this->sortField)) {
1248
1249
            if (method_exists($this, 'getDefaultSortField')) {
1250
                $this->setSortField($this->getDefaultSortField());
1251
            } else {
1252
                $columns = $this->getVisibleColumns();
1253
                $sortField = key($columns);
1254
                $this->setSortField($sortField);
1255
            }
1256
        }
1257
1258
        $form = $this->getFilterForm();
1259
1260
        if (isset($filter)) {
1261
            if (isset($name)) {
1262
                $path = array($name, 'filter');
1263
            } else {
1264
                $path = array('filter');
1265
            }
1266
            $form->setValues($filter, $path);
1267
        }
1268
1269
1270
        $filterPanel->setFilter($form);
1271
        $filterPanel->setFiltered($this);
1272
1273
        return $filterPanel;
1274
    }
1275
1276
1277
    /**
1278
     * Add the filter fields to the filter form
1279
     * @param Widget_Form $form
1280
     *
1281
     */
1282
    protected function handleAdvancedFilterFields(Widget_Item $form)
1283
    {
1284
1285
    }
1286
1287
1288
1289
1290
    protected function isFilterFieldSpecified($filter, $fieldPath)
1291
    {
1292
        if (isset($filter[$fieldPath])) {
1293
            $value = $filter[$fieldPath];
1294
            if (is_array($value)) {
1295
                foreach ($value as $val) {
1296
                    $val = trim($val);
1297
                    if (!empty($val)) {
1298
                        return true;
1299
                    }
1300
                }
1301
                return false;
1302
            }
1303
1304
            if (trim($value) !== '') {
1305
                return true;
1306
            }
1307
        }
1308
1309
        return false;
1310
    }
1311
1312
1313
    protected function handleFilterInputWidget($name, ORM_Field $field = null)
1314
    {
1315
        if (null === $field) {
1316
            return null;
1317
        }
1318
1319
        $W = bab_Widgets();
1320
1321
        if ($field instanceof ORM_FkField) {
1322
            $widget = $W->Select();
1323
            $widget->addOption('', '');
1324
1325
            $App = $this->App();
1326
            $setName = $field->getForeignSetName();
1327
1328
            $pos = strrpos($setName, '\\');
1329
            if ($pos === false) {
1330
                list(, $appSetName) = explode('_', $setName);
1331
            } else {
1332
                list(, $appSetName) = array(substr($setName, 0, $pos), substr($setName, $pos + 1));
1333
            }
1334
1335
            $set = $App->$appSetName();
1336
            $set->setName($field->getName());
1337
            $set->setDescription($field->getDescription());
1338
1339
            if ($set === null) {
1340
                return null;
1341
            }
1342
1343
            $values = $set->select();
1344
            foreach ($values as $record) {
1345
                $widget->addOption($record->id, (string)$record->name);
1346
            }
1347
1348
            return $widget;
1349
        }
1350
1351
        return parent::handleFilterInputWidget($name, $field);
1352
    }
1353
1354
1355
    /**
1356
     * Handle label and input widget merge in one item before adding to the filter form
1357
     * default is a vertical box layout
1358
     *
1359
     * @param Widget_Label                  $label
1360
     * @param Widget_Displayable_Interface  $input
1361
     * @return Widget_Item
1362
     */
1363
    protected function handleFilterLabel(Widget_Label $label, Widget_Displayable_Interface $input)
1364
    {
1365
        $W = bab_Widgets();
1366
        if ($input instanceof Widget_CheckBox) {
1367
            return $W->HBoxItems(
1368
                $input,
1369
                $label
1370
            )->setVerticalAlign('middle')
1371
            ->setHorizontalSpacing(1, 'ex');
1372
        }
1373
        return $W->VBoxItems(
1374
            $label,
1375
            $input
1376
        );
1377
    }
1378
1379
    protected function getSearchItem()
1380
    {
1381
        $W = bab_Widgets();
1382
1383
        return $W->LineEdit()->setName('search')->addClass('widget-100pc');
1384
    }
1385
1386
    /**
1387
     * Get an advanced form filter
1388
     * @see Widget_Filter
1389
     *
1390
     * @param   string          $id
1391
     * @param   array           $filter
1392
     *
1393
     * @return Widget_Form
1394
     */
1395
    public function getAdvancedFilterForm($id = null, $filter = null)
1396
    {
1397
        $App = $this->App();
1398
1399
        $W = bab_Widgets();
1400
1401
        $formItem = $this->getSearchItem();
1402
1403
        $activeFiltersFrame = $W->Frame(
1404
            null,
1405
            $W->FlowItems(
1406
                $W->VBoxItems(
1407
                    $W->Label($App->translate('Search'))->setAssociatedWidget($formItem),
1408
                    $formItem
1409
                )
1410
            )
1411
            ->setHorizontalSpacing(2, 'em')
1412
            ->setVerticalSpacing(1, 'em')
1413
            ->setVerticalAlign('bottom')
1414
        );
1415
1416
1417
        $addFilterButton = $W->Link($App->translate('More criteria'))
1418
            ->addClass('icon', Func_Icons::ACTIONS_LIST_ADD, 'widget-instant-button', 'widget-actionbutton');
1419
1420
1421
        $filterBox = $W->FlowLayout()
1422
            ->addClass('widget-instant-form')
1423
            ->setHorizontalSpacing(2, 'em')
1424
            ->setVerticalSpacing(1, 'em')
1425
            ->setVerticalAlign('bottom');
1426
1427
        $advancedFiltersFrame = $W->VBoxItems(
1428
            $addFilterButton,
1429
            $filterBox
1430
        )->addClass('widget-instant-container');
1431
1432
1433
        $columns = $this->getVisibleColumns();
1434
1435
        foreach ($columns as $fieldName => $column) {
1436
            $field = $column->getField();
1437
            if (! $column->isSearchable()) {
1438
                continue;
1439
            }
1440
1441
            if (! ($field instanceof ORM_Field)) {
1442
                $field = null;
1443
            }
1444
1445
            $label = $this->handleFilterLabelWidget($fieldName, $field);
1446
            $input = $this->handleFilterInputWidget($fieldName, $field);
1447
1448
            if (isset($input) && isset($label)) {
1449
1450
                $input->setName($fieldName);
1451
                $label->setAssociatedWidget($input);
1452
1453
                $input->addClass('widget-100pc');
1454
1455
                $formItem = $this->handleFilterLabel($label, $input);
1456
                $formItem->addClass('field_' . $fieldName);
1457
1458
                $mainSearch = (method_exists($column, 'isMainSearch') && $column->isMainSearch());
1459
1460
                if ($mainSearch || $this->isFilterFieldSpecified($filter, $column->getFieldPath())) {
1461
1462
                    $removeColumnsAction = $W->Action();
1463
                    $removeColumnsAction->setMethod(
1464
                        'addon/widgets/configurationstorage',
1465
                        'removeFilter',
1466
                        array(
1467
                            'key' => $this->getId(),
1468
                            'name' => $column->getFieldPath(),
1469
                            'insession' => $this->isConfigurationStorageInSession()
1470
                        )
1471
                    );
1472
1473
                    $activeFiltersFrame->addItem(
1474
                        $W->FlowItems(
1475
                            $formItem,
1476
                            $W->Link('', $removeColumnsAction)
1477
                                ->setAjaxAction()
1478
                                ->addClass('icon', Func_Icons::STATUS_DIALOG_ERROR)
1479
                        )
1480
                    );
1481
                } else {
1482
                    $formItem->setSizePolicy('col-lg-2 col-md-3 col-sm-6 col-xs-12');
1483
                    $filterBox->addItem($formItem);
1484
                }
1485
            }
1486
        }
1487
1488
1489
        if (! $this->submit) {
1490
            $this->submit = $W->SubmitButton();
1491
            $this->submit->setLabel(widget_translate('Apply filter'));
1492
        }
1493
1494
1495
1496
        if ($controller = $this->getRecordController()) {
1497
            $proxy = $controller->proxy();
1498
            $this->reset = $W->Link(
1499
                $App->translate('Reset'),
1500
                $proxy->resetFilters()
0 ignored issues
show
Bug introduced by
The method resetFilters() does not exist on app_Controller. 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

1500
                $proxy->/** @scrutinizer ignore-call */ 
1501
                        resetFilters()
Loading history...
1501
            )->addClass('icon', Func_Icons::ACTIONS_VIEW_REFRESH, 'widget-actionbutton')
1502
            ->setTitle($App->translate('Reset filter to default values'))
1503
            ->setAjaxAction();
1504
1505
//             $this->save = $W->Link(
1506
//                 $App->translate('Save'),
1507
//                 $proxy->confirmSaveCurrentFilter()
1508
//             )->addClass('icon', Func_Icons::ACTIONS_DOCUMENT_SAVE, 'widget-actionbutton')
1509
//             ->setTitle($App->translate('Save current filter'))
1510
//             ->setOpenMode(Widget_Link::OPEN_DIALOG_AND_RELOAD);
1511
1512
//             $this->select = null;
1513
1514
            $this->filterMenu = $W->Menu(null, $W->VBoxItems());
0 ignored issues
show
Bug Best Practice introduced by
The property filterMenu does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1515
            $this->filterMenu->setButtonClass('widget-actionbutton icon actions-list-filter');
1516
            $this->filterMenu->setButtonLabel($App->translate('Saved filters'));
1517
            $this->filterMenu->addClass(Func_Icons::ICON_LEFT_16);
1518
1519
            $filterNames = $controller->getFilterNames();
1520
            if (count($filterNames) > 0) {
1521
//                 $this->select = $W->Menu(null, $W->VBoxItems());
1522
//                 $this->select->setButtonClass('widget-link icon actions-list-filter');
1523
//                 $this->select->setButtonLabel($App->translate('Saved filters'));
1524
//                 $this->select->addClass(Func_Icons::ICON_LEFT_16);
1525
1526
1527
                foreach ($filterNames as $filterName) {
1528
                    $filter = $W->getUserConfiguration($controller->getModelViewDefaultId() . '/filters/' . $filterName, 'widgets', false);
1529
1530
//                     $this->select->addItem(
1531
//                         $W->Link(
1532
//                             $filterName,
1533
//                             $proxy->setCurrentFilterName($filterName)
1534
//                         )->setTitle($filter['description'])
1535
//                     );
1536
1537
1538
                    $this->filterMenu->addItem(
1539
                        $W->Link(
1540
                            $filterName,
1541
                            $proxy->setCurrentFilterName($filterName)
0 ignored issues
show
Bug introduced by
The method setCurrentFilterName() does not exist on app_Controller. 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

1541
                            $proxy->/** @scrutinizer ignore-call */ 
1542
                                    setCurrentFilterName($filterName)
Loading history...
1542
                        )->setTitle($filter['description'])
1543
                        ->setAjaxAction()
1544
                    );
1545
                }
1546
//                 $this->select->addSeparator();
1547
//                 $this->select->addItem(
1548
//                     $W->Link(
1549
//                         $App->translate('Manage filters'),
1550
//                         $proxy->manageFilters()
1551
//                     )->addClass('icon', Func_Icons::ACTIONS_DOCUMENT_PROPERTIES)
1552
//                     ->setOpenMode(Widget_Link::OPEN_DIALOG_AND_RELOAD)
1553
//                 );
1554
1555
                $this->filterMenu->addSeparator();
1556
                $this->filterMenu->addItem(
1557
                    $W->Link(
1558
                        $App->translate('Manage filters...'),
1559
                        $proxy->manageFilters()
0 ignored issues
show
Bug introduced by
The method manageFilters() does not exist on app_Controller. 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

1559
                        $proxy->/** @scrutinizer ignore-call */ 
1560
                                manageFilters()
Loading history...
1560
                    )->addClass('icon', Func_Icons::ACTIONS_DOCUMENT_PROPERTIES)
1561
                    ->setOpenMode(Widget_Link::OPEN_DIALOG)
1562
                );
1563
                $this->filterMenu->addSeparator();
1564
            }
1565
        }
1566
1567
        $this->filterMenu->addItem(
1568
            $W->Link(
1569
                $App->translate('Save current filter...'),
1570
                $proxy->confirmSaveCurrentFilter()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $proxy does not seem to be defined for all execution paths leading up to this point.
Loading history...
1571
            )->addClass('icon', Func_Icons::ACTIONS_DOCUMENT_SAVE)
1572
            ->setOpenMode(Widget_Link::OPEN_DIALOG)
1573
        );
1574
1575
1576
1577
        $form = $W->Form($id);
1578
        $form->setReadOnly(true);
1579
        $form->setName('filter');
1580
        $form->colon();
1581
1582
        $form->setLayout(
1583
            $W->FlowItems(
1584
                $activeFiltersFrame,
1585
                $W->FlowItems(
1586
                    $advancedFiltersFrame,
1587
                    $this->submit,
1588
                    $W->FlowItems(
1589
                        $this->reset,
1590
                        $this->filterMenu
1591
                    )
1592
//                   $this->save,
1593
//                   $this->select,
1594
                )->setHorizontalSpacing(2, 'em')
1595
                ->setVerticalSpacing(1, 'em')
1596
            )->setVerticalSpacing(1, 'em')
1597
            ->setVerticalAlign('bottom')
1598
            ->addClass(Func_Icons::ICON_LEFT_16)
1599
        );
1600
1601
        $form->setHiddenValue('tg', $App->controllerTg);
1602
        $form->setAnchor($this->getAnchor());
1603
1604
        return $form;
1605
    }
1606
1607
1608
    /**
1609
     * Get a advanced filter panel
1610
     * Use setPageLength to define the default number of items per page
1611
     *
1612
     * @param	array	$filter		Filter values
1613
     * @param	string	$name		filter form name
1614
     * @param	string	$anchor		anchor in destination page of filter, the can be a Widget_Tab id
1615
     *
1616
     * @return Widget_Filter
1617
     */
1618
    public function advancedFilterPanel($filter = null, $name = null)
1619
    {
1620
        $W = bab_Widgets();
1621
1622
        $filterPanel = $W->Filter();
1623
        $filterPanel->setLayout($W->VBoxLayout());
1624
        if (isset($name)) {
1625
            $filterPanel->setName($name);
1626
        }
1627
1628
        $pageLength = $this->getPageLength();
1629
        if (null === $pageLength) {
0 ignored issues
show
introduced by
The condition null === $pageLength is always false.
Loading history...
1630
            $pageLength = 15;
1631
        }
1632
1633
        $pageNumber = $this->getCurrentPage();
1634
        if (null === $pageNumber) {
0 ignored issues
show
introduced by
The condition null === $pageNumber is always false.
Loading history...
1635
            $pageNumber = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $pageNumber is dead and can be removed.
Loading history...
1636
        }
1637
1638
        $this->setPageLength(isset($filter['pageSize']) ? $filter['pageSize'] : $pageLength);
1639
//        $this->setCurrentPage(isset($filter['pageNumber']) ? $filter['pageNumber'] : $pageNumber);
1640
1641
        if (isset($name)) {
1642
            $this->sortParameterName = $name . '[filter][sort]';
1643
        } else {
1644
            $this->sortParameterName = 'filter[sort]';
1645
        }
1646
1647
        if (isset($filter['sort'])) {
1648
            $this->setSortField($filter['sort']);
1649
        } elseif (!isset($this->sortField)) {
1650
1651
            if (method_exists($this, 'getDefaultSortField'))
1652
            {
1653
                $this->setSortField($this->getDefaultSortField());
1654
            } else {
1655
                $columns = $this->getVisibleColumns();
1656
                $sortField = key($columns);
1657
                $this->setSortField($sortField);
1658
            }
1659
        }
1660
1661
        $form = $this->getAdvancedFilterForm(null, $filter);
1662
1663
        if (isset($filter)) {
1664
            if (isset($name)) {
1665
                $path = array($name, 'filter');
1666
            } else {
1667
                $path = array('filter');
1668
            }
1669
            $form->setValues($filter, $path);
1670
        }
1671
1672
        $filterPanel->setFilter($form);
1673
        $filterPanel->setFiltered($this);
1674
1675
1676
        return $filterPanel;
1677
    }
1678
1679
    /**
1680
     * @param app_CtrlRecord $recordController
1681
     * @return app_TableModelView
1682
     */
1683
    public function setRecordController(app_CtrlRecord $recordController)
1684
    {
1685
        $this->recordController = $recordController;
1686
        return $this;
1687
    }
1688
1689
1690
    /**
1691
     * @return app_CtrlRecord
1692
     */
1693
    public function getRecordController()
1694
    {
1695
        return $this->recordController;
1696
    }
1697
1698
1699
1700
    /**
1701
     * @return app_CtrlRecord
1702
     */
1703
    public function getRecordControllerProxy()
1704
    {
1705
        if (!isset($this->recordControllerProxy)) {
1706
            $this->recordControllerProxy = $this->getRecordController()->proxy();
1707
        }
1708
        return $this->recordControllerProxy;
1709
    }
1710
}
1711
1712
/**
1713
 * Creates a specific filter panel containing the table and an auto-generated form.
1714
 *
1715
 * @param Func_App                     $App
1716
 * @param app_TableModelView           $tableview
1717
 * @param Widget_Displayable_Interface $formContent
1718
 * @param array                        $filter
1719
 * @param string                       $name
1720
 * @return Widget_Filter
1721
 */
1722
function app_filteredTableView(Func_App $App, app_TableModelView $tableview, Widget_Displayable_Interface $formContent, $filterValues = null, $name = null)
1723
{
1724
    $W = bab_Widgets();
1725
1726
    $filterPanel = $W->Filter();
1727
    $filterPanel->setLayout($W->VBoxLayout());
1728
    if (isset($name)) {
1729
        $filterPanel->setName($name);
1730
    }
1731
1732
    if (isset($filterValues['pageSize'])) {
1733
        $tableview->setPageLength($filterValues['pageSize']);
1734
    } else if ($tableview->getPageLength() === null) {
0 ignored issues
show
introduced by
The condition $tableview->getPageLength() === null is always false.
Loading history...
1735
        $tableview->setPageLength(12);
1736
    }
1737
1738
    $tableview->setCurrentPage(isset($filterValues['pageNumber']) ? $filterValues['pageNumber'] : 0);
1739
1740
    $tableview->sortParameterName = $name . '[filter][sort]';
1741
1742
    if (isset($filterValues['sort'])) {
1743
        $tableview->setSortField($filterValues['sort']);
1744
    } else {
1745
        $columns = $tableview->getVisibleColumns();
1746
        foreach ($columns as $sort => $column) {
1747
            if ($sortField = $column->getField()) {
0 ignored issues
show
Unused Code introduced by
The assignment to $sortField is dead and can be removed.
Loading history...
1748
                $tableview->setSortField($sort);
1749
                break;
1750
            }
1751
        }
1752
    }
1753
1754
1755
    if ($formContent instanceof Widget_Form) {
1756
        $form = $formContent;
1757
    } else {
1758
        $form = $W->Form()->setLayout($W->VBoxLayout()->setVerticalSpacing(1, 'em'));
1759
        $form->setReadOnly(true);
1760
        $form->setName('filter');
1761
        $form->colon();
1762
        $form->addItem($formContent);
1763
1764
        $form->addItem($W->SubmitButton()->setLabel($App->translate('Filter')));
1765
    }
1766
1767
1768
    if (isset($filterValues) && is_array($filterValues)) {
1769
        $form->setValues($filterValues, array($name, 'filter'));
1770
    }
1771
    $form->setHiddenValue('tg', bab_rp('tg'));
1772
    $form->setHiddenValue('idx', bab_rp('idx'));
1773
1774
    $filterPanel->setFilter($form);
1775
    $filterPanel->setFiltered($tableview);
1776
1777
    return $filterPanel;
1778
}
1779
1780
1781
1782
/**
1783
 * @param string|ORM_Field $field
1784
 * @param string|null $description
1785
 *
1786
 * @return widget_TableModelViewColumn
1787
 */
1788
function app_TableModelViewColumn($field, $description = null)
1789
{
1790
    if (null === $field) {
0 ignored issues
show
introduced by
The condition null === $field is always false.
Loading history...
1791
        return null;
1792
    }
1793
1794
    if (!isset($description) && $field instanceof ORM_Field) {
1795
        $App = $field->getParentSet()->App();
1796
        $description = $App->translate($field->getDescription());
0 ignored issues
show
Bug introduced by
The method translate() does not exist on ORM_Field. It seems like you code against a sub-type of ORM_Field such as ORM_RecordSet. ( Ignorable by Annotation )

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

1796
        /** @scrutinizer ignore-call */ 
1797
        $description = $App->translate($field->getDescription());
Loading history...
1797
    }
1798
1799
    return new widget_TableModelViewColumn($field, $description);
1800
}
1801
1802
1803
class app_RecordView extends app_UiObject
1804
{
1805
    /**
1806
     * @var app_Record
1807
     */
1808
    protected $record = null;
1809
1810
    /**
1811
     * @var app_RecordSet
1812
     */
1813
    protected $recordSet = null;
1814
1815
    /**
1816
     * @var Widget_Section[]
1817
     */
1818
    protected $sections = array();
1819
1820
    protected $view = '';
1821
1822
    /**
1823
     * @var app_CtrlRecord
1824
     */
1825
    protected $recordController = null;
1826
1827
    /**
1828
     * @param Func_App $App
1829
     * @param string $id
1830
     * @param Widget_Layout $layout
1831
     */
1832
    public function __construct(Func_App $App, $id = null, Widget_Layout $layout = null)
1833
    {
1834
        parent::__construct($App);
1835
1836
        if (!isset($layout)) {
1837
            $W = bab_Widgets();
1838
            $layout = $W->Items();
1839
        }
1840
1841
        $this->setInheritedItem($layout);
1842
    }
1843
1844
1845
    /**
1846
     * @param app_Record $record
1847
     * @return self
1848
     */
1849
    public function setRecord(app_Record $record)
1850
    {
1851
        $this->record = $record;
1852
        $this->recordSet = $record->getParentSet();
1853
1854
1855
        return $this;
1856
    }
1857
1858
1859
    /**
1860
     * @param string $view
1861
     * @return self
1862
     */
1863
    public function setView($view)
1864
    {
1865
        $this->view = $view;
1866
        return $this;
1867
    }
1868
1869
1870
    /**
1871
     * @return string
1872
     */
1873
    public function getView()
1874
    {
1875
        return $this->view;
1876
    }
1877
1878
1879
1880
    /**
1881
     * Creates section in the editor.
1882
     * If a section with the same header text (title) was already
1883
     * created it is replaced by an empty section.
1884
     *
1885
     * @param string $headerText
1886
     * @return Widget_Section
1887
     */
1888
    protected function addSection($id, $headerText, $layout = null)
1889
    {
1890
        $W = bab_Widgets();
1891
        if (!isset($layout)) {
1892
            $layout = $W->VBoxLayout()->setVerticalSpacing(1, 'em');
1893
        }
1894
        $this->sections[$id] = $W->Section(
1895
            $headerText,
1896
            $layout
1897
        )->setFoldable(true);
1898
1899
        return $this->sections[$id];
1900
    }
1901
1902
    /**
1903
     * Creates section in the editor.
1904
     * If a section with the same header text (title) was already
1905
     * created it is replaced by an empty section.
1906
     *
1907
     * @param string $headerText
1908
     * @return Widget_Section
1909
     */
1910
    protected function createSection($headerText, $layout = null)
1911
    {
1912
        return $this->addSection($headerText, $headerText, $layout);
1913
    }
1914
1915
1916
    /**
1917
     * Retrieves a section in the editor.
1918
     *
1919
     * @param string $headerText
1920
     * @return Widget_Section
1921
     */
1922
    protected function getSection($id)
1923
    {
1924
        if (!isset($this->sections[$id])) {
1925
            return null;
1926
        }
1927
        return $this->sections[$id];
1928
    }
1929
1930
1931
    /**
1932
     * Returns the list of sections created via createSection().
1933
     *
1934
     * @return Widget_Section[]
1935
     */
1936
    public function getSections()
1937
    {
1938
        return $this->sections;
1939
    }
1940
1941
1942
1943
1944
    /*
1945
     * @param string $textLabel
1946
     * @param mixed $value
1947
     * @return Widget_Layout
1948
     */
1949
    function labelledWidget($textLabel, $value, app_CustomSection $section = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1950
    {
1951
        $W = bab_Widgets();
1952
1953
        if ($value instanceof Widget_Displayable_Interface) {
1954
            $widget = $value;
1955
        } else {
1956
            $widget = $W->Label($value);
1957
        }
1958
1959
        if (isset($section)) {
1960
            if ($textLabel === '__') {
1961
                $fieldLayout = app_CustomSection::FIELDS_LAYOUT_NO_LABEL;
1962
            } else {
1963
                $fieldLayout = $section->fieldsLayout;
1964
            }
1965
            switch ($fieldLayout) {
1966
                case app_CustomSection::FIELDS_LAYOUT_HORIZONTAL_LABEL:
1967
                    return $W->FlowItems(
1968
                        $W->Label($textLabel)->addClass('crm-horizontal-display-label', 'widget-strong')
1969
                            ->setSizePolicy('widget-25pc'),
1970
                        $widget
1971
                    )->addClass('widget-labelled-widget')
1972
                    ->setHorizontalSpacing(1, 'ex')
1973
                    ->setVerticalAlign('top');
1974
1975
                case app_CustomSection::FIELDS_LAYOUT_WIDE_HORIZONTAL_LABEL:
1976
                    return $W->FlowItems(
1977
                        $W->Label($textLabel)->addClass('crm-horizontal-display-label', 'widget-strong')
1978
                            ->setSizePolicy('widget-50pc'),
1979
                        $widget
1980
                    )->addClass('widget-labelled-widget')
1981
                    ->setHorizontalSpacing(1, 'ex')
1982
                    ->setVerticalAlign('top');
1983
1984
                case app_CustomSection::FIELDS_LAYOUT_NO_LABEL:
1985
                    return $widget;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $widget returns the type Widget_Label which is incompatible with the documented return type Widget_Layout.
Loading history...
1986
1987
                case app_CustomSection::FIELDS_LAYOUT_VERTICAL_LABEL:
1988
                default:
1989
                    return $W->LabelledWidget($textLabel, $widget);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $W->LabelledWidget($textLabel, $widget) returns the type Widget_LabelledWidget which is incompatible with the documented return type Widget_Layout.
Loading history...
1990
            }
1991
        }
1992
    }
1993
1994
1995
    function labelledWidgetOptional($textLabel, $displayedValue, $value = null, app_CustomSection $section = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1996
    {
1997
        if (!isset($value)) {
1998
            $value = $displayedValue;
1999
        }
2000
        if (!isset($value) || is_numeric($value) && $value == 0 || is_string($value) && trim($value) == '' || ($value instanceof Widget_Layout && count($value->getItems()) <= 0)) {
2001
            return null;
2002
        }
2003
        return $this->labelledWidget($textLabel, $displayedValue, $section);
2004
    }
2005
2006
2007
2008
    protected function fieldOutput($field, $record, $fieldName)
2009
    {
2010
        if ($field instanceof ORM_CurrencyField) {
2011
            $App = $this->App();
2012
            $value = $App->shortFormatWithUnit($this->record->$fieldName, $App->translate('_euro_'));
2013
        } else {
2014
            $value = $field->output($this->record->$fieldName);
2015
        }
2016
        return $value;
2017
    }
2018
2019
    protected function addSections($view = '')
2020
    {
2021
        $App = $this->App();
2022
        $W = bab_Widgets();
2023
2024
        $objectName = $this->record->getClassName();
2025
2026
        $customSectionSet = $App->CustomSectionSet();
2027
        $customSections = $customSectionSet->select(
2028
            $customSectionSet->object->is($objectName)->_AND_($customSectionSet->view->is($view))
2029
            );
2030
        $customSections->orderAsc($customSectionSet->rank);
2031
2032
        $currentColumn = 0;
2033
        $nbCol = 0;
2034
        $row = $W->Items()->setSizePolicy('row');
2035
        foreach ($customSections as $customSection) {
2036
2037
            if (isset($this->record) && !$customSection->isVisibleForRecord($this->record)) {
2038
                continue;
2039
            }
2040
2041
            list(, , $nbCol) = explode('-', $customSection->sizePolicy);
2042
2043
            if ($currentColumn + $nbCol > 12) {
2044
                $this->addItem($row);
0 ignored issues
show
Bug introduced by
The method addItem() does not exist on app_RecordView. 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

2044
                $this->/** @scrutinizer ignore-call */ 
2045
                       addItem($row);
Loading history...
2045
                $row = $W->Items()->setSizePolicy('row');
2046
                $currentColumn = 0;
2047
            }
2048
            $currentColumn += $nbCol;
2049
2050
            if (strpos($customSection->classname, 'horizontal') !== false) {
2051
                $box = $W->FlowItems()
2052
                    ->setVerticalAlign('top')
2053
                    ->setSpacing(1, 'em');
2054
            } else {
2055
                $box = null;
2056
            }
2057
2058
            $section = $this->getSection($customSection->id);
2059
            if (!isset($section)) {
2060
                $section = $this->addSection($customSection->id, $customSection->name, $box);
2061
                $section->addClass($customSection->classname);
2062
                $section->setSizePolicy($customSection->sizePolicy);
2063
2064
                if ($customSection->editable) {
0 ignored issues
show
Bug Best Practice introduced by
The property editable does not exist on app_CustomSection. Since you implemented __get, consider adding a @property annotation.
Loading history...
2065
                    $menu = $section->addContextMenu('inline');
2066
                    $menu->addClass(Func_Icons::ICON_LEFT_16);
2067
                    $menu->addItem(
2068
                        $W->Link(
2069
                            '',
2070
                            $this->record->getController()->editSection($this->record->id, $customSection->id)
0 ignored issues
show
Bug introduced by
The method editSection() does not exist on app_Controller. 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

2070
                            $this->record->getController()->/** @scrutinizer ignore-call */ editSection($this->record->id, $customSection->id)
Loading history...
2071
                        )->addClass('widget-actionbutton', 'section-button', 'icon', Func_Icons::ACTIONS_DOCUMENT_EDIT)
2072
                        ->setOpenMode(Widget_Link::OPEN_DIALOG)
2073
                    );
2074
                }
2075
2076
                $section->setFoldable($customSection->foldable, $customSection->folded);
2077
                $row->addItem($section);
2078
            }
2079
2080
2081
2082
            $displayFields = $customSection->getFields();
2083
2084
            foreach ($displayFields as $displayField) {
2085
                $item = null;
2086
                $displayFieldName = $displayField['fieldname'];
2087
                $parameters = $displayField['parameters'];
2088
                $classname = isset($parameters['classname']) ? $parameters['classname'] : '';
2089
                $label = isset($parameters['label']) ? $parameters['label'] : null;
2090
                $sizePolicy = isset($parameters['sizePolicy']) ? $parameters['sizePolicy'] : '';
2091
2092
                $displayFieldMethod = '_' . $displayFieldName;
2093
                if (method_exists($this, $displayFieldMethod)) {
2094
                    $item = $this->$displayFieldMethod($customSection, $label);
2095
                } else {
2096
                    try {
2097
                        $field = $this->recordSet->getField($displayFieldName);
2098
                        $value = $this->fieldOutput($field, $this->record, $displayFieldName);
2099
                        if (!isset($label) || empty($label)) {
2100
                            $label = $App->translate($field->getDescription());
2101
                        }
2102
2103
                        $outputWidget = $field->outputWidget($this->record->$displayFieldName);
0 ignored issues
show
Bug introduced by
The method outputWidget() does not exist on ORM_Field. Did you maybe mean output()? ( Ignorable by Annotation )

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

2103
                        /** @scrutinizer ignore-call */ 
2104
                        $outputWidget = $field->outputWidget($this->record->$displayFieldName);

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...
2104
2105
                        $item = $this->labelledWidgetOptional(
2106
                            $label,
2107
                            $outputWidget,
2108
                            $value,
2109
                            $customSection
2110
                        );
2111
                    } catch (ORM_Exception $e) {
2112
                        $item = null;
2113
                    }
2114
                }
2115
                if (isset($item)) {
2116
                    $item->setSizePolicy($sizePolicy);
2117
                    $item->addClass($classname);
2118
                    $section->addItem($item);
2119
                }
2120
            }
2121
        }
2122
2123
        if ($currentColumn + $nbCol> 0) {
2124
            $this->addItem($row);
2125
        }
2126
    }
2127
2128
2129
    protected function __spacer()
2130
    {
2131
        $W = bab_Widgets();
2132
        return $W->Label('')->addClass('spacer');
2133
    }
2134
}
2135
2136
2137
2138
2139
/**
2140
 * A card frame is a frame with contact informations
2141
 *
2142
 */
2143
class app_CardFrame extends app_UiObject // extends Widget_Frame
2144
{
2145
2146
    const IMAGE_WIDTH = 40;
2147
    const IMAGE_HEIGHT = 40;
2148
2149
2150
    const MAPS_URL = '//maps.google.com/?q=%s';
2151
2152
    const MAPS_ROUTE_URL = '//maps.google.com/maps?saddr=%s&daddr=%s';
2153
2154
    const STATIC_MAPS_URL = '//maps.google.com/maps/api/staticmap?';
2155
2156
    /**
2157
     * @var Widget_Section[] $sections
2158
     */
2159
    protected $sections = array();
2160
2161
2162
    protected $menu = null;
2163
2164
2165
2166
2167
2168
    public function __construct(Func_App $App, $id = null, Widget_Layout $layout = null)
2169
    {
2170
        parent::__construct($App);
2171
2172
        $W = bab_Widgets();
2173
2174
        $this->setInheritedItem($W->Frame($id, $layout));
2175
    }
2176
2177
2178
    /**
2179
     * render a labeled string
2180
     *
2181
     * @param	string | Widget_Item	$label
2182
     * @param	string | Widget_Item	$value
2183
     *
2184
     * @return Widget_Item
2185
     */
2186
    protected function labelStr($label, $value)
2187
    {
2188
        $W = bab_Widgets();
2189
2190
        if (!($label instanceOf Widget_Item)) {
2191
            $label = $W->Label($label);
2192
        }
2193
2194
        if (!($value instanceOf Widget_Displayable_Interface)) {
2195
            $value = $W->Label($value);
2196
        }
2197
2198
2199
        return $W->VBoxItems(
2200
            $label->colon(false)->addClass('crm-display-label'),
0 ignored issues
show
Bug introduced by
The method colon() does not exist on Widget_Item. It seems like you code against a sub-type of Widget_Item such as Widget_Title or Widget_SimpleTreeView or Widget_LabelledWidget or Widget_Label or Widget_InputPassword or Widget_Section or Widget_Form. ( Ignorable by Annotation )

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

2200
            $label->/** @scrutinizer ignore-call */ 
2201
                    colon(false)->addClass('crm-display-label'),
Loading history...
2201
            $value->addClass('crm-display-value')
2202
            )->setVerticalAlign('middle')->setVerticalSpacing(3, 'px');
2203
    }
2204
2205
    /**
2206
     * render a labeled string only if value set
2207
     *
2208
     * @param	string | Widget_Item	$label
2209
     * @param	string | Widget_Item	$value
2210
     *
2211
     * @return Widget_Item | null
2212
     */
2213
    protected function labelStrSet($label, $value)
2214
    {
2215
        if (!isset($value) || '' === $value) {
2216
            return null;
2217
        }
2218
2219
        return $this->labelStr($label, $value);
2220
    }
2221
2222
2223
    /**
2224
     * render a labeled string with a field value, if the value is not set, return null
2225
     *
2226
     *
2227
     * @param string $label
2228
     * @param app_Record $record
2229
     * @param ORM_Field $field
2230
     */
2231
    protected function labeledField($label, app_Record $record, ORM_Field $field)
2232
    {
2233
        $W = bab_Widgets();
2234
2235
        $fieldName = $field->getName();
2236
        $value = $record->$fieldName;
2237
2238
        if (!$field->isValueSet($value)) {
2239
            return null;
2240
        }
2241
2242
        $displayable = $field->output($value);
2243
2244
        switch(true) {
2245
            case ($field instanceof ORM_TextField):
2246
                $displayable = $W->RichText($displayable)->setRenderingOptions(BAB_HTML_ALL ^ BAB_HTML_P);
2247
                break;
2248
2249
            case ($field instanceof ORM_UrlField):
2250
                $displayable = $W->Link($displayable, $displayable);
2251
                break;
2252
2253
            case ($field instanceof ORM_EmailField):
2254
                $displayable = $W->Link($displayable, 'mailto:'.$displayable);
2255
                break;
2256
2257
            case ($field instanceof ORM_FkField):
2258
                $record = $record->$fieldName();
2259
                if (!isset($record)) {
2260
                    return null;
2261
                }
2262
                $displayable = $record->getRecordTitle();
2263
                break;
2264
        }
2265
2266
        return $this->labelStr($label, $displayable);
2267
    }
2268
2269
2270
2271
2272
2273
    /**
2274
     * Creates section in the editor.
2275
     * If a section with the same header text (title) was already
2276
     * created it is replaced by an empty section.
2277
     *
2278
     * @param string $headerText
2279
     * @return Widget_Section
2280
     */
2281
    protected function addSection($id, $headerText, $layout = null)
2282
    {
2283
        $W = bab_Widgets();
2284
        if (!isset($layout)) {
2285
            $layout = $W->VBoxLayout()->setVerticalSpacing(1, 'em');
2286
        }
2287
        $this->sections[$id] = $W->Section(
2288
            $headerText,
2289
            $layout
2290
            )->setFoldable(true);
2291
2292
            return $this->sections[$id];
2293
    }
2294
2295
    /**
2296
     * Creates section in the editor.
2297
     * If a section with the same header text (title) was already
2298
     * created it is replaced by an empty section.
2299
     *
2300
     * @param string $headerText
2301
     * @return Widget_Section
2302
     */
2303
    protected function createSection($headerText, $layout = null)
2304
    {
2305
        return $this->addSection($headerText, $headerText, $layout);
2306
    }
2307
2308
2309
    /**
2310
     * Retrieves a section in the editor.
2311
     *
2312
     * @param string $headerText
2313
     * @return Widget_Section
2314
     */
2315
    protected function getSection($id)
2316
    {
2317
        if (!isset($this->sections[$id])) {
2318
            return null;
2319
        }
2320
        return $this->sections[$id];
2321
    }
2322
2323
2324
    /**
2325
     * Returns the list of sections created via createSection().
2326
     *
2327
     * @return Widget_Section[]
2328
     */
2329
    public function getSections()
2330
    {
2331
        return $this->sections;
2332
    }
2333
2334
2335
    /**
2336
     * @param Widget_Displayable_Interface $item
2337
     * @return self
2338
     */
2339
    public function addAction(Widget_Displayable_Interface $item)
2340
    {
2341
        if (!isset($this->menu)) {
2342
            $W = bab_Widgets();
2343
            $this->menu = $W->Menu()
2344
                ->setLayout($W->FlowLayout())
2345
                ->addClass(Func_Icons::ICON_LEFT_SYMBOLIC);
2346
2347
        }
2348
        $this->menu->addItem($item);
2349
        return $this;
2350
    }
2351
}
2352
2353