Completed
Pull Request — master (#5304)
by Damian
10:55
created

CampaignAdmin::readCampaign()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 3
Metric Value
c 5
b 0
f 3
dl 0
loc 24
rs 8.6845
cc 4
eloc 17
nc 4
nop 1
1
<?php
2
3
/**
4
 * Campaign section of the CMS
5
 *
6
 * @package framework
7
 * @subpackage admin
8
 */
9
class CampaignAdmin extends LeftAndMain implements PermissionProvider {
10
11
	private static $allowed_actions = [
12
		'set',
13
		'sets',
14
		'schema',
15
		'DetailEditForm',
16
		'readCampaigns',
17
		'createCampaign',
18
		'readCampaign',
19
		'updateCampaign',
20
		'deleteCampaign',
21
	];
22
23
	private static $menu_priority = 11;
24
25
	private static $menu_title = 'Campaigns';
26
27
	private static $url_handlers = [
28
		'GET sets' => 'readCampaigns',
29
		'POST set/$ID' => 'createCampaign',
30
		'GET set/$ID/$Name' => 'readCampaign',
31
		'PUT set/$ID' => 'updateCampaign',
32
		'DELETE set/$ID' => 'deleteCampaign',
33
	];
34
35
	private static $url_segment = 'campaigns';
36
37
	/**
38
	 * Size of thumbnail width
39
	 *
40
	 * @config
41
	 * @var int
42
	 */
43
	private static $thumbnail_width = 64;
44
45
	/**
46
	 * Size of thumbnail height
47
	 *
48
	 * @config
49
	 * @var int
50
	 */
51
	private static $thumbnail_height = 64;
52
53
	public function getClientConfig() {
54
		$urlSegment = Config::inst()->get($this->class, 'url_segment');
55
56
		return array_merge(parent::getClientConfig(), [
57
			'forms' => [
58
				// TODO Use schemaUrl instead
59
				'editForm' => [
60
					'schemaUrl' => $this->Link('schema/EditForm')
61
				]
62
			],
63
			'campaignViewRoute' => $urlSegment . '/:type?/:id?/:view?',
64
			'itemListViewEndpoint' => $this->Link('set/:id/show'),
65
		]);
66
	}
67
68
	public function schema($request) {
69
		// TODO Hardcoding schema until we can get GridField to generate a schema dynamically
70
		$json = <<<JSON
71
{
72
	"id": "EditForm",
73
	"schema": {
74
		"name": "EditForm",
75
		"id": "EditForm",
76
		"action": "schema",
77
		"method": "GET",
78
		"schema_url": "admin\/campaigns\/schema\/EditForm",
79
		"attributes": {
80
			"id": "Form_EditForm",
81
			"action": "admin\/campaigns\/EditForm",
82
			"method": "POST",
83
			"enctype": "multipart\/form-data",
84
			"target": null,
85
			"class": "cms-edit-form CampaignAdmin LeftAndMain"
86
		},
87
		"data": [],
88
		"fields": [{
89
			"name": "ID",
90
			"id": "Form_EditForm_ID",
91
			"type": "Hidden",
92
			"component": null,
93
			"holder_id": null,
94
			"title": false,
95
			"source": null,
96
			"extraClass": "hidden nolabel",
97
			"description": null,
98
			"rightTitle": null,
99
			"leftTitle": null,
100
			"readOnly": false,
101
			"disabled": false,
102
			"customValidationMessage": "",
103
			"attributes": [],
104
			"data": []
105
		}, {
106
			"name": "ChangeSets",
107
			"id": "Form_EditForm_ChangeSets",
108
			"type": "Custom",
109
			"component": "GridField",
110
			"holder_id": null,
111
			"title": "Campaigns",
112
			"source": null,
113
			"extraClass": null,
114
			"description": null,
115
			"rightTitle": null,
116
			"leftTitle": null,
117
			"readOnly": false,
118
			"disabled": false,
119
			"customValidationMessage": "",
120
			"attributes": [],
121
			"data": {
122
				"recordType": "ChangeSet",
123
				"collectionReadEndpoint": {
124
					"url": "admin\/campaigns\/sets",
125
					"method": "GET"
126
				},
127
				"itemReadEndpoint": {
128
					"url": "admin\/campaigns\/set\/:id",
129
					"method": "GET"
130
				},
131
				"itemUpdateEndpoint": {
132
					"url": "admin\/campaigns\/set\/:id",
133
					"method": "PUT"
134
				},
135
				"itemCreateEndpoint": {
136
					"url": "admin\/campaigns\/set\/:id",
137
					"method": "POST"
138
				},
139
				"itemDeleteEndpoint": {
140
					"url": "admin\/campaigns\/set\/:id",
141
					"method": "DELETE"
142
				},
143
				"editFormSchemaEndpoint": "admin\/campaigns\/schema\/DetailEditForm",
144
				"columns": [
145
					{"name": "Title", "field": "Name"},
146
					{"name": "Changes", "field": "_embedded.ChangeSetItems.length"},
147
					{"name": "Description", "field": "Description"}
148
				]
149
			}
150
		}, {
151
			"name": "SecurityID",
152
			"id": "Form_EditForm_SecurityID",
153
			"type": "Hidden",
154
			"component": null,
155
			"holder_id": null,
156
			"title": "Security ID",
157
			"source": null,
158
			"extraClass": "hidden",
159
			"description": null,
160
			"rightTitle": null,
161
			"leftTitle": null,
162
			"readOnly": false,
163
			"disabled": false,
164
			"customValidationMessage": "",
165
			"attributes": [],
166
			"data": []
167
		}],
168
		"actions": []
169
	}
170
}
171
JSON;
172
173
		$formName = $request->param('ID');
174
		if($formName == 'EditForm') {
175
			$response = $this->getResponse();
176
			$response->addHeader('Content-Type', 'application/json');
177
			$response->setBody($json);
178
			return $response;
179
		} else {
180
			return parent::schema($request);
181
		}
182
	}
183
184
	/**
185
	 * REST endpoint to create a campaign.
186
	 *
187
	 * @param SS_HTTPRequest $request
188
	 *
189
	 * @return SS_HTTPResponse
190
	 */
191
	public function createCampaign(SS_HTTPRequest $request) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
192
		$response = new SS_HTTPResponse();
193
		$response->addHeader('Content-Type', 'application/json');
194
		$response->setBody(Convert::raw2json(['campaign' => 'create']));
195
196
		// TODO Implement permission check and data creation
197
198
		return $response;
199
	}
200
201
	/**
202
	 * REST endpoint to get a list of campaigns.
203
	 *
204
	 * @param SS_HTTPRequest $request
205
	 *
206
	 * @return SS_HTTPResponse
207
	 */
208
	public function readCampaigns(SS_HTTPRequest $request) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
209
		$response = new SS_HTTPResponse();
210
		$response->addHeader('Content-Type', 'application/json');
211
		$hal = $this->getListResource();
212
		$response->setBody(Convert::array2json($hal));
213
		return $response;
214
	}
215
216
	/**
217
	 * Get list contained as a hal wrapper
218
	 *
219
	 * @return array
220
	 */
221
	protected function getListResource() {
222
		$items = $this->getListItems();
223
		$count = $items->count();
224
		$hal = [
225
			'count' => $count,
226
			'total' => $count,
227
			'_links' => [
228
				'self' => [
229
					'href' => $this->Link('items')
230
				]
231
			],
232
			'_embedded' => ['ChangeSets' => []]
233
		];
234
		foreach($items as $item) {
235
			/** @var ChangeSet $item */
236
			$resource = $this->getChangeSetResource($item);
237
			$hal['_embedded']['ChangeSets'][] = $resource;
238
		}
239
		return $hal;
240
	}
241
242
	/**
243
	 * Build item resource from a changeset
244
	 *
245
	 * @param ChangeSet $changeSet
246
	 * @return array
247
	 */
248
	protected function getChangeSetResource(ChangeSet $changeSet) {
249
		$hal = [
250
			'_links' => [
251
				'self' => [
252
					'href' => $this->SetLink($changeSet->ID)
253
				]
254
			],
255
			'ID' => $changeSet->ID,
256
			'Name' => $changeSet->Name,
257
			'Description' => $changeSet->getDescription(),
258
			'Created' => $changeSet->Created,
259
			'LastEdited' => $changeSet->LastEdited,
260
			'State' => $changeSet->State,
261
			'_embedded' => ['ChangeSetItems' => []]
262
		];
263
		foreach($changeSet->Changes() as $changeSetItem) {
264
			if(!$changeSetItem) {
265
				continue;
266
			}
267
268
			/** @var ChangesetItem $changeSetItem */
269
			$resource = $this->getChangeSetItemResource($changeSetItem);
270
			$hal['_embedded']['ChangeSetItems'][] = $resource;
271
		}
272
		return $hal;
273
	}
274
275
	/**
276
	 * Build item resource from a changesetitem
277
	 *
278
	 * @param ChangeSetItem $changeSetItem
279
	 * @return array
280
	 */
281
	protected function getChangeSetItemResource(ChangeSetItem $changeSetItem) {
282
		$baseClass = ClassInfo::baseDataClass($changeSetItem->ObjectClass);
283
		$baseSingleton = DataObject::singleton($baseClass);
284
		$thumbnailWidth = (int)$this->config()->thumbnail_width;
285
		$thumbnailHeight = (int)$this->config()->thumbnail_height;
286
		$hal = [
287
			'_links' => [
288
				'self' => [
289
					'href' => $this->ItemLink($changeSetItem->ID)
290
				]
291
			],
292
			'ID' => $changeSetItem->ID,
293
			'Created' => $changeSetItem->Created,
294
			'LastEdited' => $changeSetItem->LastEdited,
295
			'Title' => $changeSetItem->getTitle(),
296
			'ChangeType' => $changeSetItem->getChangeType(),
297
			'Added' => $changeSetItem->Added,
298
			'ObjectClass' => $changeSetItem->ObjectClass,
299
			'ObjectID' => $changeSetItem->ObjectID,
300
			'BaseClass' => $baseClass,
301
			'Singular' => $baseSingleton->i18n_singular_name(),
302
			'Plural' => $baseSingleton->i18n_plural_name(),
303
			'Thumbnail' => $changeSetItem->ThumbnailURL($thumbnailWidth, $thumbnailHeight),
304
		];
305
		// Depending on whether the object was added implicitly or explicitly, set
306
		// other related objects.
307
		if($changeSetItem->Added === ChangeSetItem::IMPLICITLY) {
308
			$referencedItems = $changeSetItem->ReferencedBy();
309
			$referencedBy = [];
310
			foreach($referencedItems as $referencedItem) {
311
				$referencedBy[] = [
312
					'href' => $this->SetLink($referencedItem->ID)
313
				];
314
			}
315
			if($referencedBy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $referencedBy of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
316
				$hal['_links']['referenced_by'] = $referencedBy;
317
			}
318
		}
319
320
		return $hal;
321
	}
322
323
324
325
	/**
326
	 * Gets viewable list of campaigns
327
	 *
328
	 * @return SS_List
329
	 */
330
	protected function getListItems() {
331
		return ChangeSet::get()
332
			->filter('State', ChangeSet::STATE_OPEN)
333
			->filterByCallback(function($item) {
334
				return ($item->canView());
335
			});
336
	}
337
338
339
	/**
340
	 * REST endpoint to get a campaign.
341
	 *
342
	 * @param SS_HTTPRequest $request
343
	 *
344
	 * @return SS_HTTPResponse
345
	 */
346
	public function readCampaign(SS_HTTPRequest $request) {
347
		$response = new SS_HTTPResponse();
348
349
		if ($request->getHeader('Accept') == 'text/json') {
350
		$response->addHeader('Content-Type', 'application/json');
351
			$changeSet = ChangeSet::get()->byId($request->param('ID'));
352
353
			switch ($request->param('Name')) {
354
				case "edit":
355
					$response->setBody('{"message":"show the edit view"}');
356
					break;
357
				case "show":
358
					$response->setBody(Convert::raw2json($this->getChangeSetResource($changeSet)));
359
					break;
360
				default:
361
					$response->setBody('{"message":"404"}');
362
			}
363
364
		return $response;
365
366
		} else {
367
			return $this->index($request);
368
		}
369
	}
370
371
	/**
372
	 * REST endpoint to update a campaign.
373
	 *
374
	 * @param SS_HTTPRequest $request
375
	 *
376
	 * @return SS_HTTPResponse
377
	 */
378
	public function updateCampaign(SS_HTTPRequest $request) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
379
		$response = new SS_HTTPResponse();
380
		$response->addHeader('Content-Type', 'application/json');
381
		$response->setBody(Convert::raw2json(['campaign' => 'update']));
382
383
		// TODO Implement data update and permission checks
384
385
		return $response;
386
	}
387
388
	/**
389
	 * REST endpoint to delete a campaign.
390
	 *
391
	 * @param SS_HTTPRequest $request
392
	 *
393
	 * @return SS_HTTPResponse
394
	 */
395
	public function deleteCampaign(SS_HTTPRequest $request) {
396
		$id = $request->param('ID');
397
		if (!$id || !is_numeric($id)) {
398
            return (new SS_HTTPResponse(json_encode(['status' => 'error']), 400))
399
                ->addHeader('Content-Type', 'application/json');
400
        }
401
402
		$record = ChangeSet::get()->byID($id);
403
		if(!$record) {
404
			return (new SS_HTTPResponse(json_encode(['status' => 'error']), 404))
405
                ->addHeader('Content-Type', 'application/json');
406
		}
407
408
		if(!$record->canDelete()) {
409
			return (new SS_HTTPResponse(json_encode(['status' => 'error']), 401))
410
                ->addHeader('Content-Type', 'application/json');
411
		}
412
413
		$record->delete();
414
415
		return (new SS_HTTPResponse('', 204));
416
	}
417
418
	/**
419
	 * @todo Use GridFieldDetailForm once it can handle structured data and form schemas
420
	 *
421
	 * @return Form
422
	 */
423
	public function getDetailEditForm() {
424
		return Form::create(
425
			$this,
426
			'DetailEditForm',
427
			ChangeSet::singleton()->getCMSFields(),
428
			FieldList::create(
429
				FormAction::create('save', 'Save')
430
			)
431
		);
432
	}
433
434
	/**
435
	 * Gets user-visible url to edit a specific {@see ChangeSet}
436
	 *
437
	 * @param $itemID
438
	 * @return string
439
	 */
440
	public function SetLink($itemID) {
441
		return Controller::join_links(
442
			$this->Link('set'),
443
			$itemID
444
		);
445
	}
446
447
	/**
448
	 * Gets user-visible url to edit a specific {@see ChangeSetItem}
449
	 *
450
	 * @param int $itemID
451
	 * @return string
452
	 */
453
	public function ItemLink($itemID) {
454
		return Controller::join_links(
455
			$this->Link('item'),
456
			$itemID
457
		);
458
	}
459
460
	/**
461
	 *
462
	 */
463
	public function FindReferencedChanges() {
464
465
	}
466
467
}
468