Completed
Push — master ( 1399b0...3c5b2b )
by
unknown
01:29
created

GridFieldAddByDBField::getHTMLFragments()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 58
rs 8.9163
c 0
b 0
f 0
cc 3
nc 3
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
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
                    $id = $gridField->getList()->add($obj);
103
                    if (!$id) {
104
                        $gridField->setCustomValidationMessage(
105
                            _t(
106
                                __CLASS__ . '.AddFail',
107
                                'Unable to save {class} to the database.',
108
                                'Unable to add the DataObject.',
109
                                [
110
                                    'class' => get_class($obj),
111
                                ]
112
                            )
113
                        );
114
                    }
115
                } else {
116
                    return Security::permissionFailure(
117
                        Controller::curr(),
118
                        _t(
119
                            __CLASS__ . '.PermissionFail',
120
                            'You don\'t have permission to create a {class}.',
121
                            'Unable to add the DataObject.',
122
                            [
123
                                'class' => get_class($obj)
124
                            ]
125
                        )
126
                    );
127
                }
128
            } else {
129
                throw new UnexpectedValueException(
130
                    sprintf(
131
                        'Invalid field (%s) on %s.',
132
                        $dbField,
133
                        $obj->ClassName
134
                    )
135
                );
136
            }
137
        }
138
139
        return null;
140
    }
141
142
    /**
143
     * Returns the database field for which we'll add the new data object.
144
     *
145
     * @return string
146
     */
147
    public function getDataObjectField()
148
    {
149
        return $this->dataObjectField;
150
    }
151
152
    /**
153
     * Set the button name
154
     *
155
     * @param $name string
156
     * @return $this
157
     */
158
    public function setButtonName($name)
159
    {
160
        $this->buttonName = $name;
161
162
        return $this;
163
    }
164
165
    /**
166
     * Set the database field.
167
     *
168
     * @param $field string
169
     */
170
    public function setDataObjectField($field)
171
    {
172
        $this->dataObjectField = (string) $field;
173
    }
174
175
    /**
176
     * Renders the TextField and add button to the GridField.
177
     *
178
     * @param $gridField GridField
179
     *
180
     * @return string[]
181
     */
182
    public function getHTMLFragments($gridField)
183
    {
184
        Requirements::javascript('silverstripe/blog:client/dist/js/main.bundle.js');
185
186
        /**
187
         * @var DataList $dataList
188
         */
189
        $dataList = $gridField->getList();
190
191
        $dataClass = $dataList->dataClass();
192
193
        $obj = singleton($dataClass);
194
195
        if (!$obj->canCreate()) {
196
            return [];
197
        }
198
199
        $dbField = $this->getDataObjectField();
200
201
        $textField = TextField::create(
202
            sprintf(
203
                "gridfieldaddbydbfield[%s][%s]",
204
                $obj->ClassName,
205
                Convert::raw2htmlatt($dbField)
206
            )
207
        )
208
            ->setAttribute('placeholder', $obj->fieldLabel($dbField))
209
            ->addExtraClass('no-change-track');
210
211
        if (!$this->buttonName) {
212
            // provide a default button name, can be changed by calling {@link setButtonName()} on this component
213
            $objectName = $obj->i18n_singular_name();
214
            $this->buttonName = _t(__CLASS__ . '.ButtonName', '{name}', ['name' => $objectName]);
215
        }
216
217
        $addAction = GridField_FormAction::create(
218
            $gridField,
219
            'add',
220
            _t(
221
                __CLASS__ . '.Add',
222
                'Add {name}',
223
                'Add button text',
224
                ['name' => $this->buttonName]
225
            ),
226
            'add',
227
            'add'
228
        );
229
        $addAction->setAttribute('data-icon', 'add');
230
        $addAction->addExtraClass('btn btn-primary');
231
232
        $forTemplate = ArrayData::create([]);
233
234
        $forTemplate->Fields = ArrayList::create();
235
        $forTemplate->Fields->push($textField);
236
        $forTemplate->Fields->push($addAction);
237
238
        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...
239
    }
240
}
241