GridField   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 282
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 2 Features 1
Metric Value
eloc 73
c 6
b 2
f 1
dl 0
loc 282
ccs 88
cts 88
cp 1
rs 10
wmc 23

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getDataClass() 0 3 1
A __construct() 0 27 1
A getSessionName() 0 7 1
A setValueHolderField() 0 5 1
A setOwner() 0 5 1
A storeRelationInSession() 0 10 1
A formatSessionName() 0 3 1
A setEmptyString() 0 5 1
A setFieldFormatting() 0 12 1
A getManipulatedList() 0 7 1
A loadRelationFromSession() 0 14 3
A getOptionalTableBody() 0 16 2
A getOwner() 0 3 1
A setDisplayFields() 0 12 1
A setDataClass() 0 5 1
A getRecord() 0 3 1
A getRelationName() 0 3 1
A getList() 0 10 1
A setRecord() 0 9 2
1
<?php
2
3
namespace Moo\HasOneSelector\Form;
4
5
use Exception;
6
use Moo\HasOneSelector\ORM\DataList;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Forms\FormField;
9
use SilverStripe\Forms\GridField\GridField as SSGridField;
10
use SilverStripe\Forms\GridField\GridField_ActionMenu;
11
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
12
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
13
use SilverStripe\Forms\GridField\GridFieldButtonRow;
14
use SilverStripe\Forms\GridField\GridFieldConfig;
15
use SilverStripe\Forms\GridField\GridFieldDataColumns;
16
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
17
use SilverStripe\Forms\GridField\GridFieldDetailForm;
18
use SilverStripe\Forms\GridField\GridFieldEditButton;
19
use SilverStripe\ORM\DataObject;
20
use SilverStripe\ORM\SS_List;
21
use SilverStripe\View\Requirements;
22
23
/**
24
 * Class GridField instance of grid field.
25
 */
26
class GridField extends SSGridField
27
{
28
    /**
29
     * Name of the list data class.
30
     */
31
    protected string $dataClass = '';
32
33
    /**
34
     * Instance of data object that contains the has one relation.
35
     */
36
    protected ?DataObject $owner = null;
37
38
    /**
39
     * Text to display when no record selected.
40
     */
41
    protected string $emptyString = 'No item selected';
42
43
    /**
44
     * Instance of form field that holds the value.
45
     */
46
    protected ?FormField $valueField = null;
47
48
    /**
49
     * HasOneSelector GridField constructor.
50
     */
51 8
    public function __construct(string $name, string $title, DataObject $owner, string $dataClass = DataObject::class)
52
    {
53
        // Include styles
54 8
        Requirements::css('moo/hasoneselector:client/styles/hasoneselector.css');
55
56
        // Initiate grid field configuration based on relation editor
57 8
        $config = new GridFieldConfig();
58 8
        $config->addComponent(new GridFieldButtonRow('before'));
59 8
        $config->addComponent(new GridFieldAddNewButton('buttons-before-left'));
60 8
        $config->addComponent(new GridFieldAddExistingAutocompleter('buttons-before-right'));
61 8
        $config->addComponent(new GridFieldDataColumns());
62 8
        $config->addComponent(new GridFieldEditButton());
63 8
        $config->addComponent(new GridFieldDeleteAction(true));
64 8
        $config->addComponent(new GridField_ActionMenu());
65 8
        $config->addComponent(new GridFieldDetailForm());
66
67
        // Set the data class of the list
68 8
        $this->setDataClass($dataClass);
69
        // Set the owner data object that contains the has one relation
70 8
        $this->setOwner($owner);
71
        // Load relation value from session
72 8
        $this->loadRelationFromSession();
73
74
        // Set empty string based on the data class
75 8
        $this->setEmptyString(sprintf('No %s selected', mb_strtolower(singleton($dataClass)->singular_name())));
76
77 8
        parent::__construct($name, $title, null, $config);
78
    }
79
80
    /**
81
     * Set instance of value holder field.
82
     */
83 8
    public function setValueHolderField(FormField $field): self
84
    {
85 8
        $this->valueField = $field;
86
87 8
        return $this;
88
    }
89
90
    /**
91
     * Defined the columns to be rendered in the field.
92
     */
93 1
    public function setDisplayFields(array $fields): self
94
    {
95
        // Get grid field configuration
96 1
        $config = $this->getConfig();
97
98
        // Define columns to display in grid field
99 1
        $component = $config->getComponentByType(GridFieldDataColumns::class);
100 1
        assert($component instanceof GridFieldDataColumns);
101
102 1
        $component->setDisplayFields($fields);
103
104 1
        return $this;
105
    }
106
107
    /**
108
     * Apply transformation of the displayed data within a specific column(s).
109
     */
110 1
    public function setFieldFormatting(array $formatting): self
111
    {
112
        // Get grid field configuration
113 1
        $config = $this->getConfig();
114
115
        // Customise the display of the column
116 1
        $component = $config->getComponentByType(GridFieldDataColumns::class);
117 1
        assert($component instanceof GridFieldDataColumns);
118
119 1
        $component->setFieldFormatting($formatting);
120
121 1
        return $this;
122
    }
123
124
    /**
125
     * Set empty string when no record selected.
126
     */
127 8
    public function setEmptyString(string $string): self
128
    {
129 8
        $this->emptyString = $string;
130
131 8
        return $this;
132
    }
133
134
    /**
135
     * set the name of the data class for current list.
136
     */
137 8
    public function setDataClass(string $class): self
138
    {
139 8
        $this->dataClass = $class;
140
141 8
        return $this;
142
    }
143
144
    /**
145
     * Get the name of the data class for current list.
146
     */
147 8
    public function getDataClass(): string
148
    {
149 8
        return $this->dataClass;
150
    }
151
152
    /**
153
     * Get the record of the has one relation for current owner object.
154
     *
155
     * @throws Exception
156
     */
157 4
    public function getRecord(): ?DataObject
158
    {
159 4
        return $this->getOwner()->{rtrim($this->getName(), 'ID')}();
160
    }
161
162
    /**
163
     * Set the record of the has one relation for current owner object.
164
     *
165
     * @throws Exception
166
     */
167 1
    public function setRecord(?DataObject $object): void
168
    {
169 1
        $owner      = $this->getOwner();
170 1
        $recordName = $this->getRelationName();
171
172 1
        $owner->{$recordName} = is_null($object) ? 0 : $object->ID;
173
174
        // Store relation value in session
175 1
        $this->storeRelationInSession((int) $owner->{$recordName});
176
    }
177
178
    /**
179
     * Set instance of data object that has the has one relation.
180
     */
181 8
    public function setOwner(DataObject $owner): self
182
    {
183 8
        $this->owner = $owner;
184
185 8
        return $this;
186
    }
187
188
    /**
189
     * Get instance of data object that has the has one relation.
190
     */
191 8
    public function getOwner(): ?DataObject
192
    {
193 8
        return $this->owner;
194
    }
195
196
    /**
197
     * Get the data source.
198
     *
199
     * @return SS_List
200
     */
201 4
    public function getList()
202
    {
203
        // Get current record ID
204 4
        $id = (int) $this->getOwner()->{$this->getRelationName()};
205
206
        // Filter current list to display current record (has one) value
207 4
        $list = parent::getList();
208 4
        assert($list instanceof DataList);
209
210 4
        return $list->filter('ID', $id);
211
    }
212
213
    /**
214
     * Get the data source after applying every {@link GridField_DataManipulator} to it.
215
     */
216 3
    public function getManipulatedList(): SS_List
217
    {
218
        // Call manipulation from parent class to update current record (has one)
219 3
        parent::getManipulatedList();
220
221
        // Get list of data based on new record
222 3
        return $this->getList();
223
    }
224
225
    /**
226
     * @return string
227
     */
228 2
    protected function getOptionalTableBody(array $content)
229
    {
230
        // Text used by grid field for no items
231 2
        $noItemsText = _t('GridField.NoItemsFound', 'No items found');
232
233
        // If we have no items text in the body, then replace the text with customised string
234 2
        if (mb_strpos($content['body'], $noItemsText) !== false) {
235 2
            $content['body'] = str_replace($noItemsText, $this->emptyString, $content['body']);
236
        }
237
238
        // Append field to hold the value of has one relation
239 2
        $owner      = $this->getOwner();
240 2
        $recordName = $this->getRelationName();
241 2
        $content['body'] .= $this->valueField->setValue($owner->{$recordName})->Field();
0 ignored issues
show
Bug introduced by
The method setValue() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

241
        $content['body'] .= $this->valueField->/** @scrutinizer ignore-call */ setValue($owner->{$recordName})->Field();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
242
243 2
        return parent::getOptionalTableBody($content);
244
    }
245
246
    /**
247
     * Get relation name within the owner object. This includes the "ID" at the end.
248
     */
249 4
    protected function getRelationName(): string
250
    {
251 4
        return $this->getName().'ID';
252
    }
253
254
    /**
255
     * Store relation value in session.
256
     */
257 1
    protected function storeRelationInSession(int $recordId): void
258
    {
259
        // Session name for current owner
260 1
        $sessionName = $this->getSessionName();
261
262
        // Store relation and owner in session
263 1
        $session = Controller::curr()->getRequest()->getSession();
264 1
        $session->set($sessionName, [
265 1
            'Relation'   => $this->getRelationName(),
266 1
            'RelationID' => $recordId,
267 1
        ]);
268
    }
269
270
    /**
271
     * Load relation value from data stored in session.
272
     */
273 8
    protected function loadRelationFromSession(): void
274
    {
275
        // Session name for current owner
276 8
        $sessionName = $this->getSessionName();
277
278
        // Store relation value in session
279 8
        $session = Controller::curr()->getRequest()->getSession();
280 8
        $data    = $session->get($sessionName);
281 8
        if (!empty($data['Relation']) && !empty($data['RelationID'])) {
282
            // Get owner object
283 1
            $owner = $this->getOwner();
284
285
            // Set relation value
286 1
            $owner->{$data['Relation']} = $data['RelationID'];
287
        }
288
    }
289
290
    /**
291
     * Get session name for current owner to store relation value.
292
     */
293 8
    protected function getSessionName(): string
294
    {
295
        // Get owner object
296 8
        $owner = $this->getOwner();
297
298
        // Session name for current owner
299 8
        return static::formatSessionName($owner);
0 ignored issues
show
Bug introduced by
It seems like $owner can also be of type null; however, parameter $owner of Moo\HasOneSelector\Form\...ld::formatSessionName() does only seem to accept SilverStripe\ORM\DataObject, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

299
        return static::formatSessionName(/** @scrutinizer ignore-type */ $owner);
Loading history...
300
    }
301
302
    /**
303
     * Get formatted name for session to store relation value.
304
     */
305 9
    public static function formatSessionName(DataObject $owner): string
306
    {
307 9
        return sprintf('%s_%s_%s', self::class, $owner->ClassName, $owner->ID);
308
    }
309
}
310