Test Failed
Branch master (3c461d)
by Mohamed
103:57
created

Field::getValueHolderField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 11
rs 10
1
<?php
2
3
namespace Moo\HasOneSelector\Form;
4
5
use Exception;
6
use SilverStripe\Forms\CompositeField;
7
use SilverStripe\Forms\FormField;
8
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
9
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
10
use SilverStripe\Forms\GridField\GridFieldComponent;
11
use SilverStripe\Forms\HiddenField;
12
use SilverStripe\ORM\DataObject;
13
use SilverStripe\ORM\FieldType\DBHTMLText;
14
15
/**
16
 * Class Field provides CMS field to manage selecting/adding/editing object within
17
 * has_one relation of the current object being edited
18
 */
19
class Field extends CompositeField
20
{
21
    /**
22
     * Instance of form field that find and display selected record
23
     *
24
     * @var GridField
25
     */
26
    protected $gridField;
27
28
    /**
29
     * Instance of form field that holds the value
30
     *
31
     * @var FormField
32
     */
33
    protected $valueField;
34
35
    /**
36
     * HasOneSelector Field constructor
37
     *
38
     * @param string     $name
39
     * @param string     $title
40
     * @param DataObject $owner
41
     * @param string     $dataClass
42
     */
43
    public function __construct($name, $title, DataObject $owner, $dataClass = DataObject::class)
44
    {
45
        // Create grid field
46
        $this->initGridField($name, $title, $owner, $dataClass);
47
48
        $this->addExtraClass('b-hasoneselector-field');
49
50
        // Ensure there is a left label to allow for field to be aligned with others
51
        $this->leftTitle = ' ';
52
53
        // Create composite field with hidden field holds the value and grid field to find and select has one relation
54
        parent::__construct([
55
            $this->getValueHolderField(),
56
            $this->gridField,
57
        ]);
58
    }
59
60
    /**
61
     * Returns a "field holder" for this field.
62
     *
63
     * Forms are constructed by concatenating a number of these field holders.
64
     *
65
     * The default field holder is a label and a form field inside a div.
66
     *
67
     * @see FieldHolder.ss
68
     *
69
     * @param array $properties
70
     *
71
     * @return DBHTMLText
72
     */
73
    public function FieldHolder($properties = [])
74
    {
75
        // Set title based on left title property
76
        $properties['Title'] = $this->leftTitle;
77
78
        // Render field holder
79
        return parent::FieldHolder($properties);
80
    }
81
82
    /**
83
     * Get instance of value holder field that hold the value of has one
84
     *
85
     * @return FormField
86
     */
87
    protected function getValueHolderField()
88
    {
89
        if (is_null($this->valueField)) {
90
            // Name of the has one relation
91
            $recordName = $this->gridField->getName() . 'ID';
92
93
            // Field to hold the value
94
            $this->valueField = HiddenField::create($recordName, '', '');
95
        }
96
97
        return $this->valueField;
98
    }
99
100
    /**
101
     * Initiate instance of grid field. This is a subclass of GridField
102
     *
103
     * @param  string     $name
104
     * @param  string     $title
105
     * @param  DataObject $owner
106
     * @param  string     $dataClass
107
     * @return GridField
108
     */
109
    protected function initGridField($name, $title, DataObject $owner, $dataClass = DataObject::class)
110
    {
111
        if (is_null($this->gridField)) {
112
            $this->gridField = GridField::create($name, $title, $owner, $dataClass);
113
        }
114
        $this->gridField->setValueHolderField($this->getValueHolderField());
115
116
        return $this->gridField;
117
    }
118
119
    /**
120
     * Remove the linkable grid field component
121
     *
122
     * @return $this
123
     */
124
    public function removeLinkable()
125
    {
126
        // Remove grid field linkable component
127
        $this->gridField->getConfig()->getComponents()->each(function ($component) {
128
            if ($component instanceof GridFieldAddExistingAutocompleter) {
129
                $this->gridField->getConfig()->removeComponentsByType(GridFieldAddExistingAutocompleter::class);
130
            }
131
        });
132
133
        return $this;
134
    }
135
136
    /**
137
     * Add linkable grid field component
138
     *
139
     * @param  GridFieldComponent|null $component
140
     * @return $this
141
     */
142
    public function enableLinkable(GridFieldComponent $component = null)
143
    {
144
        // Use default linkable grid field component
145
        if (is_null($component)) {
146
            $component = new GridFieldAddExistingAutocompleter('buttons-before-right');
147
        }
148
149
        // Add grid field component
150
        $this->gridField->getConfig()->addComponent($component);
151
152
        return $this;
153
    }
154
155
    /**
156
     * Remove the addable grid field component
157
     *
158
     * @return $this
159
     */
160
    public function removeAddable()
161
    {
162
        // Remove grid field addable component
163
        $this->gridField->getConfig()->getComponents()->each(function ($component) {
164
            if ($component instanceof GridFieldAddNewButton) {
165
                $this->gridField->getConfig()->removeComponentsByType(GridFieldAddNewButton::class);
166
            }
167
        });
168
169
        return $this;
170
    }
171
172
    /**
173
     * Add addable grid field component
174
     *
175
     * @param  GridFieldComponent|null $component
176
     * @return $this
177
     */
178
    public function enableAddable(GridFieldComponent $component = null)
179
    {
180
        // Use default addable grid field component
181
        if (is_null($component)) {
182
            $component = new GridFieldAddNewButton('buttons-before-left');
183
        }
184
185
        // Add grid field component
186
        $this->gridField->getConfig()->addComponent($component);
187
188
        return $this;
189
    }
190
191
    /**
192
     * Proxy any undefined methods to the grid field as this is the main field and the composite is wrapper to manage
193
     * the field and value of has one
194
     *
195
     * @param  string    $method
196
     * @param  array     $arguments
197
     * @return mixed
198
     * @throws Exception
199
     */
200
    public function __call($method, $arguments = [])
201
    {
202
        if ($this->gridField instanceof GridField) {
0 ignored issues
show
introduced by
$this->gridField is always a sub-type of Moo\HasOneSelector\Form\GridField.
Loading history...
203
            return $this->gridField->{$method}(...$arguments);
204
        }
205
206
        return parent::__call($method, $arguments);
207
    }
208
}
209