GridFieldAddByDBField   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 220
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 13
dl 0
loc 220
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getActions() 0 6 1
B handleAction() 0 56 5
A getDataObjectField() 0 4 1
A setButtonName() 0 6 1
A setDataObjectField() 0 4 1
B getHTMLFragments() 0 58 3
1
<?php
2
3
namespace SilverStripe\Blog\Forms\GridField;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Control\HTTPResponse;
7
use SilverStripe\Core\Convert;
8
use SilverStripe\Core\Injector\Injectable;
9
use SilverStripe\Forms\GridField\GridField;
10
use SilverStripe\Forms\GridField\GridField_ActionProvider;
11
use SilverStripe\Forms\GridField\GridField_FormAction;
12
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
13
use SilverStripe\Forms\TextField;
14
use SilverStripe\ORM\ArrayList;
15
use SilverStripe\ORM\DataList;
16
use SilverStripe\ORM\DataObject;
17
use SilverStripe\Security\Security;
18
use SilverStripe\View\ArrayData;
19
use SilverStripe\View\Requirements;
20
use UnexpectedValueException;
21
22
class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLProvider
23
{
24
    use Injectable;
25
26
    /**
27
     * HTML Fragment to render the field.
28
     *
29
     * @var string
30
     */
31
    protected $targetFragment;
32
33
    /**
34
     * Default field to create the DataObject by should be Title.
35
     *
36
     * @var string
37
     */
38
    protected $dataObjectField = 'Title';
39
40
    /**
41
     * Name for the buttons displayed in the CMS
42
     *
43
     * @var string
44
     */
45
    protected $buttonName;
46
47
    /**
48
     * Creates a text field and add button which allows the user to directly create a new
49
     * DataObject by just entering the title.
50
     *
51
     * @param string $targetFragment
52
     * @param string $dataObjectField
53
     */
54
    public function __construct($targetFragment = 'before', $dataObjectField = 'Title')
55
    {
56
        $this->targetFragment = $targetFragment;
57
        $this->dataObjectField = (string) $dataObjectField;
58
    }
59
60
    /**
61
     * Provide actions to this component.
62
     *
63
     * @param GridField $gridField
64
     *
65
     * @return array
66
     */
67
    public function getActions($gridField)
68
    {
69
        return [
70
            'add',
71
        ];
72
    }
73
74
    /**
75
     * Handles the add action for the given DataObject.
76
     *
77
     * @param $gridField GridField
78
     * @param $actionName string
79
     * @param $arguments mixed
80
     * @param $data array
81
     *
82
     * @return null|HTTPResponse
83
     *
84
     * @throws UnexpectedValueException
85
     */
86
    public function handleAction(GridField $gridField, $actionName, $arguments, $data)
87
    {
88
        if ($actionName == 'add') {
89
            $dbField = $this->getDataObjectField();
90
91
            $objClass = $gridField->getModelClass();
92
93
            /**
94
             * @var DataObject $obj
95
             */
96
            $obj = $objClass::create();
97
98
            if ($obj->hasField($dbField)) {
99
                $obj->setCastedField($dbField, $data['gridfieldaddbydbfield'][$obj->ClassName][$dbField]);
100
101
                if ($obj->canCreate()) {
102
                    $obj->write();
103
                    $id = $gridField->getList()->add($obj);
104
                    if (!$id) {
105
                        $gridField->setCustomValidationMessage(
106
                            _t(
107
                                __CLASS__ . '.AddFail',
108
                                'Unable to save {class} to the database.',
109
                                'Unable to add the DataObject.',
110
                                [
111
                                    'class' => get_class($obj),
112
                                ]
113
                            )
114
                        );
115
                    }
116
                } else {
117
                    return Security::permissionFailure(
118
                        Controller::curr(),
119
                        _t(
120
                            __CLASS__ . '.PermissionFail',
121
                            'You don\'t have permission to create a {class}.',
122
                            'Unable to add the DataObject.',
123
                            [
124
                                'class' => get_class($obj)
125
                            ]
126
                        )
127
                    );
128
                }
129
            } else {
130
                throw new UnexpectedValueException(
131
                    sprintf(
132
                        'Invalid field (%s) on %s.',
133
                        $dbField,
134
                        $obj->ClassName
135
                    )
136
                );
137
            }
138
        }
139
140
        return null;
141
    }
142
143
    /**
144
     * Returns the database field for which we'll add the new data object.
145
     *
146
     * @return string
147
     */
148
    public function getDataObjectField()
149
    {
150
        return $this->dataObjectField;
151
    }
152
153
    /**
154
     * Set the button name
155
     *
156
     * @param $name string
157
     * @return $this
158
     */
159
    public function setButtonName($name)
160
    {
161
        $this->buttonName = $name;
162
163
        return $this;
164
    }
165
166
    /**
167
     * Set the database field.
168
     *
169
     * @param $field string
170
     */
171
    public function setDataObjectField($field)
172
    {
173
        $this->dataObjectField = (string) $field;
174
    }
175
176
    /**
177
     * Renders the TextField and add button to the GridField.
178
     *
179
     * @param $gridField GridField
180
     *
181
     * @return string[]
182
     */
183
    public function getHTMLFragments($gridField)
184
    {
185
        Requirements::javascript('silverstripe/blog:client/dist/js/main.bundle.js');
186
187
        /**
188
         * @var DataList $dataList
189
         */
190
        $dataList = $gridField->getList();
191
192
        $dataClass = $dataList->dataClass();
193
194
        $obj = singleton($dataClass);
195
196
        if (!$obj->canCreate()) {
197
            return [];
198
        }
199
200
        $dbField = $this->getDataObjectField();
201
202
        $textField = TextField::create(
203
            sprintf(
204
                "gridfieldaddbydbfield[%s][%s]",
205
                $obj->ClassName,
206
                Convert::raw2htmlatt($dbField)
207
            )
208
        )
209
            ->setAttribute('placeholder', $obj->fieldLabel($dbField))
210
            ->addExtraClass('no-change-track');
211
212
        if (!$this->buttonName) {
213
            // provide a default button name, can be changed by calling {@link setButtonName()} on this component
214
            $objectName = $obj->i18n_singular_name();
215
            $this->buttonName = _t(__CLASS__ . '.ButtonName', '{name}', ['name' => $objectName]);
216
        }
217
218
        $addAction = GridField_FormAction::create(
219
            $gridField,
220
            'add',
221
            _t(
222
                __CLASS__ . '.Add',
223
                'Add {name}',
224
                'Add button text',
225
                ['name' => $this->buttonName]
226
            ),
227
            'add',
228
            'add'
229
        );
230
        $addAction->setAttribute('data-icon', 'add');
231
        $addAction->addExtraClass('btn btn-primary');
232
233
        $forTemplate = ArrayData::create([]);
234
235
        $forTemplate->Fields = ArrayList::create();
236
        $forTemplate->Fields->push($textField);
237
        $forTemplate->Fields->push($addAction);
238
239
        return [$this->targetFragment => $forTemplate->renderWith(self::class)];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array($this->targ...nderWith(self::class)); (array<string,SilverStrip...M\FieldType\DBHTMLText>) is incompatible with the return type documented by SilverStripe\Blog\Forms\...Field::getHTMLFragments of type string[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
240
    }
241
}
242