WidgetAreaEditor   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 36
eloc 72
c 2
b 0
f 0
dl 0
loc 178
rs 9.52

7 Methods

Rating   Name   Duplication   Size   Complexity  
A IdxField() 0 3 1
A __construct() 0 6 1
A Value() 0 5 1
A UsedWidgets() 0 9 1
B AvailableWidgets() 0 27 9
D saveInto() 0 80 22
A FieldHolder() 0 6 1
1
<?php
2
3
namespace SilverStripe\Widgets\Forms;
4
5
use Exception;
6
use SilverStripe\Core\ClassInfo;
7
use SilverStripe\Core\Config\Config;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Forms\FormField;
10
use SilverStripe\ORM\ArrayList;
11
use SilverStripe\ORM\DataObjectInterface;
12
use SilverStripe\View\Requirements;
13
use SilverStripe\Widgets\Model\Widget;
14
15
/**
16
 * Special field type for selecting and configuring widgets on a page.
17
 *
18
 * @package widgets
19
 */
20
class WidgetAreaEditor extends FormField
21
{
22
    /**
23
     * @param string $name
24
     * @param array $widgetClasses
25
     * @param int $maxWidgets
26
     */
27
    public function __construct($name, $widgetClasses = array(Widget::class), $maxWidgets = 0)
28
    {
29
        $this->MaxWidgets = $maxWidgets;
0 ignored issues
show
Bug Best Practice introduced by
The property MaxWidgets does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
30
        $this->widgetClasses = $widgetClasses;
0 ignored issues
show
Bug Best Practice introduced by
The property widgetClasses does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
31
32
        parent::__construct($name);
33
    }
34
35
    /**
36
     * @param array $properties
37
     *
38
     * @return string - HTML
39
     */
40
    public function FieldHolder($properties = array())
41
    {
42
        Requirements::css('silverstripe/widgets:css/WidgetAreaEditor.css');
43
        Requirements::javascript('silverstripe/widgets:javascript/WidgetAreaEditor.js');
44
45
        return $this->renderWith(WidgetAreaEditor::class);
46
    }
47
48
    /**
49
     *
50
     * @return ArrayList
51
     */
52
    public function AvailableWidgets()
53
    {
54
        $widgets= new ArrayList();
55
56
        foreach ($this->widgetClasses as $widgetClass) {
57
            $classes = ClassInfo::subclassesFor($widgetClass);
58
59
            if (isset($classes[strtolower(Widget::class)])) {
60
                unset($classes[strtolower(Widget::class)]);
61
            } elseif (isset($classes[0]) && $classes[0] == Widget::class) {
62
                unset($classes[0]);
63
            }
64
65
            foreach ($classes as $class) {
66
                $available = Config::inst()->get($class, 'only_available_in');
67
68
                if (!empty($available) && is_array($available)) {
69
                    if (in_array($this->Name, $available)) {
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\Widgets\Forms\WidgetAreaEditor. Since you implemented __get, consider adding a @property annotation.
Loading history...
70
                        $widgets->push(singleton($class));
71
                    }
72
                } else {
73
                    $widgets->push(singleton($class));
74
                }
75
            }
76
        }
77
78
        return $widgets;
79
    }
80
81
    /**
82
     * @return HasManyList
0 ignored issues
show
Bug introduced by
The type SilverStripe\Widgets\Forms\HasManyList 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...
83
     */
84
    public function UsedWidgets()
85
    {
86
        // Call class_exists() to load Widget.php earlier and avoid a segfault
87
        class_exists(Widget::class);
88
89
        $relationName = $this->name;
90
        $widgets = $this->form->getRecord()->getComponent($relationName)->Items();
91
92
        return $widgets;
93
    }
94
95
    /**
96
     * @return string
97
     */
98
    public function IdxField()
99
    {
100
        return $this->id() . 'ID';
101
    }
102
103
    /**
104
     *
105
     * @return int
106
     */
107
    public function Value()
108
    {
109
        $relationName = $this->name;
110
111
        return $this->form->getRecord()->getComponent($relationName)->ID;
112
    }
113
114
    /**
115
     * @param DataObjectInterface $record
116
     * @throws Exception if no form could be retrieved
117
     */
118
    public function saveInto(DataObjectInterface $record)
119
    {
120
        $name = $this->name;
121
        $idName = $name . "ID";
122
123
        $widgetarea = $record->getComponent($name);
124
        $widgetarea->write();
125
126
        $record->$idName = $widgetarea->ID;
127
128
        $widgets = $widgetarea->Items();
129
130
        // store the field IDs and delete the missing fields
131
        // alternatively, we could delete all the fields and re add them
132
        $missingWidgets = array();
133
134
        if ($widgets) {
135
            foreach ($widgets as $existingWidget) {
136
                $missingWidgets[$existingWidget->ID] = $existingWidget;
137
            }
138
        }
139
140
        if (!$this->getForm()) {
141
            throw new Exception("no form");
142
        }
143
144
        $widgetData = $this->getForm()->getController()->getRequest()->requestVar('Widget');
145
        if ($widgetData && isset($widgetData[$this->getName()])) {
146
            $widgetAreaData = $widgetData[$this->getName()];
147
148
            foreach ($widgetAreaData as $newWidgetID => $newWidgetData) {
149
                // Sometimes the id is "new-1" or similar, ensure this doesn't get into the query
150
                if (!is_numeric($newWidgetID)) {
151
                    $newWidgetID = 0;
152
                }
153
154
                $widget = null;
155
                if ($newWidgetID) {
156
                    // \"ParentID\" = '0' is for the new page
157
                    $widget = Widget::get()
158
                        ->filter('ParentID', array(0, $record->$name()->ID))
159
                        ->byID($newWidgetID);
160
161
                    // check if we are updating an existing widget
162
                    if ($widget && isset($missingWidgets[$widget->ID])) {
163
                        unset($missingWidgets[$widget->ID]);
164
                    }
165
                }
166
167
                // unsantise the class name
168
                if (empty($newWidgetData['Type'])) {
169
                    $newWidgetData['Type'] = '';
170
                }
171
                $newWidgetData['Type'] = str_replace('_', '\\', $newWidgetData['Type']);
172
173
                // create a new object
174
                if (!$widget
175
                    && !empty($newWidgetData['Type'])
176
                    && class_exists($newWidgetData['Type'])
177
                    && is_subclass_of($newWidgetData['Type'], Widget::class)
178
                ) {
179
                    $widget = Injector::inst()->create($newWidgetData['Type']);
180
                    $widget->ID = 0;
181
                    $widget->ParentID = $record->$name()->ID;
182
                }
183
184
                if ($widget) {
185
                    if ($widget->ParentID == 0) {
186
                        $widget->ParentID = $record->$name()->ID;
187
                    }
188
                    $widget->populateFromPostData($newWidgetData);
189
                }
190
            }
191
        }
192
193
        // remove the fields not saved
194
        if ($missingWidgets) {
195
            foreach ($missingWidgets as $removedWidget) {
196
                if (isset($removedWidget) && is_numeric($removedWidget->ID)) {
197
                    $removedWidget->delete();
198
                }
199
            }
200
        }
201
    }
202
}
203