Completed
Push — master ( 7691fc...c836b7 )
by Robbie
9s
created
src/TagField.php 1 patch
Indentation   +432 added lines, -432 removed lines patch added patch discarded remove patch
@@ -23,436 +23,436 @@
 block discarded – undo
23 23
  */
24 24
 class TagField extends DropdownField
25 25
 {
26
-    /**
27
-     * @var array
28
-     */
29
-    private static $allowed_actions = array(
30
-        'suggest'
31
-    );
32
-
33
-    /**
34
-     * @var bool
35
-     */
36
-    protected $shouldLazyLoad = false;
37
-
38
-    /**
39
-     * @var int
40
-     */
41
-    protected $lazyLoadItemLimit = 10;
42
-
43
-    /**
44
-     * @var bool
45
-     */
46
-    protected $canCreate = true;
47
-
48
-    /**
49
-     * @var string
50
-     */
51
-    protected $titleField = 'Title';
52
-
53
-    /**
54
-     * @var DataList
55
-     */
56
-    protected $sourceList;
57
-
58
-    /**
59
-     * @var bool
60
-     */
61
-    protected $isMultiple = true;
62
-
63
-    /**
64
-     * @param string $name
65
-     * @param string $title
66
-     * @param null|DataList $source
67
-     * @param null|DataList $value
68
-     * @param string $titleField
69
-     */
70
-    public function __construct($name, $title = '', $source = [], $value = null, $titleField = 'Title')
71
-    {
72
-        $this->setSourceList($source);
73
-        $this->setTitleField($titleField);
74
-        parent::__construct($name, $title, $source, $value);
75
-    }
76
-
77
-    /**
78
-     * @return bool
79
-     */
80
-    public function getShouldLazyLoad()
81
-    {
82
-        return $this->shouldLazyLoad;
83
-    }
84
-
85
-    /**
86
-     * @param bool $shouldLazyLoad
87
-     *
88
-     * @return static
89
-     */
90
-    public function setShouldLazyLoad($shouldLazyLoad)
91
-    {
92
-        $this->shouldLazyLoad = $shouldLazyLoad;
93
-
94
-        return $this;
95
-    }
96
-
97
-    /**
98
-     * @return int
99
-     */
100
-    public function getLazyLoadItemLimit()
101
-    {
102
-        return $this->lazyLoadItemLimit;
103
-    }
104
-
105
-    /**
106
-     * @param int $lazyLoadItemLimit
107
-     *
108
-     * @return static
109
-     */
110
-    public function setLazyLoadItemLimit($lazyLoadItemLimit)
111
-    {
112
-        $this->lazyLoadItemLimit = $lazyLoadItemLimit;
113
-
114
-        return $this;
115
-    }
116
-
117
-    /**
118
-     * @return bool
119
-     */
120
-    public function getIsMultiple()
121
-    {
122
-        return $this->isMultiple;
123
-    }
124
-
125
-    /**
126
-     * @param bool $isMultiple
127
-     *
128
-     * @return static
129
-     */
130
-    public function setIsMultiple($isMultiple)
131
-    {
132
-        $this->isMultiple = $isMultiple;
133
-
134
-        return $this;
135
-    }
136
-
137
-    /**
138
-     * @return bool
139
-     */
140
-    public function getCanCreate()
141
-    {
142
-        return $this->canCreate;
143
-    }
144
-
145
-    /**
146
-     * @param bool $canCreate
147
-     *
148
-     * @return static
149
-     */
150
-    public function setCanCreate($canCreate)
151
-    {
152
-        $this->canCreate = $canCreate;
153
-
154
-        return $this;
155
-    }
156
-
157
-    /**
158
-     * @return string
159
-     */
160
-    public function getTitleField()
161
-    {
162
-        return $this->titleField;
163
-    }
164
-
165
-    /**
166
-     * @param string $titleField
167
-     *
168
-     * @return $this
169
-     */
170
-    public function setTitleField($titleField)
171
-    {
172
-        $this->titleField = $titleField;
173
-
174
-        return $this;
175
-    }
176
-
177
-    /**
178
-     * Get the DataList source. The 4.x upgrade for SelectField::setSource starts to convert this to an array
179
-     * @return DataList
180
-     */
181
-    public function getSourceList()
182
-    {
183
-        return $this->sourceList;
184
-    }
185
-
186
-    /**
187
-     * Set the model class name for tags
188
-     * @param  DataList $className
189
-     * @return self
190
-     */
191
-    public function setSourceList($sourceList)
192
-    {
193
-        $this->sourceList = $sourceList;
194
-        return $this;
195
-    }
196
-
197
-    /**
198
-     * {@inheritdoc}
199
-     */
200
-    public function Field($properties = array())
201
-    {
202
-        Requirements::css('silverstripe/tagfield:css/select2.min.css');
203
-        Requirements::css('silverstripe/tagfield:css/TagField.css');
204
-
205
-        Requirements::javascript('silverstripe/tagfield:js/select2.js');
206
-        Requirements::javascript('silverstripe/tagfield:js/TagField.js');
207
-
208
-        $this->addExtraClass('ss-tag-field');
209
-
210
-        if ($this->getIsMultiple()) {
211
-            $this->setAttribute('multiple', 'multiple');
212
-        }
213
-
214
-        if ($this->shouldLazyLoad) {
215
-            $this->setAttribute('data-ss-tag-field-suggest-url', $this->getSuggestURL());
216
-        } else {
217
-            $properties = array_merge($properties, array(
218
-                'Options' => $this->getOptions()
219
-            ));
220
-        }
221
-
222
-        $this->setAttribute('data-can-create', (int) $this->getCanCreate());
223
-
224
-        return $this
225
-            ->customise($properties)
226
-            ->renderWith(self::class);
227
-    }
228
-
229
-    /**
230
-     * @return string
231
-     */
232
-    protected function getSuggestURL()
233
-    {
234
-        return Controller::join_links($this->Link(), 'suggest');
235
-    }
236
-
237
-    /**
238
-     * @return ArrayList
239
-     */
240
-    protected function getOptions()
241
-    {
242
-        $options = ArrayList::create();
243
-
244
-        $source = $this->getSourceList();
245
-
246
-        if (!$source) {
247
-            $source = ArrayList::create();
248
-        }
249
-
250
-        $dataClass = $source->dataClass();
251
-
252
-        $values = $this->Value();
253
-
254
-        if (!$values) {
255
-            return $options;
256
-        }
257
-
258
-        if (is_array($values)) {
259
-            $values = DataList::create($dataClass)->filter($this->getTitleField(), $values);
260
-        }
261
-
262
-        $ids = $values->column($this->getTitleField());
263
-
264
-        $titleField = $this->getTitleField();
265
-
266
-        foreach ($source as $object) {
267
-            $options->push(
268
-                ArrayData::create(array(
269
-                'Title' => $object->$titleField,
270
-                'Value' => $object->Title,
271
-                'Selected' => in_array($object->Title, $ids),
272
-                ))
273
-            );
274
-        }
275
-
276
-        return $options;
277
-    }
278
-
279
-    /**
280
-     * {@inheritdoc}
281
-     */
282
-    public function setValue($value, $source = null)
283
-    {
284
-        if ($source instanceof DataObject) {
285
-            $name = $this->getName();
286
-
287
-            if ($source->hasMethod($name)) {
288
-                $value = $source->$name()->column($this->getTitleField());
289
-            }
290
-        } elseif ($value instanceof SS_List) {
291
-            $value = $value->column($this->getTitleField());
292
-        }
293
-
294
-        if (!is_array($value)) {
295
-            return parent::setValue($value);
296
-        }
297
-
298
-        return parent::setValue(array_filter($value));
299
-    }
300
-
301
-    /**
302
-     * {@inheritdoc}
303
-     */
304
-    public function getAttributes()
305
-    {
306
-        return array_merge(
307
-            parent::getAttributes(),
308
-            [
309
-                'name' => $this->getName() . '[]',
310
-                'style'=> 'width: 100%'
311
-            ]
312
-        );
313
-    }
314
-
315
-    /**
316
-     * {@inheritdoc}
317
-     */
318
-    public function saveInto(DataObjectInterface $record)
319
-    {
320
-        parent::saveInto($record);
321
-
322
-        $name = $this->getName();
323
-        $titleField = $this->getTitleField();
324
-        $source = $this->getSource();
325
-        $values = $this->Value();
326
-        $relation = $record->$name();
327
-        $ids = array();
328
-
329
-        if (!$values) {
330
-            $values = array();
331
-        }
332
-        if (empty($record) || empty($titleField)) {
333
-            return;
334
-        }
335
-
336
-        if (!$record->hasMethod($name)) {
337
-            throw new Exception(
338
-                sprintf("%s does not have a %s method", get_class($record), $name)
339
-            );
340
-        }
341
-
342
-        foreach ($values as $key => $value) {
343
-            // Get or create record
344
-            $record = $this->getOrCreateTag($value);
345
-            if ($record) {
346
-                $ids[] = $record->ID;
347
-                $values[$key] = $record->Title;
348
-            }
349
-        }
350
-
351
-        $relation->setByIDList(array_filter($ids));
352
-    }
353
-
354
-    /**
355
-     * Get or create tag with the given value
356
-     *
357
-     * @param  string $term
358
-     * @return DataObject
359
-     */
360
-    protected function getOrCreateTag($term)
361
-    {
362
-        // Check if existing record can be found
363
-        /** @var DataList $source */
364
-        $source = $this->getSourceList();
365
-        $titleField = $this->getTitleField();
366
-        $record = $source
367
-            ->filter($titleField, $term)
368
-            ->first();
369
-        if ($record) {
370
-            return $record;
371
-        }
372
-
373
-        // Create new instance if not yet saved
374
-        if ($this->getCanCreate()) {
375
-            $dataClass = $source->dataClass();
376
-            $record = Injector::inst()->create($dataClass);
377
-            $record->{$titleField} = $term;
378
-            $record->write();
379
-            return $record;
380
-        } else {
381
-            return false;
382
-        }
383
-    }
384
-
385
-    /**
386
-     * Returns a JSON string of tags, for lazy loading.
387
-     *
388
-     * @param  HTTPRequest $request
389
-     * @return HTTPResponse
390
-     */
391
-    public function suggest(HTTPRequest $request)
392
-    {
393
-        $tags = $this->getTags($request->getVar('term'));
394
-
395
-        $response = new HTTPResponse();
396
-        $response->addHeader('Content-Type', 'application/json');
397
-        $response->setBody(json_encode(array('items' => $tags)));
398
-
399
-        return $response;
400
-    }
401
-
402
-    /**
403
-     * Returns array of arrays representing tags.
404
-     *
405
-     * @param  string $term
406
-     * @return array
407
-     */
408
-    protected function getTags($term)
409
-    {
410
-        /**
411
-         * @var array $source
412
-         */
413
-        $source = $this->getSourceList();
414
-
415
-        $titleField = $this->getTitleField();
416
-
417
-        $query = $source
418
-            ->filter($titleField . ':PartialMatch:nocase', $term)
419
-            ->sort($titleField)
420
-            ->limit($this->getLazyLoadItemLimit());
421
-
422
-        // Map into a distinct list
423
-        $items = array();
424
-        $titleField = $this->getTitleField();
425
-        foreach ($query->map('ID', $titleField) as $id => $title) {
426
-            $items[$title] = array(
427
-                'id' => $title,
428
-                'text' => $title
429
-            );
430
-        }
431
-
432
-        return array_values($items);
433
-    }
434
-
435
-    /**
436
-     * DropdownField assumes value will be a scalar so we must
437
-     * override validate. This only applies to Silverstripe 3.2+
438
-     *
439
-     * @param Validator $validator
440
-     * @return bool
441
-     */
442
-    public function validate($validator)
443
-    {
444
-        return true;
445
-    }
446
-
447
-    /**
448
-     * Converts the field to a readonly variant.
449
-     *
450
-     * @return TagField_Readonly
451
-     */
452
-    public function performReadonlyTransformation()
453
-    {
454
-        $copy = $this->castedCopy(ReadonlyTagField::class);
455
-        $copy->setSourceList($this->getSourceList());
456
-        return $copy;
457
-    }
26
+	/**
27
+	 * @var array
28
+	 */
29
+	private static $allowed_actions = array(
30
+		'suggest'
31
+	);
32
+
33
+	/**
34
+	 * @var bool
35
+	 */
36
+	protected $shouldLazyLoad = false;
37
+
38
+	/**
39
+	 * @var int
40
+	 */
41
+	protected $lazyLoadItemLimit = 10;
42
+
43
+	/**
44
+	 * @var bool
45
+	 */
46
+	protected $canCreate = true;
47
+
48
+	/**
49
+	 * @var string
50
+	 */
51
+	protected $titleField = 'Title';
52
+
53
+	/**
54
+	 * @var DataList
55
+	 */
56
+	protected $sourceList;
57
+
58
+	/**
59
+	 * @var bool
60
+	 */
61
+	protected $isMultiple = true;
62
+
63
+	/**
64
+	 * @param string $name
65
+	 * @param string $title
66
+	 * @param null|DataList $source
67
+	 * @param null|DataList $value
68
+	 * @param string $titleField
69
+	 */
70
+	public function __construct($name, $title = '', $source = [], $value = null, $titleField = 'Title')
71
+	{
72
+		$this->setSourceList($source);
73
+		$this->setTitleField($titleField);
74
+		parent::__construct($name, $title, $source, $value);
75
+	}
76
+
77
+	/**
78
+	 * @return bool
79
+	 */
80
+	public function getShouldLazyLoad()
81
+	{
82
+		return $this->shouldLazyLoad;
83
+	}
84
+
85
+	/**
86
+	 * @param bool $shouldLazyLoad
87
+	 *
88
+	 * @return static
89
+	 */
90
+	public function setShouldLazyLoad($shouldLazyLoad)
91
+	{
92
+		$this->shouldLazyLoad = $shouldLazyLoad;
93
+
94
+		return $this;
95
+	}
96
+
97
+	/**
98
+	 * @return int
99
+	 */
100
+	public function getLazyLoadItemLimit()
101
+	{
102
+		return $this->lazyLoadItemLimit;
103
+	}
104
+
105
+	/**
106
+	 * @param int $lazyLoadItemLimit
107
+	 *
108
+	 * @return static
109
+	 */
110
+	public function setLazyLoadItemLimit($lazyLoadItemLimit)
111
+	{
112
+		$this->lazyLoadItemLimit = $lazyLoadItemLimit;
113
+
114
+		return $this;
115
+	}
116
+
117
+	/**
118
+	 * @return bool
119
+	 */
120
+	public function getIsMultiple()
121
+	{
122
+		return $this->isMultiple;
123
+	}
124
+
125
+	/**
126
+	 * @param bool $isMultiple
127
+	 *
128
+	 * @return static
129
+	 */
130
+	public function setIsMultiple($isMultiple)
131
+	{
132
+		$this->isMultiple = $isMultiple;
133
+
134
+		return $this;
135
+	}
136
+
137
+	/**
138
+	 * @return bool
139
+	 */
140
+	public function getCanCreate()
141
+	{
142
+		return $this->canCreate;
143
+	}
144
+
145
+	/**
146
+	 * @param bool $canCreate
147
+	 *
148
+	 * @return static
149
+	 */
150
+	public function setCanCreate($canCreate)
151
+	{
152
+		$this->canCreate = $canCreate;
153
+
154
+		return $this;
155
+	}
156
+
157
+	/**
158
+	 * @return string
159
+	 */
160
+	public function getTitleField()
161
+	{
162
+		return $this->titleField;
163
+	}
164
+
165
+	/**
166
+	 * @param string $titleField
167
+	 *
168
+	 * @return $this
169
+	 */
170
+	public function setTitleField($titleField)
171
+	{
172
+		$this->titleField = $titleField;
173
+
174
+		return $this;
175
+	}
176
+
177
+	/**
178
+	 * Get the DataList source. The 4.x upgrade for SelectField::setSource starts to convert this to an array
179
+	 * @return DataList
180
+	 */
181
+	public function getSourceList()
182
+	{
183
+		return $this->sourceList;
184
+	}
185
+
186
+	/**
187
+	 * Set the model class name for tags
188
+	 * @param  DataList $className
189
+	 * @return self
190
+	 */
191
+	public function setSourceList($sourceList)
192
+	{
193
+		$this->sourceList = $sourceList;
194
+		return $this;
195
+	}
196
+
197
+	/**
198
+	 * {@inheritdoc}
199
+	 */
200
+	public function Field($properties = array())
201
+	{
202
+		Requirements::css('silverstripe/tagfield:css/select2.min.css');
203
+		Requirements::css('silverstripe/tagfield:css/TagField.css');
204
+
205
+		Requirements::javascript('silverstripe/tagfield:js/select2.js');
206
+		Requirements::javascript('silverstripe/tagfield:js/TagField.js');
207
+
208
+		$this->addExtraClass('ss-tag-field');
209
+
210
+		if ($this->getIsMultiple()) {
211
+			$this->setAttribute('multiple', 'multiple');
212
+		}
213
+
214
+		if ($this->shouldLazyLoad) {
215
+			$this->setAttribute('data-ss-tag-field-suggest-url', $this->getSuggestURL());
216
+		} else {
217
+			$properties = array_merge($properties, array(
218
+				'Options' => $this->getOptions()
219
+			));
220
+		}
221
+
222
+		$this->setAttribute('data-can-create', (int) $this->getCanCreate());
223
+
224
+		return $this
225
+			->customise($properties)
226
+			->renderWith(self::class);
227
+	}
228
+
229
+	/**
230
+	 * @return string
231
+	 */
232
+	protected function getSuggestURL()
233
+	{
234
+		return Controller::join_links($this->Link(), 'suggest');
235
+	}
236
+
237
+	/**
238
+	 * @return ArrayList
239
+	 */
240
+	protected function getOptions()
241
+	{
242
+		$options = ArrayList::create();
243
+
244
+		$source = $this->getSourceList();
245
+
246
+		if (!$source) {
247
+			$source = ArrayList::create();
248
+		}
249
+
250
+		$dataClass = $source->dataClass();
251
+
252
+		$values = $this->Value();
253
+
254
+		if (!$values) {
255
+			return $options;
256
+		}
257
+
258
+		if (is_array($values)) {
259
+			$values = DataList::create($dataClass)->filter($this->getTitleField(), $values);
260
+		}
261
+
262
+		$ids = $values->column($this->getTitleField());
263
+
264
+		$titleField = $this->getTitleField();
265
+
266
+		foreach ($source as $object) {
267
+			$options->push(
268
+				ArrayData::create(array(
269
+				'Title' => $object->$titleField,
270
+				'Value' => $object->Title,
271
+				'Selected' => in_array($object->Title, $ids),
272
+				))
273
+			);
274
+		}
275
+
276
+		return $options;
277
+	}
278
+
279
+	/**
280
+	 * {@inheritdoc}
281
+	 */
282
+	public function setValue($value, $source = null)
283
+	{
284
+		if ($source instanceof DataObject) {
285
+			$name = $this->getName();
286
+
287
+			if ($source->hasMethod($name)) {
288
+				$value = $source->$name()->column($this->getTitleField());
289
+			}
290
+		} elseif ($value instanceof SS_List) {
291
+			$value = $value->column($this->getTitleField());
292
+		}
293
+
294
+		if (!is_array($value)) {
295
+			return parent::setValue($value);
296
+		}
297
+
298
+		return parent::setValue(array_filter($value));
299
+	}
300
+
301
+	/**
302
+	 * {@inheritdoc}
303
+	 */
304
+	public function getAttributes()
305
+	{
306
+		return array_merge(
307
+			parent::getAttributes(),
308
+			[
309
+				'name' => $this->getName() . '[]',
310
+				'style'=> 'width: 100%'
311
+			]
312
+		);
313
+	}
314
+
315
+	/**
316
+	 * {@inheritdoc}
317
+	 */
318
+	public function saveInto(DataObjectInterface $record)
319
+	{
320
+		parent::saveInto($record);
321
+
322
+		$name = $this->getName();
323
+		$titleField = $this->getTitleField();
324
+		$source = $this->getSource();
325
+		$values = $this->Value();
326
+		$relation = $record->$name();
327
+		$ids = array();
328
+
329
+		if (!$values) {
330
+			$values = array();
331
+		}
332
+		if (empty($record) || empty($titleField)) {
333
+			return;
334
+		}
335
+
336
+		if (!$record->hasMethod($name)) {
337
+			throw new Exception(
338
+				sprintf("%s does not have a %s method", get_class($record), $name)
339
+			);
340
+		}
341
+
342
+		foreach ($values as $key => $value) {
343
+			// Get or create record
344
+			$record = $this->getOrCreateTag($value);
345
+			if ($record) {
346
+				$ids[] = $record->ID;
347
+				$values[$key] = $record->Title;
348
+			}
349
+		}
350
+
351
+		$relation->setByIDList(array_filter($ids));
352
+	}
353
+
354
+	/**
355
+	 * Get or create tag with the given value
356
+	 *
357
+	 * @param  string $term
358
+	 * @return DataObject
359
+	 */
360
+	protected function getOrCreateTag($term)
361
+	{
362
+		// Check if existing record can be found
363
+		/** @var DataList $source */
364
+		$source = $this->getSourceList();
365
+		$titleField = $this->getTitleField();
366
+		$record = $source
367
+			->filter($titleField, $term)
368
+			->first();
369
+		if ($record) {
370
+			return $record;
371
+		}
372
+
373
+		// Create new instance if not yet saved
374
+		if ($this->getCanCreate()) {
375
+			$dataClass = $source->dataClass();
376
+			$record = Injector::inst()->create($dataClass);
377
+			$record->{$titleField} = $term;
378
+			$record->write();
379
+			return $record;
380
+		} else {
381
+			return false;
382
+		}
383
+	}
384
+
385
+	/**
386
+	 * Returns a JSON string of tags, for lazy loading.
387
+	 *
388
+	 * @param  HTTPRequest $request
389
+	 * @return HTTPResponse
390
+	 */
391
+	public function suggest(HTTPRequest $request)
392
+	{
393
+		$tags = $this->getTags($request->getVar('term'));
394
+
395
+		$response = new HTTPResponse();
396
+		$response->addHeader('Content-Type', 'application/json');
397
+		$response->setBody(json_encode(array('items' => $tags)));
398
+
399
+		return $response;
400
+	}
401
+
402
+	/**
403
+	 * Returns array of arrays representing tags.
404
+	 *
405
+	 * @param  string $term
406
+	 * @return array
407
+	 */
408
+	protected function getTags($term)
409
+	{
410
+		/**
411
+		 * @var array $source
412
+		 */
413
+		$source = $this->getSourceList();
414
+
415
+		$titleField = $this->getTitleField();
416
+
417
+		$query = $source
418
+			->filter($titleField . ':PartialMatch:nocase', $term)
419
+			->sort($titleField)
420
+			->limit($this->getLazyLoadItemLimit());
421
+
422
+		// Map into a distinct list
423
+		$items = array();
424
+		$titleField = $this->getTitleField();
425
+		foreach ($query->map('ID', $titleField) as $id => $title) {
426
+			$items[$title] = array(
427
+				'id' => $title,
428
+				'text' => $title
429
+			);
430
+		}
431
+
432
+		return array_values($items);
433
+	}
434
+
435
+	/**
436
+	 * DropdownField assumes value will be a scalar so we must
437
+	 * override validate. This only applies to Silverstripe 3.2+
438
+	 *
439
+	 * @param Validator $validator
440
+	 * @return bool
441
+	 */
442
+	public function validate($validator)
443
+	{
444
+		return true;
445
+	}
446
+
447
+	/**
448
+	 * Converts the field to a readonly variant.
449
+	 *
450
+	 * @return TagField_Readonly
451
+	 */
452
+	public function performReadonlyTransformation()
453
+	{
454
+		$copy = $this->castedCopy(ReadonlyTagField::class);
455
+		$copy->setSourceList($this->getSourceList());
456
+		return $copy;
457
+	}
458 458
 }
Please login to merge, or discard this patch.