Completed
Push — master ( d520d9...2d6225 )
by
unknown
12s
created

src/Forms/GridField/GridFieldAddByDBField.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
     * Creates a text field and add button which allows the user to directly create a new
42
     * DataObject by just entering the title.
43
     *
44
     * @param string $targetFragment
45
     * @param string $dataObjectField
46
     */
47
    public function __construct($targetFragment = 'before', $dataObjectField = 'Title')
48
    {
49
        $this->targetFragment = $targetFragment;
50
        $this->dataObjectField = (string) $dataObjectField;
51
    }
52
53
    /**
54
     * Provide actions to this component.
55
     *
56
     * @param GridField $gridField
57
     *
58
     * @return array
59
     */
60
    public function getActions($gridField)
61
    {
62
        return [
63
            'add',
64
        ];
65
    }
66
67
    /**
68
     * Handles the add action for the given DataObject.
69
     *
70
     * @param $gridField GridField
71
     * @param $actionName string
72
     * @param $arguments mixed
73
     * @param $data array
74
     *
75
     * @return null|HTTPResponse
76
     *
77
     * @throws UnexpectedValueException
78
     */
79
    public function handleAction(GridField $gridField, $actionName, $arguments, $data)
80
    {
81
        if ($actionName == 'add') {
82
            $dbField = $this->getDataObjectField();
83
84
            $objClass = $gridField->getModelClass();
85
86
            /**
87
             * @var DataObject $obj
88
             */
89
            $obj = $objClass::create();
90
91
            if ($obj->hasField($dbField)) {
92
                $obj->setCastedField($dbField, $data['gridfieldaddbydbfield'][$obj->ClassName][$dbField]);
93
94
                if ($obj->canCreate()) {
95
                    $id = $gridField->getList()->add($obj);
96
                    if (!$id) {
97
                        $gridField->setCustomValidationMessage(
98
                            _t(
99
                                __CLASS__ . '.AddFail',
100
                                'Unable to save {class} to the database.',
101
                                'Unable to add the DataObject.',
102
                                [
103
                                    'class' => get_class($obj),
104
                                ]
105
                            )
106
                        );
107
                    }
108
                } else {
109
                    return Security::permissionFailure(
110
                        Controller::curr(),
111
                        _t(
112
                            __CLASS__ . '.PermissionFail',
113
                            'You don\'t have permission to create a {class}.',
114
                            'Unable to add the DataObject.',
115
                            [
116
                                'class' => get_class($obj)
117
                            ]
118
                        )
119
                    );
120
                }
121
            } else {
122
                throw new UnexpectedValueException(
123
                    sprintf(
124
                        'Invalid field (%s) on %s.',
125
                        $dbField,
126
                        $obj->ClassName
127
                    )
128
                );
129
            }
130
        }
131
132
        return null;
133
    }
134
135
    /**
136
     * Returns the database field for which we'll add the new data object.
137
     *
138
     * @return string
139
     */
140
    public function getDataObjectField()
141
    {
142
        return $this->dataObjectField;
143
    }
144
145
    /**
146
     * Set the database field.
147
     *
148
     * @param $field string
149
     */
150
    public function setDataObjectField($field)
151
    {
152
        $this->dataObjectField = (string) $field;
153
    }
154
155
    /**
156
     * Renders the TextField and add button to the GridField.
157
     *
158
     * @param $gridField GridField
159
     *
160
     * @return string[]
161
     */
162
    public function getHTMLFragments($gridField)
163
    {
164
        Requirements::javascript('silverstripe/blog:client/dist/js/main.bundle.js');
165
166
        /**
167
         * @var DataList $dataList
168
         */
169
        $dataList = $gridField->getList();
170
171
        $dataClass = $dataList->dataClass();
172
173
        $obj = singleton($dataClass);
174
175
        if (!$obj->canCreate()) {
176
            return [];
177
        }
178
179
        $dbField = $this->getDataObjectField();
180
181
        $textField = TextField::create(
182
            sprintf(
183
                "gridfieldaddbydbfield[%s][%s]",
184
                $obj->ClassName,
185
                Convert::raw2htmlatt($dbField)
186
            )
187
        )
188
            ->setAttribute('placeholder', $obj->fieldLabel($dbField))
189
            ->addExtraClass('no-change-track');
190
191
        $addAction = GridField_FormAction::create(
192
            $gridField,
193
            'add',
194
            _t(
195
                __CLASS__ . '.Add',
196
                'Add {name}',
197
                'Add button text',
198
                ['name' => $obj->i18n_singular_name()]
199
            ),
200
            'add',
201
            'add'
202
        );
203
        $addAction->setAttribute('data-icon', 'add');
204
        $addAction->addExtraClass('btn btn-primary');
205
206
        $forTemplate = ArrayData::create([]);
207
208
        $forTemplate->Fields = ArrayList::create();
209
        $forTemplate->Fields->push($textField);
210
        $forTemplate->Fields->push($addAction);
211
212
        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...
213
    }
214
}
215