Completed
Push — master ( 6b7dd4...0b91cf )
by Justin
04:42
created

PageEditPage::save()   F

Complexity

Conditions 32
Paths 149

Size

Total Lines 128
Code Lines 66

Duplication

Lines 0
Ratio 0 %

Importance

Changes 14
Bugs 3 Features 6
Metric Value
cc 32
eloc 66
c 14
b 3
f 6
nc 149
nop 1
dl 0
loc 128
rs 3.7583

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
		));
136
137
		//set available styles
138
		$template->assign("styles", StyleController::listAllStyles());
139
140
		//get all pages from database
141
		$pages = array();
142
		$rows = Database::getInstance()->listRows("SELECT `id`, `alias` FROM `{praefix}pages` WHERE `editable` = '1' AND `activated` = '1'; ");
143
144
		foreach ($rows as $row) {
145
			$pages[] = array(
146
				'id' => $row['id'],
147
				'alias' => $row['alias']
148
			);
149
		}
150
151
		$template->assign("parent_pages", $pages);
152
153
		//https://developers.google.com/search/reference/robots_meta_tag?hl=de
154
		$robots_options = array(
155
			"all",
156
			"noindex",
157
			"nofollow",
158
			"none",
159
			"noarchive",
160
			"nosnippet",
161
			"noodp",
162
			"notranslate",
163
			"noimageindex",
164
			"unavailable_after: "
165
		);
166
167
		$template->assign("robots_options", $robots_options);
168
169
		$sitemap_change_frequencies = $this->sitemap_change_frequencies;
170
171
		$template->assign("sitemap_change_frequencies", $sitemap_change_frequencies);
172
173
		//OpenGraph types,https://developers.facebook.com/docs/reference/opengraph/
174
		$og_types = array("website", "article", "book", "profile");
175
176
		$template->assign("og_types", $og_types);
177
178
		//add support to show additional code from plugins
179
		$additional_code_header = "";
180
		$additional_code_footer = "";
181
182
		Events::throwEvent("page_edit_additional_code_header", array(
183
			'page' => &$page,
184
			'code' => &$additional_code_header
185
		));
186
187
		$template->assign("additional_code_header", $additional_code_footer);
188
189
		Events::throwEvent("page_edit_additional_code_footer", array(
190
			'page' => &$page,
191
			'code' => &$additional_code_footer
192
		));
193
194
		$template->assign("additional_code_footer", $additional_code_footer);
195
196
		$template->assign("errors", $error_messages);
197
		$template->assign("success_messages", $success_messages);
198
199
		return $template->getCode();
200
	}
201
202
	protected function save (Page &$page) {
203
		//first check permissions
204
		if (!PermissionChecker::current()->hasRight("can_edit_all_pages") && !(PermissionChecker::current()->hasRight("can_edit_own_pages") && $page->getAuthorID() == User::current()->getID())) {
205
			//user doesn't have permissions to edit this page
206
			return "You don't have permissions to edit this page!";
207
		}
208
209
		if (!isset($_POST['title']) || empty($_POST['title'])) {
210
			return "No title was set";
211
		}
212
213
		//validate title
214
		$title = htmlentities($_POST['title']);
215
216
		if (!isset($_POST['html_code']) || empty($_POST['html_code'])) {
217
			return "No content was set or content is empty!";
218
		}
219
220
		$content = $_POST['html_code'];
221
222
		//TODO: save page attributes
223
		if (!isset($_REQUEST['parent']) || empty($_REQUEST['parent'])) {
224
			return "Parent page wasn't set!";
225
		}
226
227
		$parent = (int) $_REQUEST['parent'];
228
229
		if (!isset($_REQUEST['design']) || empty($_REQUEST['design'])) {
230
			return "Design wasn't set!";
231
		}
232
233
		$design = $_REQUEST['design'];
234
235
		//TODO: check, if style (design) exists
236
237
		$template = "none";
238
239
		if (isset($_REQUEST['has_custom_template']) && isset($_REQUEST['template']) && !empty($_REQUEST['template'])) {
240
			$template = $_REQUEST['template'];
241
		}
242
243
		$keywords = "";
244
245
		if (!isset($_REQUEST['meta_keywords']) || empty($_REQUEST['meta_keywords'])) {
246
			//return "Meta keywords wasn't set!";
247
		} else {
248
			$keywords = htmlentities($_REQUEST['meta_keywords']);
249
		}
250
251
		$robots = "";
252
253
		if (!isset($_REQUEST['meta_robots']) || empty($_REQUEST['meta_robots'])) {
254
			//return "Meta robots wasn't set!";
255
		} else {
256
			$robots = htmlentities($_REQUEST['meta_robots']);
257
		}
258
259
		$canoncials = "";
260
261
		if (isset($_REQUEST['has_canoncials']) && isset($_REQUEST['meta_canoncials']) && !empty($_REQUEST['meta_canoncials'])) {
262
			$canoncials = $_REQUEST['meta_canoncials'];
263
		}
264
265
		$sitemap = 0;
266
		$sitemap_changefreq = "WEEKLY";
267
		$sitemap_priority = 0.5;
268
269
		if (isset($_REQUEST['sitemap'])) {
270
			$sitemap = 1;
271
272
			if (!isset($_REQUEST['sitemap_changefreq']) || empty($_REQUEST['sitemap_changefreq'])) {
273
				return "Sitemap change frequency wasn't set!";
274
			}
275
276
			$sitemap_changefreq = $_REQUEST['sitemap_changefreq'];
277
278
			if (!in_array($sitemap_changefreq, $this->sitemap_change_frequencies)) {
279
				return "Invalide value for sitemap change frequency: " . $sitemap_changefreq;
280
			}
281
282
			if (!isset($_REQUEST['sitemap_priority']) || empty($_REQUEST['sitemap_priority'])) {
283
				return "Sitemap priority wasn't set!";
284
			}
285
286
			$sitemap_priority = (float) $_REQUEST['sitemap_priority'];
287
288
			if ($sitemap_priority < 0) {
289
				return "Minimum value of sitemap priority is 0.";
290
			}
291
292
			if ($sitemap_priority > 1) {
293
				return "Maximum value of sitemap priority is 1.";
294
			}
295
		}
296
297
		if (!isset($_REQUEST['og_type']) || empty($_REQUEST['og_type'])) {
298
			return "OpenGraph type wasn't set!";
299
		}
300
301
		$og_type = $_REQUEST['og_type'];
302
303
		//update page in database
304
		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 WHERE `id` = :pageID; ", array(
305
			'title' => $title,
306
			'content' => $content,
307
			'pageID' => $page->getPageID(),
308
			'parent' => $parent,
309
			'design' => $design,
310
			'template' => $template,
311
			'sitemap' => $sitemap,
312
			'sitemap_changefreq' => $sitemap_changefreq,
313
			'sitemap_priority' => $sitemap_priority,
314
			'keywords' => $keywords,
315
			'robots' => $robots,
316
			'canoncials' => $canoncials,
317
			'og_type' => $og_type
318
		));
319
320
		//clear cache
321
		$page->clearCache();
322
323
		//reload page from database
324
		$page->loadByID($page->getPageID(), false);
325
326
		//TODO: remove this line later
327
		Cache::clear("pages");
328
329
		return true;
330
	}
331
332
	protected function publish (Page &$page) {
333
		//check permissions for publishing
334
		if (PermissionChecker::current()->hasRight("can_publish_all_pages") || (PermissionChecker::current()->hasRight("can_publish_own_pages") && $page->getAuthorID() == User::current()->getID())) {
335
			//update page in database
336
			Database::getInstance()->execute("UPDATE `{praefix}pages` SET `published` = '1' WHERE `id` = :pageID; ", array(
337
				'pageID' => $page->getPageID()
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
		} else {
351
			return "You don't have the permissions to publish this page!";
352
		}
353
	}
354
355
	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

355
	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...
356
		//show error
357
		$template = new DwooTemplate("pages/error");
358
		$template->assign("message", "No pageID was set!");
359
		return $template->getCode();
360
	}
361
362
	public function getFooterScripts(): string {
363
		$style_name = Registry::singleton()->getSetting("current_style_name");
364
		$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...
365
366
		$thirdparty_url = Registry::singleton()->getSetting("thirdparty_url");
367
368
		/*return "<!-- CK Editor -->
369
			<script src=\"" . $style_path . "bower_components/ckeditor/ckeditor.js\"></script>
370
			
371
			<script>
372
				$(function () {
373
					// Replace the <textarea id=\"editor1\"> with a CKEditor
374
					// instance, using default configuration.
375
					CKEDITOR.replace('wysiwygEditor', {
376
						height: '500px',
377
						enterMode: CKEDITOR.ENTER_BR
378
					});
379
				});
380
			</script>";*/
381
382
		return "<script src=\"" . $thirdparty_url . "tinymce_4.8.2/js/tinymce/tinymce.min.js\"></script>
383
  				<script>tinymce.init({
384
					  selector: 'textarea',
385
					  height: 500,
386
					  theme: 'modern',
387
					  removed_menuitems: 'newdocument',
388
					  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',
389
					  toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify  | numlist bullist outdent indent  | removeformat',
390
					  image_advtab: true
391
				});
392
				
393
				document.getElementById('customTplCheckbox').onchange = function() {
394
					document.getElementById('inputTpl').disabled = !this.checked;
395
					
396
					if (!this.checked) {
397
						document.getElementById('inputTpl').value = 'none';
398
					}
399
				};
400
				
401
				document.getElementById('customCanoncialsCheckbox').onchange = function() {
402
					document.getElementById('inputCanoncials').disabled = !this.checked;
403
					
404
					if (!this.checked) {
405
						document.getElementById('inputCanoncials').value = '';
406
					}
407
				};
408
				
409
				document.getElementById('inputSitemap').onchange = function() {
410
					document.getElementById('inputSitemapChangeFrequency').disabled = !this.checked;
411
					document.getElementById('inputSitemapPriority').disabled = !this.checked;
412
				};
413
				</script>";
414
	}
415
416
	public function listRequiredPermissions(): array {
417
		return array("can_edit_all_pages", "can_edit_own_pages");
418
	}
419
420
}
421
422
?>
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...
423