Completed
Push — master ( f3b14d...1fe4c3 )
by Damian
10s
created

Widget   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 286
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 30
lcom 1
cbo 8
dl 0
loc 286
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A populateDefaults() 0 5 1
A WidgetHolder() 0 4 1
A forTemplate() 0 8 2
A Content() 0 4 1
A getTitle() 0 5 2
A getCMSTitle() 0 4 1
A getDescription() 0 4 1
A DescriptionSegment() 0 4 1
A EditableSegment() 0 4 1
A getCMSFields() 0 10 1
B CMSEditor() 0 28 4
A ClassName() 0 4 1
A Name() 0 4 1
B getController() 0 21 5
C populateFromPostData() 0 28 7
1
<?php
2
3
namespace SilverStripe\Widgets\Model;
4
5
use Exception;
6
use SilverStripe\Core\ClassInfo;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Forms\CheckboxField;
9
use SilverStripe\Forms\FieldList;
10
use SilverStripe\Forms\HiddenField;
11
use SilverStripe\Forms\TextField;
12
use SilverStripe\ORM\DataObject;
13
use SilverStripe\Widgets\Model\WidgetArea;
14
15
/**
16
 * Widgets let CMS authors drag and drop small pieces of functionality into
17
 * defined areas of their websites.
18
 *
19
 * You can use forms in widgets by implementing a {@link WidgetController}.
20
 *
21
 * See {@link WidgetController} for more information.
22
 *
23
 * @package widgets
24
 */
25
class Widget extends DataObject
26
{
27
    /**
28
     * @var array
29
     */
30
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
31
        "Title" => "Varchar(255)",
32
        "Sort" => "Int",
33
        "Enabled" => "Boolean",
34
    );
35
36
    /**
37
     * @var array
38
     */
39
    private static $defaults = array(
0 ignored issues
show
Unused Code introduced by
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
40
        'Enabled' => true,
41
    );
42
43
    /**
44
     * @var array
45
     */
46
    private static $casting = array(
0 ignored issues
show
Unused Code introduced by
The property $casting is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
47
        'CMSTitle' => 'Text',
48
        'Description' => 'Text',
49
    );
50
51
    private static $only_available_in = array();
0 ignored issues
show
Unused Code introduced by
The property $only_available_in is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
52
53
    /**
54
     * @var array
55
     */
56
    private static $has_one = array(
0 ignored issues
show
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
57
        "Parent" => WidgetArea::class,
58
    );
59
60
    /**
61
     * @var string
62
     */
63
    private static $default_sort = "\"Sort\"";
0 ignored issues
show
Unused Code introduced by
The property $default_sort is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
64
65
    /**
66
     * @var string
67
     */
68
    private static $title = "Widget Title";
0 ignored issues
show
Unused Code introduced by
The property $title is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
69
70
    /**
71
     * @var string
72
     */
73
    private static $cmsTitle = "Name of this widget";
0 ignored issues
show
Unused Code introduced by
The property $cmsTitle is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
74
75
    /**
76
     * @var string
77
     */
78
    private static $description = "Description of what this widget does.";
0 ignored issues
show
Unused Code introduced by
The property $description is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
79
80
    /**
81
     * @var array
82
     */
83
    private static $summary_fields = array(
0 ignored issues
show
Unused Code introduced by
The property $summary_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
84
        'CMSTitle' => 'Title'
85
    );
86
87
    /**
88
     * @var string
89
     */
90
    private static $table_name = 'Widget';
0 ignored issues
show
Unused Code introduced by
The property $table_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
91
92
    /**
93
     * @var WidgetController
94
     */
95
    protected $controller;
96
97
    public function populateDefaults()
98
    {
99
        parent::populateDefaults();
100
        $this->setField('Title', $this->getTitle());
101
    }
102
103
    /**
104
     * Note: Overloaded in {@link WidgetController}.
105
     *
106
     * @return string HTML
107
     */
108
    public function WidgetHolder()
109
    {
110
        return $this->renderWith("WidgetHolder");
111
    }
112
113
    /**
114
     * Default way to render widget in templates.
115
     * @return string HTML
116
     */
117
    public function forTemplate($holder = true)
118
    {
119
        if ($holder) {
120
            return $this->WidgetHolder();
121
        }
122
123
        return $this->Content();
124
    }
125
126
    /**
127
     * Renders the widget content in a custom template with the same name as the
128
     * current class. This should be the main point of output customization.
129
     *
130
     * Invoked from within WidgetHolder.ss, which contains the "framing" around
131
     * the custom content, like a title.
132
     *
133
     * Note: Overloaded in {@link WidgetController}.
134
     *
135
     * @return string HTML
136
     */
137
    public function Content()
138
    {
139
        return $this->renderWith(array_reverse(ClassInfo::ancestry($this->class)));
140
    }
141
142
    /**
143
     * Get the frontend title for this widget
144
     *
145
     * @return string
146
     */
147
    public function getTitle()
148
    {
149
        return $this->getField('Title')
150
            ?: _t($this->class . '.TITLE', $this->config()->title);
151
    }
152
153
    /**
154
     * @return string
155
     */
156
    public function getCMSTitle()
157
    {
158
        return _t($this->class . '.CMSTITLE', $this->config()->cmsTitle);
159
    }
160
161
    /**
162
     * @return string
163
     */
164
    public function getDescription()
165
    {
166
        return _t($this->class . '.DESCRIPTION', $this->config()->description);
167
    }
168
169
    /**
170
     * @return string - HTML
171
     */
172
    public function DescriptionSegment()
173
    {
174
        return $this->renderWith('WidgetDescription');
175
    }
176
177
    /**
178
     * @see WidgetController::editablesegment()
179
     *
180
     * @return string - HTML
181
     */
182
    public function EditableSegment()
183
    {
184
        return $this->renderWith('WidgetEditor');
185
    }
186
187
    /**
188
     * @return FieldList
189
     */
190
    public function getCMSFields()
191
    {
192
        $fields = new FieldList(
193
            new TextField('Title', $this->fieldLabel('Title'), null, 255),
194
            new CheckboxField('Enabled', $this->fieldLabel('Enabled'))
195
        );
196
        $this->extend('updateCMSFields', $fields);
197
198
        return $fields;
199
    }
200
201
    /**
202
     * @return FieldList
203
     */
204
    public function CMSEditor()
205
    {
206
        $fields = $this->getCMSFields();
207
        $outputFields = new FieldList();
208
209
        $this->FormID = $this->ID ?: uniqid();
0 ignored issues
show
Documentation introduced by
The property FormID does not exist on object<SilverStripe\Widgets\Model\Widget>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
210
        $outputFields->push(
211
            HiddenField::create(
212
                'Widget[' . $this->FormID . '][FormID]',
0 ignored issues
show
Documentation introduced by
The property FormID does not exist on object<SilverStripe\Widgets\Model\Widget>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
213
                'FormID',
214
                $this->FormID
0 ignored issues
show
Documentation introduced by
The property FormID does not exist on object<SilverStripe\Widgets\Model\Widget>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
215
            )->addExtraClass('formid')
216
        );
217
218
        foreach ($fields as $field) {
219
            $name = $field->getName();
220
            $value = $this->getField($name);
221
            if ($value) {
222
                $field->setValue($value);
223
            }
224
            $namefiltered = preg_replace("/([A-Za-z0-9\-_]+)/", "Widget[" . $this->FormID . "][\\1]", $name);
0 ignored issues
show
Documentation introduced by
The property FormID does not exist on object<SilverStripe\Widgets\Model\Widget>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
225
226
            $field->setName($namefiltered);
227
            $outputFields->push($field);
228
        }
229
230
        return $outputFields;
231
    }
232
233
    /**
234
     * A fully qualified class name is returned with underscores instead of backslashes so it is HTML safe. Dashes
235
     * can't be used as they're handled in the Javascript for other purposes.
236
     *
237
     * @return string
238
     */
239
    public function ClassName()
240
    {
241
        return str_replace('\\', '_', $this->class);
242
    }
243
244
    /**
245
     * @return string
246
     */
247
    public function Name()
248
    {
249
        return "Widget[" . $this->ID . "]";
250
    }
251
252
    /**
253
     * @throws Exception
254
     *
255
     * @return WidgetController
256
     */
257
    public function getController()
258
    {
259
        if ($this->controller) {
260
            return $this->controller;
261
        }
262
263
        foreach (array_reverse(ClassInfo::ancestry($this->class)) as $widgetClass) {
264
            $controllerClass = "{$widgetClass}Controller";
265
            if (class_exists($controllerClass)) {
266
                break;
267
            }
268
        }
269
270
        if (!class_exists($controllerClass)) {
0 ignored issues
show
Bug introduced by
The variable $controllerClass does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
271
            throw new Exception("Could not find controller class for $this->classname");
0 ignored issues
show
Bug introduced by
The property classname does not seem to exist. Did you mean ClassName?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
272
        }
273
274
        $this->controller = Injector::inst()->create($controllerClass, $this);
275
276
        return $this->controller;
277
    }
278
279
    /**
280
     * @param array $data
281
     */
282
    public function populateFromPostData($data)
283
    {
284
        $fields = $this->getCMSFields();
285
        foreach ($data as $name => $value) {
286
            if ($name != "Type") {
287
                if ($field = $fields->dataFieldByName($name)) {
288
                    $field->setValue($value);
289
                    $field->saveInto($this);
290
                } else {
291
                    $this->setField($name, $value);
292
                }
293
            }
294
        }
295
296
        //Look for checkbox fields not present in the data
297
        foreach ($fields as $field) {
298
            if ($field instanceof CheckboxField && !array_key_exists($field->getName(), $data)) {
299
                $field->setValue(false);
300
                $field->saveInto($this);
301
            }
302
        }
303
304
        $this->write();
305
306
        // The field must be written to ensure a unique ID.
307
        $this->Name = $this->class . $this->ID;
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<SilverStripe\Widgets\Model\Widget>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
308
        $this->write();
309
    }
310
}
311