PageEditPage::save()   F
last analyzed

Complexity

Conditions 34
Paths 181

Size

Total Lines 135
Code Lines 70

Duplication

Lines 0
Ratio 0 %

Importance

Changes 15
Bugs 3 Features 7
Metric Value
cc 34
eloc 70
c 15
b 3
f 7
nc 181
nop 1
dl 0
loc 135
rs 3.4916

How to fix   Long Method    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
3
/**
4
 * Copyright (c) 2018 Justin Kuenzel (jukusoft.com)
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
20
/**
21
 * Project: RocketCMS
22
 * License: Apache 2.0 license
23
 * User: Justin
24
 * Date: 03.09.2018
25
 * Time: 14:36
26
 */
27
28
class PageEditPage extends PageType {
29
30
	protected $sitemap_change_frequencies = array(
31
		"AlWAYS", "HOURLY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY", "NEVER"
32
	);
33
34
	public function getContent(): string {
35
		$template = new DwooTemplate("pages/editpage");
36
37
		//check, if pageID is set
38
		if (!isset($_REQUEST['edit']) || empty($_REQUEST['edit'])) {
39
			//show error
40
			return $this->showError("No pageID was set!");
41
		}
42
43
		$pageID = (int) $_REQUEST['edit'];
44
45
		$page = new Page();
46
		$page->loadByID($pageID);
47
48
		//first check permissions
49
		if (!PermissionChecker::current()->hasRight("can_edit_all_pages") && !(PermissionChecker::current()->hasRight("can_edit_own_pages") && $page->getAuthorID() == User::current()->getID())) {
50
			//user doesn't have permissions to edit this page
51
			return $this->showError("You don't have permissions to edit this page!");
52
		}
53
54
		//first, lock page
55
		Page::lockPage($page->getPageID(), User::current()->getID());
56
57
		$success_messages = array();
58
		$error_messages = array();
59
60
		//save page
61
		if (isset($_REQUEST['submit'])) {
62
			if ($_REQUEST['submit'] === "Save") {
63
				//save page
64
				$res = $this->save($page);
65
66
				if ($res === true) {
67
					$success_messages[] = "Saved page successfully!";
68
				} else {
69
					$error_messages[] = $res;
70
				}
71
			} else if ($_REQUEST['submit'] === "SaveUnlock") {
72
				//save page
73
				$res = $this->save($page);
74
75
				if ($res === true) {
76
					//unlock page
77
					Page::unlockPage($page->getPageID());
78
79
					//redirect to admin/pages
80
					header("Location: " . DomainUtils::generateURL("admin/pages"));
81
82
					ob_flush();
83
					ob_end_flush();
84
85
					exit;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
86
				} else {
87
					$error_messages[] = $res;
88
				}
89
			} else if ($_REQUEST['submit'] === "Publish") {
90
				//save page
91
				$res = $this->save($page);
92
93
				if ($res === true) {
94
					$success_messages[] = "Saved page successfully!";
95
				} else {
96
					$error_messages[] = $res;
97
				}
98
99
				//publish page
100
				$res = $this->publish($page);
101
102
				if ($res === true) {
103
					$success_messages[] = "Page published successfully!";
104
				} else {
105
					$error_messages[] = $res;
106
				}
107
			}
108
		}
109
110
		$template->assign("action_url", DomainUtils::generateURL($this->getPage()->getAlias(), array("edit" => $pageID)));
111
112
		$template->assign("page", array(
113
			'id' => $page->getPageID(),
114
			'alias' => "/" . $page->getAlias(),
115
			'title' => $page->getTitle(),
116
			'content' => $page->getContent(),
117
			'is_published' => $page->isPublished(),
118
			'can_publish' => (!$page->isPublished() && (PermissionChecker::current()->hasRight("can_publish_all_pages") || (PermissionChecker::current()->hasRight("can_publish_own_pages") && $page->getAuthorID() == User::current()->getID()))),
119
			'can_change_owner' => (PermissionChecker::current()->hasRight("can_change_page_owner") || $page->getAuthorID() == User::current()->getID()),
120
			'folder' => $page->getFolder(),
121
			'preview_url' => DomainUtils::generateURL($page->getAlias(), array("preview" => "true")),
122
			'current_style' => $page->getStyle(),
123
			'template' => $page->getCustomTemplate(),
124
			'has_custom_template' => $page->hasCustomTemplate(),
125
			'parent' => $page->getParentID(),
126
			'meta_description' => $page->getMetaDescription(),
127
			'meta_keywords' => $page->getMetaKeywords(),
128
			'meta_robots' => $page->getMetaRobotsOptions(),
129
			'meta_canonicals' => $page->getMetaCanonicals(),
130
			'has_canoncials' => !empty($page->getMetaCanonicals()),
131
			'sitemap' => $page->isSitemapEnabled(),
132
			'sitemap_changefreq' => $page->getSitemapChangeFreq(),
133
			'sitemap_priority' => $page->getSitemapPriority(),
134
			'og_type' => $page->getOgType(),
135
			'og_title' => $page->getOgTitle(),
136
			'og_description' => $page->getOgDescription()
137
		));
138
139
		//set available styles
140
		$template->assign("styles", StyleController::listAllStyles());
141
142
		//get all pages from database
143
		$pages = array();
144
		$rows = Database::getInstance()->listRows("SELECT `id`, `alias` FROM `{praefix}pages` WHERE `editable` = '1' AND `activated` = '1'; ");
145
146
		foreach ($rows as $row) {
147
			$pages[] = array(
148
				'id' => $row['id'],
149
				'alias' => $row['alias']
150
			);
151
		}
152
153
		$template->assign("parent_pages", $pages);
154
155
		//https://developers.google.com/search/reference/robots_meta_tag?hl=de
156
		$robots_options = array(
157
			"all",
158
			"noindex",
159
			"nofollow",
160
			"none",
161
			"noarchive",
162
			"nosnippet",
163
			"noodp",
164
			"notranslate",
165
			"noimageindex",
166
			"unavailable_after: "
167
		);
168
169
		$template->assign("robots_options", $robots_options);
170
171
		$sitemap_change_frequencies = $this->sitemap_change_frequencies;
172
173
		$template->assign("sitemap_change_frequencies", $sitemap_change_frequencies);
174
175
		//OpenGraph types,https://developers.facebook.com/docs/reference/opengraph/
176
		$og_types = array("website", "article", "book", "profile");
177
178
		$template->assign("og_types", $og_types);
179
180
		//add support to show additional code from plugins
181
		$additional_code_header = "";
182
		$additional_code_footer = "";
183
		$additional_seo_code_header = "";
184
		$additional_seo_code_footer = "";
185
186
		Events::throwEvent("page_edit_additional_code_header", array(
187
			'page' => &$page,
188
			'code' => &$additional_code_header
189
		));
190
191
		$template->assign("additional_code_header", $additional_code_header);
192
193
		Events::throwEvent("page_edit_additional_code_footer", array(
194
			'page' => &$page,
195
			'code' => &$additional_code_footer
196
		));
197
198
		$template->assign("additional_code_footer", $additional_code_footer);
199
200
		Events::throwEvent("pageedit_additional_seo_code", array(
201
			'page' => &$page,
202
			'seo_header' => &$additional_seo_code_header,
203
			'seo_footer' => &$additional_seo_code_footer
204
		));
205
206
		$template->assign("additional_seo_code_header", $additional_seo_code_header);
207
		$template->assign("additional_seo_code_footer", $additional_seo_code_footer);
208
209
		$template->assign("errors", $error_messages);
210
		$template->assign("success_messages", $success_messages);
211
212
		return $template->getCode();
213
	}
214
215
	protected function save (Page &$page) {
216
		//first check permissions
217
		if (!PermissionChecker::current()->hasRight("can_edit_all_pages") && !(PermissionChecker::current()->hasRight("can_edit_own_pages") && $page->getAuthorID() == User::current()->getID())) {
218
			//user doesn't have permissions to edit this page
219
			return "You don't have permissions to edit this page!";
220
		}
221
222
		if (!isset($_POST['title']) || empty($_POST['title'])) {
223
			return "No title was set";
224
		}
225
226
		//validate title
227
		$title = htmlentities($_POST['title']);
228
229
		if (!isset($_POST['html_code']) || empty($_POST['html_code'])) {
230
			return "No content was set or content is empty!";
231
		}
232
233
		$content = $_POST['html_code'];
234
235
		//TODO: save page attributes
236
		if (!isset($_REQUEST['parent']) || empty($_REQUEST['parent'])) {
237
			return "Parent page wasn't set!";
238
		}
239
240
		$parent = (int) $_REQUEST['parent'];
241
242
		if (!isset($_REQUEST['design']) || empty($_REQUEST['design'])) {
243
			return "Design wasn't set!";
244
		}
245
246
		$design = $_REQUEST['design'];
247
248
		//TODO: check, if style (design) exists
249
250
		$template = "none";
251
252
		if (isset($_REQUEST['has_custom_template']) && isset($_REQUEST['template']) && !empty($_REQUEST['template'])) {
253
			$template = $_REQUEST['template'];
254
		}
255
256
		$keywords = "";
257
258
		if (!isset($_REQUEST['meta_keywords']) || empty($_REQUEST['meta_keywords'])) {
259
			//return "Meta keywords wasn't set!";
260
		} else {
261
			$keywords = htmlentities($_REQUEST['meta_keywords']);
262
		}
263
264
		$robots = "";
265
266
		if (!isset($_REQUEST['meta_robots']) || empty($_REQUEST['meta_robots'])) {
267
			//return "Meta robots wasn't set!";
268
		} else {
269
			$robots = htmlentities($_REQUEST['meta_robots']);
270
		}
271
272
		$canoncials = "";
273
274
		if (isset($_REQUEST['has_canoncials']) && isset($_REQUEST['meta_canoncials']) && !empty($_REQUEST['meta_canoncials'])) {
275
			$canoncials = $_REQUEST['meta_canoncials'];
276
		}
277
278
		$sitemap = 0;
279
		$sitemap_changefreq = "WEEKLY";
280
		$sitemap_priority = 0.5;
281
282
		if (isset($_REQUEST['sitemap'])) {
283
			$sitemap = 1;
284
285
			if (!isset($_REQUEST['sitemap_changefreq']) || empty($_REQUEST['sitemap_changefreq'])) {
286
				return "Sitemap change frequency wasn't set!";
287
			}
288
289
			$sitemap_changefreq = $_REQUEST['sitemap_changefreq'];
290
291
			if (!in_array($sitemap_changefreq, $this->sitemap_change_frequencies)) {
292
				return "Invalide value for sitemap change frequency: " . $sitemap_changefreq;
293
			}
294
295
			if (!isset($_REQUEST['sitemap_priority']) || empty($_REQUEST['sitemap_priority'])) {
296
				return "Sitemap priority wasn't set!";
297
			}
298
299
			$sitemap_priority = (float) str_replace(",", ".", $_REQUEST['sitemap_priority']);
300
301
			if ($sitemap_priority < 0) {
302
				return "Minimum value of sitemap priority is 0.";
303
			}
304
305
			if ($sitemap_priority > 1) {
306
				return "Maximum value of sitemap priority is 1.";
307
			}
308
		}
309
310
		if (!isset($_REQUEST['og_type']) || empty($_REQUEST['og_type'])) {
311
			return "OpenGraph type wasn't set!";
312
		}
313
314
		$og_type = $_REQUEST['og_type'];
315
316
		if (!isset($_REQUEST['og_title']) || empty($_REQUEST['og_title'])) {
317
			return "OpenGraph title wasn't set!";
318
		}
319
320
		$og_title = htmlentities($_REQUEST['og_title']);
321
322
		//update page in database
323
		Database::getInstance()->execute("UPDATE `{praefix}pages` SET `title` = :title, `content` = :content, `parent` = :parent, `design` = :design, `template` = :template, `sitemap` = :sitemap, `sitemap_changefreq` = :sitemap_changefreq, `sitemap_priority` = :sitemap_priority, `meta_keywords` = :keywords, `meta_robots` = :robots, `meta_canonicals` = :canoncials, `og_type` = :og_type, `og_title` = :og_title WHERE `id` = :pageID; ", array(
324
			'title' => $title,
325
			'content' => $content,
326
			'pageID' => $page->getPageID(),
327
			'parent' => $parent,
328
			'design' => $design,
329
			'template' => $template,
330
			'sitemap' => $sitemap,
331
			'sitemap_changefreq' => $sitemap_changefreq,
332
			'sitemap_priority' => $sitemap_priority,
333
			'keywords' => $keywords,
334
			'robots' => $robots,
335
			'canoncials' => $canoncials,
336
			'og_type' => $og_type,
337
			'og_title' => $og_title
338
		));
339
340
		//clear cache
341
		$page->clearCache();
342
343
		//reload page from database
344
		$page->loadByID($page->getPageID(), false);
345
346
		//TODO: remove this line later
347
		Cache::clear("pages");
348
349
		return true;
350
	}
351
352
	protected function publish (Page &$page) {
353
		//check permissions for publishing
354
		if (PermissionChecker::current()->hasRight("can_publish_all_pages") || (PermissionChecker::current()->hasRight("can_publish_own_pages") && $page->getAuthorID() == User::current()->getID())) {
355
			//update page in database
356
			Database::getInstance()->execute("UPDATE `{praefix}pages` SET `published` = '1' WHERE `id` = :pageID; ", array(
357
				'pageID' => $page->getPageID()
358
			));
359
360
			//clear cache
361
			$page->clearCache();
362
363
			//reload page from database
364
			$page->loadByID($page->getPageID(), false);
365
366
			//TODO: remove this line later
367
			Cache::clear("pages");
368
369
			return true;
370
		} else {
371
			return "You don't have the permissions to publish this page!";
372
		}
373
	}
374
375
	protected function showError (string $message) : string {
0 ignored issues
show
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

375
	protected function showError (/** @scrutinizer ignore-unused */ string $message) : string {

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

Loading history...
376
		//show error
377
		$template = new DwooTemplate("pages/error");
378
		$template->assign("message", "No pageID was set!");
379
		return $template->getCode();
380
	}
381
382
	public function getFooterScripts(): string {
383
		$style_name = Registry::singleton()->getSetting("current_style_name");
384
		$style_path = DomainUtils::getBaseURL() . "/styles/" . $style_name . "/";
0 ignored issues
show
Unused Code introduced by
The assignment to $style_path is dead and can be removed.
Loading history...
385
386
		$thirdparty_url = Registry::singleton()->getSetting("thirdparty_url");
387
388
		/*return "<!-- CK Editor -->
389
			<script src=\"" . $style_path . "bower_components/ckeditor/ckeditor.js\"></script>
390
			
391
			<script>
392
				$(function () {
393
					// Replace the <textarea id=\"editor1\"> with a CKEditor
394
					// instance, using default configuration.
395
					CKEDITOR.replace('wysiwygEditor', {
396
						height: '500px',
397
						enterMode: CKEDITOR.ENTER_BR
398
					});
399
				});
400
			</script>";*/
401
402
		return "<script src=\"" . $thirdparty_url . "tinymce_4.8.2/js/tinymce/tinymce.min.js\"></script>
403
  				<script>tinymce.init({
404
					  selector: '#wysiwygEditor',
405
					  height: 500,
406
					  theme: 'modern',
407
					  removed_menuitems: 'newdocument',
408
					  plugins: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount imagetools contextmenu colorpicker textpattern help',
409
					  toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify  | numlist bullist outdent indent  | removeformat',
410
					  image_advtab: true
411
				});
412
				
413
				document.getElementById('customTplCheckbox').onchange = function() {
414
					document.getElementById('inputTpl').disabled = !this.checked;
415
					
416
					if (!this.checked) {
417
						document.getElementById('inputTpl').value = 'none';
418
					}
419
				};
420
				
421
				document.getElementById('customCanoncialsCheckbox').onchange = function() {
422
					document.getElementById('inputCanoncials').disabled = !this.checked;
423
					
424
					if (!this.checked) {
425
						document.getElementById('inputCanoncials').value = '';
426
					}
427
				};
428
				
429
				document.getElementById('inputSitemap').onchange = function() {
430
					document.getElementById('inputSitemapChangeFrequency').disabled = !this.checked;
431
					document.getElementById('inputSitemapPriority').disabled = !this.checked;
432
				};
433
				</script>";
434
	}
435
436
	public function listRequiredPermissions(): array {
437
		return array("can_edit_all_pages", "can_edit_own_pages");
438
	}
439
440
}
441
442
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
443