Test Failed
Push — master ( 86af80...31151e )
by Mohamed
03:18 queued 01:08
created

Field::removeAddable()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 4
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 10
ccs 0
cts 5
cp 0
crap 6
rs 10
1
<?php
2
3
namespace Moo\HasOneSelector\Form;
4
5
use Exception;
6
use Moo\HasOneSelector\ORM\DataList;
7
use SilverStripe\Forms\CompositeField;
8
use SilverStripe\Forms\FormField;
9
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
10
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
11
use SilverStripe\Forms\GridField\GridFieldComponent;
12
use SilverStripe\Forms\HiddenField;
13
use SilverStripe\ORM\DataObject;
14
use SilverStripe\ORM\FieldType\DBHTMLText;
15
use SilverStripe\ORM\SS_List;
16
17
/**
18
 * Class Field provides CMS field to manage selecting/adding/editing object within
19
 * has_one relation of the current object being edited.
20
 */
21
class Field extends CompositeField
22
{
23
    /**
24
     * Instance of form field that find and display selected record.
25
     */
26
    protected ?GridField $gridField = null;
27
28
    /**
29
     * Instance of form field that holds the value.
30
     */
31
    protected ?FormField $valueField = null;
32
33
    /**
34
     * HasOneSelector Field constructor.
35
     *
36
     * @param string $name
37
     * @param string $title
38
     * @param string $dataClass
39
     */
40 1
    public function __construct($name, $title, DataObject $owner, $dataClass = DataObject::class)
41
    {
42
        // Create grid field
43 1
        $this->initGridField($name, $title, $owner, $dataClass);
44
45 1
        $this->addExtraClass('b-hasoneselector-field');
46
47
        // Ensure there is a left label to allow for field to be aligned with others
48 1
        $this->leftTitle = ' ';
49
50
        // Create composite field with hidden field holds the value and grid field to find and select has one relation
51 1
        parent::__construct([
52 1
            $this->getValueHolderField(),
53 1
            $this->getGridField(),
54
        ]);
55
    }
56
57
    /**
58
     * Returns a "field holder" for this field.
59
     *
60
     * Forms are constructed by concatenating a number of these field holders.
61
     *
62
     * The default field holder is a label and a form field inside a div.
63
     *
64
     * @see FieldHolder.ss
65
     *
66
     * @param array $properties
67
     *
68
     * @return DBHTMLText
69
     */
70 1
    public function FieldHolder($properties = [])
71
    {
72
        // Set title based on left title property
73 1
        $properties['Title'] = $this->leftTitle;
74
75
        // Render field holder
76 1
        return parent::FieldHolder($properties);
77
    }
78
79
    /**
80
     * Get instance of value holder field that hold the value of has one.
81
     */
82 1
    protected function getValueHolderField(): FormField
83
    {
84 1
        if (is_null($this->valueField)) {
85
            // Name of the has one relation
86 1
            $recordName = $this->getGridField()->getName().'ID';
87
88
            // Field to hold the value
89 1
            $this->valueField = HiddenField::create($recordName, '', '');
90
        }
91
92 1
        return $this->valueField;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->valueField could return the type null which is incompatible with the type-hinted return SilverStripe\Forms\FormField. Consider adding an additional type-check to rule them out.
Loading history...
93
    }
94
95
    /**
96
     * Get instance of grid field embed in wrapper field.
97
     */
98 1
    public function getGridField(): GridField
99
    {
100 1
        return $this->gridField;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->gridField could return the type null which is incompatible with the type-hinted return Moo\HasOneSelector\Form\GridField. Consider adding an additional type-check to rule them out.
Loading history...
101
    }
102
103
    /**
104
     * Initiate instance of grid field. This is a subclass of GridField.
105
     */
106 1
    protected function initGridField(
107
        string $name,
108
        string $title,
109
        DataObject $owner,
110
        string $dataClass = DataObject::class
111
    ): GridField {
112 1
        if (is_null($this->gridField)) {
113 1
            $this->gridField = GridField::create($name, $title, $owner, $dataClass);
114
            // Instance of data list that manages the grid field data
115 1
            $this->gridField->setList($this->createList());
0 ignored issues
show
Bug introduced by
The method setList() 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

115
            $this->gridField->/** @scrutinizer ignore-call */ 
116
                              setList($this->createList());

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...
116
        }
117 1
        $this->gridField->setValueHolderField($this->getValueHolderField());
118
119 1
        return $this->gridField;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->gridField could return the type null which is incompatible with the type-hinted return Moo\HasOneSelector\Form\GridField. Consider adding an additional type-check to rule them out.
Loading history...
120
    }
121
122
    /**
123
     * Create data list for grid field.
124
     */
125 1
    protected function createList(): SS_List
126
    {
127 1
        return DataList::create($this->getGridField());
128
    }
129
130
    /**
131
     * Remove the linkable grid field component.
132
     */
133
    public function removeLinkable(): self
134
    {
135
        // Remove grid field linkable component
136
        $this->getGridField()->getConfig()->getComponents()->each(function ($component) {
137
            if ($component instanceof GridFieldAddExistingAutocompleter) {
138
                $this->getGridField()->getConfig()->removeComponentsByType(GridFieldAddExistingAutocompleter::class);
139
            }
140
        });
141
142
        return $this;
143
    }
144
145
    /**
146
     * Add linkable grid field component.
147
     */
148
    public function enableLinkable(GridFieldComponent $component = null): self
149
    {
150
        // Use default linkable grid field component
151
        if (is_null($component)) {
152
            $component = new GridFieldAddExistingAutocompleter('buttons-before-right');
153
        }
154
155
        // Add grid field component
156
        $this->getGridField()->getConfig()->addComponent($component);
157
158
        return $this;
159
    }
160
161
    /**
162
     * Remove the addable grid field component.
163
     */
164
    public function removeAddable(): self
165
    {
166
        // Remove grid field addable component
167
        $this->getGridField()->getConfig()->getComponents()->each(function ($component) {
168
            if ($component instanceof GridFieldAddNewButton) {
169
                $this->getGridField()->getConfig()->removeComponentsByType(GridFieldAddNewButton::class);
170
            }
171
        });
172
173
        return $this;
174
    }
175
176
    /**
177
     * Add addable grid field component.
178
     */
179
    public function enableAddable(GridFieldComponent $component = null): self
180
    {
181
        // Use default addable grid field component
182
        if (is_null($component)) {
183
            $component = new GridFieldAddNewButton('buttons-before-left');
184
        }
185
186
        // Add grid field component
187
        $this->getGridField()->getConfig()->addComponent($component);
188
189
        return $this;
190
    }
191
192
    /**
193
     * Proxy any undefined methods to the grid field as this is the main field and the composite is wrapper to manage
194
     * the field and value of has one.
195
     *
196
     * @param string $method
197
     * @param array  $arguments
198
     *
199
     * @throws Exception
200
     *
201
     * @return mixed
202
     */
203 1
    public function __call($method, $arguments = [])
204
    {
205 1
        return $this->getGridField()->{$method}(...$arguments);
206
    }
207
}
208