ResourceLocatorField::setValue()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 19
nc 6
nop 2
dl 0
loc 35
rs 9.0111
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\CKANRegistry\Forms;
4
5
use InvalidArgumentException;
6
use SilverStripe\Forms\FormField;
7
use SilverStripe\ORM\DataObjectInterface;
8
9
class ResourceLocatorField extends FormField
10
{
11
    /**
12
     * The default CKAN endpoint to be used in a default isn't provided on construction
13
     * @see ResourceLocatorField::$defaultEndpoint
14
     *
15
     * @config
16
     * @var string
17
     */
18
    private static $default_endpoint = 'https://demo.ckan.org/';
19
20
    /**
21
     * The default CKAN endpoint to be used in this field. This will allow consumers of the field to only provide
22
     * package or dataset IDs and still work. If not set the configured default will instead be used.
23
     *
24
     * @var string|null
25
     */
26
    protected $defaultEndpoint;
27
28
    /**
29
     * Set a site name that can be used to refer to the CKAN endpoint. By default this will be "a CKAN website".
30
     *
31
     * @var string|null
32
     */
33
    protected $siteName = null;
34
35
    /**
36
     * The name of the subfield to save the endpoint value of this field into
37
     *
38
     * @var string
39
     */
40
    protected $endpointFieldName = 'Endpoint';
41
42
    /**
43
     * The name of the subfield to save the dataset value of this field into
44
     *
45
     * @var string
46
     */
47
    protected $datasetFieldName = 'DataSet';
48
49
    /**
50
     * The name of the subfield to save the resource value of this field into
51
     *
52
     * @var string
53
     */
54
    protected $resourceFieldName = 'Identifier';
55
56
    /**
57
     * @param string $name
58
     * @param string $title
59
     * @param string $value
60
     * @param string $defaultEndpoint
61
     */
62
    public function __construct($name, $title = null, $value = null, $defaultEndpoint = null)
63
    {
64
        parent::__construct($name, $title, $value);
65
        $this->setDefaultEndpoint($defaultEndpoint);
66
67
        // Set a default description
68
        $this->setDescription(_t(
69
            __CLASS__ . '.DESCRIPTION',
70
            'Connect to a data source from {site}. Once added and saved you can configure the appearance and add search'
71
            . ' filters.',
72
            [ 'site' => $this->getSiteName() ]
73
        ));
74
    }
75
76
    public function getSchemaDataDefaults()
77
    {
78
        return array_merge(parent::getSchemaDataDefaults(), [
79
            'hideLabels' => true,
80
            'defaultEndpoint' => $this->getDefaultEndpoint(),
81
        ]);
82
    }
83
84
    public function performReadonlyTransformation()
85
    {
86
        // Set read only and clone to maintain immutability
87
        $clone = clone $this->setReadonly(true);
88
89
        // Clear out the description that's only relevant when the field is editable.
90
        $clone->setDescription('');
91
92
        return $clone;
93
    }
94
95
96
    public function setValue($value, $data = null)
97
    {
98
        // Handle the case where this is being set as a legitimate "spec" containing endpoint, dataset and resource
99
        if (is_array($value)) {
100
            $this->value = $value;
101
            return $this;
102
        }
103
104
        // If it's still not valid we'll just run with an empty value (assume the relation isn't created)
105
        if (!$value instanceof DataObjectInterface) {
106
            $this->value = null;
107
            return $this;
108
        }
109
110
        $endpoint = $value->{$this->getEndpointFieldName()};
111
        $dataset = $value->{$this->getDatasetFieldName()};
112
        $resource = $value->{$this->getResourceFieldName()};
113
114
        // Validate we have a dataset
115
        if (!$dataset) {
116
            $this->value = null;
117
            return $this;
118
        }
119
120
        // Validate we have an endpoint (or a default to fall back upon)
121
        if (!$endpoint) {
122
            $endpoint = $this->getDefaultEndpoint();
123
            if (!$endpoint) {
124
                $this->value = null;
125
                return $this;
126
            }
127
        }
128
129
        $this->value = compact('endpoint', 'dataset', 'resource');
130
        return $this;
131
    }
132
133
    public function setSubmittedValue($value, $data = null)
134
    {
135
        return $this->setValue(json_decode($value, true));
136
    }
137
138
    public function dataValue()
139
    {
140
        // Although by default this "saves into" a child object we provide a JSON encoded value in case this method is
141
        // used.
142
        return json_encode($this->Value());
143
    }
144
145
    public function saveInto(DataObjectInterface $dataObject)
146
    {
147
        // Duplicate existing logic where the field is skipped given there's no name on this field.
148
        if (!$this->name) {
149
            return;
150
        }
151
152
        // Find what we're actually saving into
153
        $resource = $dataObject->{$this->name};
154
155
        if (!$resource || !$resource instanceof DataObjectInterface) {
156
            throw new InvalidArgumentException('Could not determine where to save the value of ' . __CLASS__);
157
        }
158
159
        // Pull the value that'll be null or an associative array of our specification
160
        $value = $this->Value();
161
        $resource->setCastedField($this->getEndpointFieldName(), $value ? $value['endpoint'] : null);
162
        $resource->setCastedField($this->getDatasetFieldName(), $value ? $value['dataset'] : null);
163
        $resource->setCastedField($this->getResourceFieldName(), $value ? $value['resource'] : null);
164
165
        // Now set the updated resource back on the parent
166
        $dataObject->setCastedField($this->name, $resource);
167
168
        // Ensure changes are persisted as this is not saved on page save if the ID of the resource did not change.
169
        $resource->write();
170
    }
171
172
    /**
173
     * @see ResourceLocatorField::$defaultEndpoint
174
     * @return string
175
     */
176
    public function getDefaultEndpoint()
177
    {
178
        if (!$this->defaultEndpoint) {
179
            return self::config()->get('default_endpoint');
180
        }
181
182
        return $this->defaultEndpoint;
183
    }
184
185
    /**
186
     * @see ResourceLocatorField::$defaultEndpoint
187
     * @param string $defaultEndpoint
188
     * @return $this
189
     */
190
    public function setDefaultEndpoint($defaultEndpoint)
191
    {
192
        $this->defaultEndpoint = $defaultEndpoint;
193
        return $this;
194
    }
195
196
    /**
197
     * @return null|string
198
     */
199
    public function getSiteName()
200
    {
201
        // Allow empty site names
202
        if ($this->siteName === null) {
203
            return _t(__CLASS__ . '.GENERIC_SITE_NAME', 'a CKAN website');
204
        }
205
206
        return $this->siteName;
207
    }
208
209
    /**
210
     * @param null|string $siteName
211
     * @return $this
212
     */
213
    public function setSiteName($siteName)
214
    {
215
        $this->siteName = $siteName;
216
        return $this;
217
    }
218
219
    /**
220
     * @return string
221
     */
222
    public function getEndpointFieldName()
223
    {
224
        return $this->endpointFieldName;
225
    }
226
227
    /**
228
     * @param string $endpointFieldName
229
     * @return $this
230
     */
231
    public function setEndpointFieldName($endpointFieldName)
232
    {
233
        $this->endpointFieldName = $endpointFieldName;
234
        return $this;
235
    }
236
237
    /**
238
     * @return string
239
     */
240
    public function getDatasetFieldName()
241
    {
242
        return $this->datasetFieldName;
243
    }
244
245
    /**
246
     * @param string $datasetFieldName
247
     * @return $this
248
     */
249
    public function setDatasetFieldName($datasetFieldName)
250
    {
251
        $this->datasetFieldName = $datasetFieldName;
252
        return $this;
253
    }
254
255
    /**
256
     * @return string
257
     */
258
    public function getResourceFieldName()
259
    {
260
        return $this->resourceFieldName;
261
    }
262
263
    /**
264
     * @param string $resourceFieldName
265
     * @return $this
266
     */
267
    public function setResourceFieldName($resourceFieldName)
268
    {
269
        $this->resourceFieldName = $resourceFieldName;
270
        return $this;
271
    }
272
}
273