Passed
Push — develop ( 3e7098...172c78 )
by Jens
02:50
created

JsonStorage::addDocument()   D

Complexity

Conditions 10
Paths 6

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 10
eloc 15
c 4
b 1
f 0
nc 6
nop 1
dl 0
loc 27
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace library\storage
3
{
4
5
	use library\crypt\Crypt;
6
	use library\images\ImageResizer;
7
8
	/**
9
	 * Class JsonStorage
10
	 * @package library\storage
11
	 */
12
	class JsonStorage implements Storage
13
	{
14
		private $storagePath;
15
		private $repository;
16
17
		/**
18
		 * JsonStorage constructor.
19
		 *
20
		 * @param $storagePath
21
		 */
22
		public function __construct($storagePath)
23
		{
24
			$this->storagePath = $storagePath;
25
			$this->config();
26
		}
27
28
		/**
29
		 * Retrieve the data from the storagepath
30
		 * so it can be interacted with
31
		 *
32
		 * @throws \Exception
33
		 */
34
		private function config()
35
		{
36
			$storagePath = __DIR__ . $this->storagePath;
37
			if (realpath($storagePath) !== false) {
38
				$jsonString = file_get_contents($storagePath);
39
				$this->repository = json_decode($jsonString);
40
			} else {
41
				// Here is some logic for the initialisation of a new clone of the framework
42
				initFramework($storagePath);
43
			}
44
		}
45
46
		/**
47
		 * @return array
48
		 */
49
		public function getApplicationComponents()
50
		{
51
			return $this->repository->applicationComponents;
52
		}
53
54
		/**
55
		 * Get user by username
56
		 *
57
		 * @param $username
58
		 *
59
		 * @return array
60
		 */
61
		public function getUserByUsername($username)
62
		{
63
			$return = array();
64
			
65
			$users = $this->repository->users;
66
			foreach ($users as $user) {
67
				if ($user->username == $username) {
68
					$return = $user;
69
					break;
70
				}
71
			}
72
			
73
			return $return;
74
		}
75
76
		public function getUserBySlug($slug)
77
		{
78
			$return = array();
79
80
			$users = $this->repository->users;
81
			foreach ($users as $user) {
82
				if ($user->slug == $slug) {
83
					$return = $user;
84
					break;
85
				}
86
			}
87
88
			return $return;
89
		}
90
91
		public function getUsers()
92
		{
93
			return $this->repository->users;
94
		}
95
96
		public function saveUser($slug, $postValues)
97
		{
98
			$userObj = $this->createUserFromPostValues($postValues);
99
			if ($userObj->slug != $slug) {
100
				// If the username changed, check for duplicates
101
				$doesItExist = $this->getUserBySlug($userObj->slug);
102
				if (!empty($doesItExist)) {
103
					throw new \Exception('Trying to rename user to existing username');
104
				}
105
			}
106
			$users = $this->getUsers();
107
			foreach ($users as $key => $user) {
108
				if ($user->slug == $slug) {
109
					$users[$key] = $userObj;
110
				}
111
			}
112
			$this->repository->users = $users;
113
			$this->save();
114
		}
115
116
		public function addUser($postValues)
117
		{
118
			$userObj = $this->createUserFromPostValues($postValues);
119
120
			$doesItExist = $this->getUserBySlug($userObj->slug);
121
			if (!empty($doesItExist)) {
122
				throw new \Exception('Trying to add username that already exists.');
123
			}
124
			$this->repository->users[] = $userObj;
125
			$this->save();
126
		}
127
128
		public function deleteUserBySlug($slug)
129
		{
130
			$userToDelete = $this->getUserBySlug($slug);
131
			if (empty($userToDelete)) {
132
				throw new \Exception('Trying to delete a user that doesn\'t exist.');
133
			}
134
			$users = $this->getUsers();
135
			foreach ($users as $key => $user) {
136
				if ($user->slug == $userToDelete->slug) {
137
					unset($users[$key]);
138
					$this->repository->users = array_values($users);
139
				}
140
			}
141
			$this->save();
142
		}
143
144
		private function createUserFromPostValues($postValues)
145
		{
146
			if (isset($postValues['username'])) {
147
				$user = new \stdClass();
148
				$user->username = $postValues['username'];
149
				$user->slug = slugify($postValues['username']);
150
				$user->rights = array();
151
				if (isset($postValues['rights'])) {
152
					$user->rights = $postValues['rights'];
153
				}
154
155
				if (isset($postValues['password']) && empty($postValues['password']) === false) {
156
					$crypt = new Crypt();
157
					$user->password = $crypt->encrypt($postValues['password'], 16);
158
					$user->salt = $crypt->getLastSalt();
159
				} else {
160
					$user->password = $postValues['passHash'];
161
					$user->salt = $postValues['salt'];
162
				}
163
164
				return $user;
165
			} else {
166
				throw new \Exception('Trying to create user with invalid data.');
167
			}
168
		}
169
170
		/*
171
		 *
172
		 * Documents
173
		 *
174
		 */
175
		/**
176
		 * Get documents
177
		 *
178
		 * @return array
179
		 */
180
		public function getDocuments()
181
		{
182
			return $this->repository->documents;
183
		}
184
185
		/**
186
		 * @param string $slug
187
		 * @return mixed
188
		 * @throws \Exception
189
		 */
190
		public function getDocumentBySlug($slug)
191
		{
192
			$documentContainer = $this->getDocumentContainerByPath('/' . $slug);
193
			$indices = $documentContainer['indices'];
194
195
			if ($indices === null) {
196
				$emptyReturn = new \stdClass();
197
				$emptyReturn->title = 'Not found';
198
				$emptyReturn->type = null;
199
				$emptyReturn->state = 'published';
200
				return $emptyReturn;
201
			}
202
203
			$folder = $this->repository->documents;
204
			foreach ($indices as $index) {
205
				if ($folder === $this->repository->documents) {
206
					$folder = $folder[$index];
207
				} else {
208
					$folder = $folder->content[$index];
209
				}
210
			}
211
212
			return $folder;
213
		}
214
215
		public function saveDocument($postValues)
216
		{
217
			$documentFolderObject = $this->createDocumentFromPostValues($postValues);
218
219
			$documentContainer = $this->getDocumentContainerByPath($_GET['slug']);
220
			$indices = $documentContainer['indices'];
221
222
			$folder = $this->repository->documents;
223
			$previousFolder = $this->repository->documents;
224
			foreach ($indices as $index) {
225
				if ($folder === $this->repository->documents) {
226
					$folder = $folder[$index];
227
				} else {
228
					$previousFolder = $folder;
229
					$folder = $folder->content[$index];
230
				}
231
			}
232
233
			if ($previousFolder === $this->repository->documents) {
234
				// Check for duplicates
235
				foreach ($this->repository->documents as $index => $document) {
236
					if (end($indices) !== $index && $document->slug == $documentFolderObject->slug && $document->type == 'document') {
237
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
238
					}
239
				}
240
				$this->repository->documents[end($indices)] = $documentFolderObject;
241
			} else {
242
				// Check for duplicates
243
				foreach ($previousFolder->content as $index => $document) {
244
					if (end($indices) !== $index && $document->slug == $documentFolderObject->slug && $document->type == 'document') {
245
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
246
					}
247
				}
248
				$previousFolder->content[end($indices)] = $documentFolderObject ;
249
			}
250
251
			$this->save();
252
		}
253
254
		public function addDocument($postValues)
255
		{
256
			$documentFolderObject = $this->createDocumentFromPostValues($postValues);
257
			if ($postValues['path'] == '' || $postValues['path'] == '/') {
258
				// Check folder duplicate child
259
				foreach ($this->repository->documents as $document) {
260
					if ($document->slug == $documentFolderObject->slug && $document->type == 'document') {
261
						// TODO make it so it doesnt throw an exception, but instead shows a warning
262
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
263
					}
264
				}
265
				$this->repository->documents[] = $documentFolderObject;
266
			} else {
267
				// Check folder duplicate child
268
				$containerFolder = $this->getDocumentFolderBySlug($postValues['path']);
269
				if (isset($containerFolder->content)) {
270
					foreach ($containerFolder->content as $document) {
271
						if ($document->slug == $documentFolderObject->slug && $document->type == 'document') {
272
							// TODO make it so it doesnt throw an exception, but instead shows a warning
273
							throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
274
						}
275
					}
276
				}
277
				$containerFolder->content[] = $documentFolderObject;
278
			}
279
			$this->save();
280
		}
281
282
		public function deleteDocumentBySlug($slug)
283
		{
284
			$documentContainer = $this->getDocumentContainerByPath($slug);
285
			$indices = $documentContainer['indices'];
286
287
			$folder = $this->repository->documents;
288
			$previousFolder = $this->repository->documents;
289
			foreach ($indices as $index) {
290
				if ($folder === $this->repository->documents) {
291
					$folder = $folder[$index];
292
				} else {
293
					$previousFolder = $folder;
294
					$folder = $folder->content[$index];
295
				}
296
			}
297
298
			if ($previousFolder === $this->repository->documents) {
299
				unset($this->repository->documents[end($indices)]);
300
				$this->repository->documents = array_values($this->repository->documents);
301
			} else {
302
				unset($previousFolder->content[end($indices)]);
303
				$previousFolder->content = array_values($previousFolder->content);
304
			}
305
306
			$this->save();
307
		}
308
309
		private function createDocumentFromPostValues($postValues)
310
		{
311
			$documentType = $this->getDocumentTypeBySlug($postValues['documentType']);
312
313
			$staticBricks = $documentType->bricks;
314
315
			$documentObj = new \stdClass();
316
			$documentObj->title = $postValues['title'];
317
			$documentObj->slug = slugify($postValues['title']);
318
			$documentObj->type = $postValues['documentType'];
319
			$documentObj->documentType = $documentType->title;
320
			$documentObj->documentTypeSlug = $documentType->slug;
321
			$documentObj->state = isset($postValues['state']) ? 'published' : 'unpublished';
322
			$documentObj->lastModificationDate = time();
323
			$documentObj->creationDate = isset($postValues['creationDate']) ? intval($postValues['creationDate']) : time();
324
			$documentObj->lastModifiedBy = $_SESSION['cloudcontrol']->username;
325
326
			$documentObj->fields = isset($postValues['fields']) ? $postValues['fields'] : array();
327
			$documentObj->bricks = array();
328
			if (isset($postValues['bricks'])) {
329
				foreach ($postValues['bricks'] as $brickSlug => $brick) {
330
					// Check if its multiple
331
					$multiple = false;
332
					foreach ($staticBricks as $staticBrick) {
333
						if ($staticBrick->slug === $brickSlug) {
334
							$multiple = $staticBrick->multiple;
335
							break;
336
						}
337
					}
338
339
					if ($multiple) {
340
						$brickArray = array();
341
						foreach ($brick as $brickInstance) {
342
							$brickObj = new \stdClass();
343
							$brickObj->fields = new \stdClass();
344
							$brickObj->type = $staticBrick->brickSlug;
0 ignored issues
show
Bug introduced by
The variable $staticBrick seems to be defined by a foreach iteration on line 332. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
345
346
							foreach ($brickInstance['fields'] as $fieldName => $fieldValues) {
347
								$brickObj->fields->$fieldName = $fieldValues;
348
							}
349
350
							$brickArray[] = $brickObj;
351
						}
352
353
						$documentObj->bricks[$brickSlug] = $brickArray;
354
					} else {
355
						$documentObj->bricks[$brickSlug] = $brick;
356
					}
357
				}
358
			}
359
			$documentObj->dynamicBricks = array();
360
			if (isset($postValues['dynamicBricks'])) {
361
				foreach ($postValues['dynamicBricks'] as $brickTypeSlug => $brick) {
362
					foreach ($brick as $brickContent) {
363
						$brickObj = new \stdClass();
364
						$brickObj->type = $brickTypeSlug;
365
						$brickObj->fields = $brickContent;
366
						$documentObj->dynamicBricks[] = $brickObj;
367
					}
368
				}
369
			}
370
			return $documentObj;
371
		}
372
373
		/**
374
		 * Add new document in given path
375
		 *
376
		 * @param array $postValues
377
		 *
378
		 * @throws \Exception
379
		 */
380
		public function addDocumentFolder($postValues)
381
		{
382
			$documentFolderObject = $this->createDocumentFolderFromPostValues($postValues);
383
			if ($postValues['path'] == '' || $postValues['path'] == '/') {
384
				// Check folder duplicate child
385
				foreach ($this->repository->documents as $document) {
386
					if ($document->slug == $documentFolderObject->slug && $document->type == 'folder') {
387
						// TODO make it so it doesnt throw an exception, but instead shows a warning
388
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
389
					}
390
				}
391
				$this->repository->documents[] = $documentFolderObject;
392
			} else {
393
				$documentContainer = $this->getDocumentContainerByPath($postValues['path']);
394
				$documentContainerArray = $documentContainer['indices'];
395
				$containerFolder = $documentContainer['containerFolder'];
396
				$folder = $this->repository->documents;
397
				foreach ($documentContainerArray as $index) {
398
					if ($folder === $this->repository->documents) {
399
						$folder = $folder[$index];
400
					} else {
401
						$folder = $folder->content[$index];
402
					}
403
404
				}
405
				// Check folder duplicate child
406
				foreach ($containerFolder->content as $document) {
407
					if ($document->slug == $documentFolderObject->slug && $document->type == 'folder') {
408
						// TODO make it so it doesnt throw an exception, but instead shows a warning
409
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
410
					}
411
				}
412
				$folder->content[] = $documentFolderObject;
413
			}
414
			$this->save();
415
		}
416
417
		/**
418
		 * Delete a folder by its compound slug
419
		 *
420
		 * @param $slug
421
		 *
422
		 * @throws \Exception
423
		 */
424
		public function deleteDocumentFolderBySlug($slug)
425
		{
426
			$documentContainer = $this->getDocumentContainerByPath($slug);
427
			$indices = $documentContainer['indices'];
428
429
			$folder = $this->repository->documents;
430
			$previousFolder = $this->repository->documents;
431
			foreach ($indices as $index) {
432
				if ($folder === $this->repository->documents) {
433
					$folder = $folder[$index];
434
				} else {
435
					$previousFolder = $folder;
436
					$folder = $folder->content[$index];
437
				}
438
			}
439
440
			if ($previousFolder === $this->repository->documents) {
441
				unset($this->repository->documents[end($indices)]);
442
				$this->repository->documents = array_values($this->repository->documents);
443
			} else {
444
				unset($previousFolder->content[end($indices)]);
445
				$previousFolder->content = array_values($previousFolder->content);
446
			}
447
448
			$this->save();
449
		}
450
451
		/**
452
		 * Retrieve a folder by its compound slug
453
		 *
454
		 * @param $slug
455
		 *
456
		 * @return mixed
457
		 * @throws \Exception
458
		 */
459
		public function getDocumentFolderBySlug($slug)
460
		{
461
			$documentContainer = $this->getDocumentContainerByPath('/' . $slug);
462
			$indices = $documentContainer['indices'];
463
464
			$folder = $this->repository->documents;
465
			foreach ($indices as $index) {
466
				if ($folder === $this->repository->documents) {
467
					$folder = $folder[$index];
468
				} else {
469
					$folder = $folder->content[$index];
470
				}
471
			}
472
473
			return $folder;
474
		}
475
476
		/**
477
		 * Save changes to folder
478
		 *
479
		 * @param $postValues
480
		 *
481
		 * @throws \Exception
482
		 */
483
		public function saveDocumentFolder($postValues)
484
		{
485
			$documentFolderObject = $this->createDocumentFolderFromPostValues($postValues);
486
487
			$documentContainer = $this->getDocumentContainerByPath($_GET['slug']);
488
			$indices = $documentContainer['indices'];
489
490
			$folder = $this->repository->documents;
491
			$previousFolder = $this->repository->documents;
492
			foreach ($indices as $index) {
493
				if ($folder === $this->repository->documents) {
494
					$folder = $folder[$index];
495
				} else {
496
					$previousFolder = $folder;
497
					$folder = $folder->content[$index];
498
				}
499
			}
500
501
			if ($previousFolder === $this->repository->documents) {
502
				// Check for duplicates
503
				foreach ($this->repository->documents as $index => $document) {
504
					if (end($indices) !== $index && $document->slug == $documentFolderObject->slug && $document->type == 'folder') {
505
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
506
					}
507
				}
508
				$this->repository->documents[end($indices)] = $documentFolderObject;
509
			} else {
510
				// Check for duplicates
511
				foreach ($previousFolder->content as $index => $document) {
512
					if (end($indices) !== $index && $document->slug == $documentFolderObject->slug && $document->type == 'folder') {
513
						throw new \Exception('Duplicate slug: ' . $document->slug . ' in folder ' . $postValues['path']);
514
					}
515
				}
516
				$previousFolder->content[end($indices)] = $documentFolderObject ;
517
			}
518
519
			$this->save();
520
		}
521
522
		/**
523
		 * Convert path to indeces
524
		 *
525
		 * @param $path
526
		 *
527
		 * @return array
528
		 * @throws \Exception
529
		 */
530
		private function getDocumentContainerByPath($path)
531
		{
532
			$slugs = explode('/', $path);
533
			$slugs = array_filter($slugs);
534
			end($slugs);
535
			$lastKey = key($slugs);
536
			$root = $this->repository->documents;
537
			$i = 0;
538
			$returnArray = array();
539
			$noMatches = 0;
540
			$foundDocument = null;
541
			$document = null;
542
			$previousDocument = null;
543
			foreach ($slugs as $slug) {
544
				$matched = false;
545
				$previousDocument = null;
546
				end($root);
547
				$lastSubKey = key($root);
548
				foreach ($root as $index => $document) {
549
					if ($slug == $document->slug) {
550
						if ($i != $lastKey && $document->type == 'folder') {
551
							$returnArray[] = $index;
552
							$root = $root[$index]->content;
553
							$matched = true;
554
						} else {
555
							$foundDocument = $document;
556
							$returnArray[] = $index;
557
							$matched = true;
558
						}
559
					}
560
561
					if ($lastSubKey != $index) {
562
						$previousDocument = $document;
563
					}
564
				}
565
				if ($matched === true) {
566
					$noMatches += 1;
567
				} else {
568
					//throw new \Exception('Unknown folder "' . $slug . '" in path: ' . $path);
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
569
					return array(
570
							'containerFolder' => new \stdClass(),
571
							'indices' => null,
572
							'document' => new \stdClass(),
573
							'previousDocument' => new \stdClass()
574
					);
575
				}
576
				$i += 1;
577
			}
578
			if ($noMatches > 0) {
579
				return array(
580
					'containerFolder' => $document,
581
					'indices' => $returnArray,
582
					'document' => $foundDocument,
583
					'previousDocument' => $previousDocument
584
				);
585
			} else {
586
				throw new \Exception('Invalid path: ' . $path);
587
			}
588
		}
589
590
		/**
591
		 * Create folder from post values
592
		 *
593
		 * @param $postValues
594
		 *
595
		 * @return \stdClass
596
		 * @throws \Exception
597
		 */
598
		private function createDocumentFolderFromPostValues($postValues)
599
		{
600
			if (isset($postValues['title'], $postValues['path'], $postValues['content'])) {
601
				$documentFolderObject = new \stdClass();
602
				$documentFolderObject->title = $postValues['title'];
603
				$documentFolderObject->slug = slugify($postValues['title']);
604
				$documentFolderObject->type = 'folder';
605
				$documentFolderObject->content = json_decode($postValues['content']);
606
607
				return $documentFolderObject;
608
			} else {
609
				throw new \Exception('Trying to create document folder with invalid data.');
610
			}
611
		}
612
613
		/*
614
		 * 
615
		 * Sitemap
616
		 *
617
		 */
618
		/**
619
		 * @return array
620
		 */
621
		public function getSitemap()
622
		{
623
			return $this->repository->sitemap;
624
		}
625
626
		/**
627
		 * Add a sitemap item
628
		 *
629
		 * @param $postValues
630
		 *
631
		 * @throws \Exception
632
		 */
633
		public function addSitemapItem($postValues) 
634
		{
635
			$sitemapObject = $this->createSitemapItemFromPostValues($postValues);
636
			
637
			$this->repository->sitemap[] = $sitemapObject;
638
			$this->save();
639
		}
640
641
		/**
642
		 * Save changes to a sitemap item
643
		 *
644
		 * @param $slug
645
		 * @param $postValues
646
		 *
647
		 * @throws \Exception
648
		 */
649
		public function saveSitemapItem($slug, $postValues)
650
		{
651
			$sitemapObject = $this->createSitemapItemFromPostValues($postValues);
652
			
653
			$sitemap = $this->repository->sitemap;
654
			foreach ($sitemap as $key => $sitemapItem) {
655
				if ($sitemapItem->slug == $slug) {
656
					$sitemap[$key] = $sitemapObject;
657
				}
658
			}
659
			$this->repository->sitemap = $sitemap;
660
			$this->save();
661
		}
662
663
		/**
664
		 * Delete a sitemap item by its slug
665
		 *
666
		 * @param $slug
667
		 *
668
		 * @throws \Exception
669
		 */
670
		public function deleteSitemapItemBySlug($slug)
671
		{
672
			$sitemap = $this->repository->sitemap;
673
			foreach ($sitemap as $key => $sitemapItem) {
674
				if ($sitemapItem->slug == $slug) {
675
					unset($sitemap[$key]);
676
				}
677
			}
678
			$sitemap = array_values($sitemap);
679
			$this->repository->sitemap = $sitemap;
680
			$this->save();
681
		}
682
683
		/**
684
		 * Create a sitemap item from post values
685
		 *
686
		 * @param $postValues
687
		 *
688
		 * @return \stdClass
689
		 * @throws \Exception
690
		 */
691
		private function createSitemapItemFromPostValues($postValues)
692
		{
693
			if (isset($postValues['title'], $postValues['url'], $postValues['component'], $postValues['template'])) {
694
				$sitemapObject = new \stdClass();
695
				$sitemapObject->title = $postValues['title'];
696
				$sitemapObject->slug = slugify($postValues['title']);
697
				$sitemapObject->url = $postValues['url'];
698
				$sitemapObject->component = $postValues['component'];
699
				$sitemapObject->template = $postValues['template'];
700
				$sitemapObject->regex = isset($postValues['regex']);
701
				$sitemapObject->parameters = new \stdClass();
702
				if (isset($postValues['parameterNames'], $postValues['parameterValues'])) {
703
					foreach ($postValues['parameterNames'] as $key => $value) {
704
						$sitemapObject->parameters->$value = $postValues['parameterValues'][$key];
705
					}
706
				}
707
				return $sitemapObject;
708
			} else {
709
				throw new \Exception('Trying to create sitemap item with invalid data.');
710
			}
711
		}
712
713
		/**
714
		 * Save changes to a sitemap item
715
		 *
716
		 * @param $postValues
717
		 *
718
		 * @throws \Exception
719
		 */
720
		public function saveSitemap($postValues)
721
		{
722
			if (isset($postValues['sitemapitem']) && is_array($postValues['sitemapitem'])) {
723
				$sitemap = array();
724
				foreach ($postValues['sitemapitem'] as $sitemapItem) {
725
					$sitemapItemObject = json_decode($sitemapItem);
726
					if (isset($sitemapItemObject->object)) {
727
						unset($sitemapItemObject->object);
728
					}
729
					$sitemap[] = $sitemapItemObject;
730
				}
731
				$this->repository->sitemap = $sitemap;
732
				$this->save();
733
			}
734
		}
735
736
		/**
737
		 * Get a sitemap item by its slug
738
		 *
739
		 * @param $slug
740
		 *
741
		 * @return mixed
742
		 */
743
		public function getSitemapItemBySlug($slug)
744
		{
745
			$sitemap = $this->repository->sitemap;
746
			foreach ($sitemap as $sitemapItem) {
747
				if ($sitemapItem->slug == $slug) {
748
					return $sitemapItem;
749
				}
750
			}
751
			return null;
752
		}
753
754
		/*
755
		 *
756
		 * Images
757
		 *
758
		 */
759
		/**
760
		 * Get all images
761
		 *
762
		 * @return array
763
		 */
764
		public function getImages()
765
		{
766
			return $this->repository->images;
767
		}
768
769
		public function addImage($postValues)
770
		{
771
			$destinationPath = realpath(__DIR__ . '/../../www/images/');
772
773
			$filename = $this->validateFilename($postValues['name'], $destinationPath);
774
			$destination = $destinationPath . '/' . $filename;
775
776
			if ($postValues['error'] != '0') {
777
				throw new \Exception('Error uploading file. Error code: ' . $postValues['error']);
778
			}
779
780
			if (move_uploaded_file($postValues['tmp_name'], $destination)) {
781
				$imageResizer = new ImageResizer($this->getImageSet());
782
				$fileNames = $imageResizer->applyImageSetToImage($destination);
783
				$fileNames['original'] = $filename;
784
				$imageObject = new \stdClass();
785
				$imageObject->file = $filename;
786
				$imageObject->type = $postValues['type'];
787
				$imageObject->size = $postValues['size'];
788
				$imageObject->set = $fileNames;
789
790
				$this->repository->images[] = $imageObject;
791
				$this->save();
792
			} else {
793
				throw new \Exception('Error moving uploaded file');
794
			}
795
		}
796
797
		public function deleteImageByName($filename)
798
		{
799
			$destinationPath = realpath(__DIR__ . '/../../www/images/');
800
801
			$images = $this->getImages();
802
803
			foreach ($images as $key => $image) {
804
				if ($image->file == $filename) {
805
					foreach ($image->set as $imageSetFilename) {
806
						$destination = $destinationPath . '/' . $imageSetFilename;
807
						if (file_exists($destination)) {
808
							unlink($destination);
809
						} else {
810
							dump($destination);
811
						}
812
					}
813
					unset($images[$key]);
814
				}
815
			}
816
817
			$this->repository->images = $images;
818
			$this->save();
819
		}
820
821
		/**
822
		 * @param $filename
823
		 * @return null
824
         */
825
		public function getImageByName($filename)
826
		{
827
			$images = $this->getImages();
828
			foreach ($images as $image) {
829
				if ($image->file == $filename) {
830
					return $image;
831
				}
832
			}
833
			return null;
834
		}
835
836
		/*
837
		 *
838
		 * Files
839
		 *
840
		 */
841
		/**
842
		 * Get all files
843
		 *
844
		 * @return array
845
		 */
846
		public function getFiles()
847
		{
848
			$files =  $this->repository->files;
849
			usort($files, array($this, 'compareFiles'));
850
			return $files;
851
		}
852
853
		private function compareFiles($a, $b)
854
		{
855
			return strcmp($a->file, $b->file);
856
		}
857
858
		public function addFile($postValues)
859
		{
860
			$destinationPath = realpath(__DIR__ . '/../../www/files/');
861
862
			$filename = $this->validateFilename($postValues['name'], $destinationPath);
863
			$destination = $destinationPath . '/' . $filename;
864
865
			if ($postValues['error'] != '0') {
866
				throw new \Exception('Error uploading file. Error code: ' . $postValues['error']);
867
			}
868
869
			if (move_uploaded_file($postValues['tmp_name'], $destination)) {
870
				$file = new \stdClass();
871
				$file->file = $filename;
872
				$file->type = $postValues['type'];
873
				$file->size = $postValues['size'];
874
875
				$this->repository->files[] = $file;
876
				$this->save();
877
			} else {
878
				throw new \Exception('Error moving uploaded file');
879
			}
880
		}
881
882
		private function validateFilename($filename, $path)
883
		{
884
			$fileParts = explode('.', $filename);
885
			if (count($fileParts) > 1) {
886
				$extension = end($fileParts);
887
				array_pop($fileParts);
888
				$fileNameWithoutExtension = implode('-', $fileParts);
889
				$fileNameWithoutExtension = slugify($fileNameWithoutExtension);
890
				$filename = $fileNameWithoutExtension . '.' . $extension;
891
			} else {
892
				$filename = slugify($filename);
893
			}
894
895
			if (file_exists($path . '/' . $filename)) {
896
				$fileParts = explode('.', $filename);
897
				if (count($fileParts) > 1) {
898
					$extension = end($fileParts);
899
					array_pop($fileParts);
900
					$fileNameWithoutExtension = implode('-', $fileParts);
901
					$fileNameWithoutExtension .= '-copy';
902
					$filename = $fileNameWithoutExtension . '.' . $extension;
903
				} else {
904
					$filename .= '-copy';
905
				}
906
				return $this->validateFilename($filename,$path);
907
			}
908
			return $filename;
909
		}
910
911
		/**
912
		 * @param $filename
913
		 * @return null
914
         */
915
		public function getFileByName($filename)
916
		{
917
			$files = $this->getFiles();
918
			foreach ($files as $file) {
919
				if ($filename == $file->file) {
920
					return $file;
921
				}
922
			}
923
			return null;
924
		}
925
926
		/**
927
		 * @param $filename
928
		 * @throws \Exception
929
         */
930
		public function deleteFileByName($filename)
931
		{
932
			$destinationPath = realpath(__DIR__ . '/../../www/files/');
933
			$destination = $destinationPath . '/' . $filename;
934
935
			if (file_exists($destination)) {
936
				$files = $this->getFiles();
937
				foreach ($files as $key => $file) {
938
					if ($file->file == $filename) {
939
						unlink($destination);
940
						unset($files[$key]);
941
					}
942
				}
943
944
				$files = array_values($files);
945
				$this->repository->files = $files;
946
				$this->save();
947
			}
948
		}
949
950
		/*
951
		 * 
952
		 * Configuration
953
		 *
954
		 */
955
		/**
956
		 * @return array
957
		 */
958
		public function getDocumentTypes()
959
		{
960
			return $this->repository->documentTypes;
961
		}
962
963
		/**
964
		 * Add a document type from post values
965
		 *
966
		 * @param $postValues
967
		 *
968
		 * @throws \Exception
969
		 */
970
		public function addDocumentType($postValues)
971
		{
972
			$documentTypeObject = $this->createDocumentTypeFromPostValues($postValues);
973
			
974
			$this->repository->documentTypes[] = $documentTypeObject;
975
			$this->save();
976
		}
977
978
		/**
979
		 * Create a document type from post values
980
		 *
981
		 * @param $postValues
982
		 *
983
		 * @return \stdClass
984
		 * @throws \Exception
985
		 */
986
		public function createDocumentTypeFromPostValues($postValues)
987
		{
988
			if (isset($postValues['title'])) {
989
				$documentTypeObject = new \stdClass();
990
				$documentTypeObject->title = $postValues['title'];
991
				$documentTypeObject->slug = slugify($postValues['title']);
992
				$documentTypeObject->fields = array();
993
				$documentTypeObject->bricks = array();
994
				$documentTypeObject->dynamicBricks = isset($postValues['dynamicBricks']) ? $postValues['dynamicBricks'] : array();
995
				if (isset($postValues['fieldTitles'], $postValues['fieldTypes'], $postValues['fieldRequired'], $postValues['fieldMultiple'])) {
996
					foreach ($postValues['fieldTitles'] as $key => $value) {
997
						$fieldObject = new \stdClass();
998
						$fieldObject->title = $value;
999
						$fieldObject->slug = slugify($value);
1000
						$fieldObject->type = $postValues['fieldTypes'][$key];
1001
						$fieldObject->required = ($postValues['fieldRequired'][$key] === 'true');
1002
						$fieldObject->multiple = ($postValues['fieldMultiple'][$key] === 'true');
1003
						
1004
						$documentTypeObject->fields[] = $fieldObject;
1005
					}
1006
				}
1007
				if (isset($postValues['brickTitles'], $postValues['brickBricks'])) {
1008
					foreach ($postValues['brickTitles'] as $key => $value) {
1009
						$brickObject = new \stdClass();
1010
						$brickObject->title = $value;
1011
						$brickObject->slug = slugify($value);
1012
						$brickObject->brickSlug = $postValues['brickBricks'][$key];
1013
						$brickObject->multiple = ($postValues['brickMultiples'][$key] === 'true');
1014
1015
						$documentTypeObject->bricks[] = $brickObject;
1016
					}
1017
				}
1018
				return $documentTypeObject;
1019
			} else {
1020
				throw new \Exception('Trying to create document type with invalid data.');
1021
			}
1022
		}
1023
1024
		/**
1025
		 * Delete document type
1026
		 *
1027
		 * @param $slug
1028
		 *
1029
		 * @throws \Exception
1030
		 */
1031
		public function deleteDocumentTypeBySlug($slug)
1032
		{
1033
			$documentTypes = $this->repository->documentTypes;
1034
			foreach ($documentTypes as $key => $documentTypeObject) {
1035
				if ($documentTypeObject->slug == $slug) {
1036
					unset($documentTypes[$key]);
1037
				}
1038
			}
1039
			$documentTypes = array_values($documentTypes);
1040
			$this->repository->documentTypes = $documentTypes;
1041
			$this->save();
1042
		}
1043
1044
		/**
1045
		 * Get document type by its slug
1046
		 *
1047
		 * @param      $slug
1048
		 * @param bool $getBricks
1049
		 *
1050
		 * @return mixed
1051
		 */
1052
		public function getDocumentTypeBySlug($slug, $getBricks = false)
1053
		{
1054
			$documentTypes = $this->repository->documentTypes;
1055
			foreach ($documentTypes as $documentType) {
1056
				if ($documentType->slug == $slug) {
1057
					if ($getBricks === true) {
1058
						foreach ($documentType->bricks as $key => $brick) {
1059
							$brickStructure = $this->getBrickBySlug($brick->brickSlug);
1060
							$documentType->bricks[$key]->structure = $brickStructure;
1061
						}
1062
						foreach ($documentType->dynamicBricks as $key => $brickSlug) {
1063
							$brickStructure = $this->getBrickBySlug($brickSlug);
1064
							$documentType->dynamicBricks[$key] = $brickStructure;
1065
						}
1066
					}
1067
					return $documentType;
1068
				}
1069
			}
1070
			return null;
1071
		}
1072
1073
		/**
1074
		 * Save changes to a document type
1075
		 *
1076
		 * @param $slug
1077
		 * @param $postValues
1078
		 *
1079
		 * @throws \Exception
1080
		 */
1081
		public function saveDocumentType($slug, $postValues)
1082
		{
1083
			$documentTypeObject = $this->createDocumentTypeFromPostValues($postValues);
1084
			
1085
			$documentTypes = $this->repository->documentTypes;
1086
			foreach ($documentTypes as $key => $documentType) {
1087
				if ($documentType->slug == $slug) {
1088
					$documentTypes[$key] = $documentTypeObject;
1089
				}
1090
			}
1091
			$this->repository->documentTypes = $documentTypes;
1092
			$this->save();
1093
		}
1094
		
1095
		/*
1096
		 *
1097
		 * Bricks
1098
		 *
1099
		 */
1100
		/**
1101
		 * @return array
1102
		 */
1103
		public function getBricks()
1104
		{
1105
			return $this->repository->bricks;
1106
		}
1107
1108
		/**
1109
		 * Add a brick
1110
		 *
1111
		 * @param $postValues
1112
		 *
1113
		 * @throws \Exception
1114
		 */
1115
		public function addBrick($postValues)
1116
		{
1117
			$brickObject = $this->createBrickFromPostValues($postValues);
1118
			
1119
			$this->repository->bricks[] = $brickObject;
1120
			$this->save();
1121
		}
1122
1123
		/**
1124
		 * Create a brick from post values
1125
		 *
1126
		 * @param $postValues
1127
		 *
1128
		 * @return \stdClass
1129
		 * @throws \Exception
1130
		 */
1131
		public function createBrickFromPostValues($postValues)
1132
		{
1133
			if (isset($postValues['title'])) {
1134
				$brickObject = new \stdClass();
1135
				$brickObject->title = $postValues['title'];
1136
				$brickObject->slug = slugify($postValues['title']);
1137
				$brickObject->fields = array();
1138
				if (isset($postValues['fieldTitles'], $postValues['fieldTypes'], $postValues['fieldRequired'], $postValues['fieldMultiple'])) {
1139
					foreach ($postValues['fieldTitles'] as $key => $value) {
1140
						$fieldObject = new \stdClass();
1141
						$fieldObject->title = $value;
1142
						$fieldObject->slug = slugify($value);
1143
						$fieldObject->type = $postValues['fieldTypes'][$key];
1144
						$fieldObject->required = ($postValues['fieldRequired'][$key] === 'true');
1145
						$fieldObject->multiple = ($postValues['fieldMultiple'][$key] === 'true');
1146
						
1147
						$brickObject->fields[] = $fieldObject;
1148
					}
1149
				}
1150
				return $brickObject;
1151
			} else {
1152
				throw new \Exception('Trying to create document type with invalid data.');
1153
			}
1154
		}
1155
1156
		/**
1157
		 * Get a brick by its slug
1158
		 *
1159
		 * @param $slug
1160
		 *
1161
		 * @return \stdClass
1162
		 */
1163
		public function getBrickBySlug($slug)
1164
		{
1165
			$bricks = $this->repository->bricks;
1166
			foreach ($bricks as $brick) {
1167
				if ($brick->slug == $slug) {
1168
					return $brick;
1169
				}
1170
			}
1171
			return null;
1172
		}
1173
1174
		/**
1175
		 * Save changes to a brick
1176
		 *
1177
		 * @param $slug
1178
		 * @param $postValues
1179
		 *
1180
		 * @throws \Exception
1181
		 */
1182
		public function saveBrick($slug, $postValues)
1183
		{
1184
			$brickObject = $this->createBrickFromPostValues($postValues);
1185
			
1186
			$bricks = $this->repository->bricks;
1187
			foreach ($bricks as $key => $brick) {
1188
				if ($brick->slug == $slug) {
1189
					$bricks[$key] = $brickObject;
1190
				}
1191
			}
1192
			$this->repository->bricks = $bricks;
1193
			$this->save();
1194
		}
1195
1196
		/**
1197
		 * Delete a brick by its slug
1198
		 *
1199
		 * @param $slug
1200
		 *
1201
		 * @throws \Exception
1202
		 */
1203
		public function deleteBrickBySlug($slug)
1204
		{
1205
			$bricks = $this->repository->bricks;
1206
			foreach ($bricks as $key => $brickObject) {
1207
				if ($brickObject->slug == $slug) {
1208
					unset($bricks[$key]);
1209
				}
1210
			}
1211
			
1212
			$bricks = array_values($bricks);
1213
			$this->repository->bricks = $bricks;
1214
			$this->save();
1215
		}
1216
		
1217
		/*
1218
		 * 
1219
		 * Misc
1220
		 *
1221
		 */
1222
		/**
1223
		 * Save changes made to the repository
1224
		 * in the storagepath
1225
		 *
1226
		 * @throws \Exception
1227
		 */
1228
		private function save() {
1229
			$storagePath = __DIR__ . $this->storagePath;
1230
			if (realpath($storagePath) !== false) {
1231
				file_put_contents($storagePath, json_encode($this->repository));
1232
			} else {
1233
				throw new \Exception('Couldnt find storagePath ' . $storagePath);
1234
			}
1235
		}
1236
1237
		/*
1238
		 *
1239
		 * Image Set
1240
		 *
1241
		 */
1242
1243
		/**
1244
		 * Get the image set
1245
		 *
1246
		 * @return array
1247
		 */
1248
		public function getImageSet()
1249
		{
1250
			return $this->repository->imageSet;
1251
		}
1252
1253
		/**
1254
		 * Get Image by slug
1255
		 *
1256
		 * @param $slug
1257
		 *
1258
		 * @return \stdClass
1259
		 */
1260
		public function getImageSetBySlug($slug)
1261
		{
1262
			$imageSet = $this->getImageSet();
1263
			foreach ($imageSet as $set) {
1264
				if ($set->slug == $slug) {
1265
					return $set;
1266
				}
1267
			}
1268
			return null;
1269
		}
1270
1271
		/**
1272
		 * Save Image Set by it's slug
1273
		 *
1274
		 * @param $slug
1275
		 * @param $postValues
1276
		 *
1277
		 * @throws \Exception
1278
		 */
1279
		public function saveImageSet($slug, $postValues)
1280
		{
1281
			$imageSetObject = $this->createImageSetFromPostValues($postValues);
1282
1283
			$imageSet = $this->repository->imageSet;
1284
			foreach ($imageSet as $key => $set) {
1285
				if ($set->slug == $slug) {
1286
					$imageSet[$key] = $imageSetObject;
1287
				}
1288
			}
1289
			$this->repository->imageSet = $imageSet;
1290
			$this->save();
1291
		}
1292
1293
		/**
1294
		 * Ceate image set from post values
1295
		 *
1296
		 * @param $postValues
1297
		 *
1298
		 * @return \stdClass
1299
		 * @throws \Exception
1300
		 */
1301
		private function createImageSetFromPostValues($postValues)
1302
		{
1303
			if (isset($postValues['title'], $postValues['width'], $postValues['height'], $postValues['method'])) {
1304
				$imageSetObject = new \stdClass();
1305
1306
				$imageSetObject->title = $postValues['title'];
1307
				$imageSetObject->slug = slugify($postValues['title']);
1308
				$imageSetObject->width = $postValues['width'];
1309
				$imageSetObject->height = $postValues['height'];
1310
				$imageSetObject->method = $postValues['method'];
1311
1312
				return $imageSetObject;
1313
			} else {
1314
				throw new \Exception('Trying to create image set with invalid data.');
1315
			}
1316
		}
1317
1318
		/**
1319
		 * Add image set
1320
		 *
1321
		 * @param $postValues
1322
		 *
1323
		 * @throws \Exception
1324
		 */
1325
		public function addImageSet($postValues)
1326
		{
1327
			$imageSetObject = $this->createImageSetFromPostValues($postValues);
1328
1329
			$this->repository->imageSet[] = $imageSetObject;
1330
1331
			$this->save();
1332
		}
1333
1334
		/**
1335
		 * Delete Image Set by its slug
1336
		 *
1337
		 * @param $slug
1338
		 *
1339
		 * @throws \Exception
1340
		 */
1341
		public function deleteImageSetBySlug($slug)
1342
		{
1343
			$imageSet = $this->getImageSet();
1344
1345
			foreach ($imageSet as $key => $set) {
1346
				if ($set->slug == $slug) {
1347
					unset($imageSet[$key]);
1348
				}
1349
			}
1350
			$imageSet = array_values($imageSet);
1351
			$this->repository->imageSet = $imageSet;
1352
			$this->save();
1353
		}
1354
1355
		/**
1356
		 * Get the image set with the smallest size
1357
		 *
1358
		 * @return \stdClass
1359
		 */
1360
		public function getSmallestImageSet()
1361
		{
1362
			$imageSet = $this->getImageSet();
1363
1364
			$returnSize = PHP_INT_MAX;
1365
			$returnSet = null;
1366
1367
			foreach ($imageSet as $set) {
1368
				$size = $set->width * $set->height;
1369
				if ($size < $returnSize) {
1370
					$returnSize = $size;
1371
					$returnSet = $set;
1372
				}
1373
			}
1374
1375
			if ($returnSet === null) {
1376
				$returnSet = new \stdClass();
1377
				$returnSet->slug = 'original';
1378
			}
1379
1380
			return $returnSet;
1381
		}
1382
	}
1383
}