Completed
Push — master ( d3cb02...3e1e56 )
by Justin
04:39
created

PageEditPage::save()   D

Complexity

Conditions 32
Paths 65

Size

Total Lines 122
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 11
Bugs 0 Features 6
Metric Value
cc 32
eloc 62
c 11
b 0
f 6
nc 65
nop 1
dl 0
loc 122
rs 4.1666

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
		if (!isset($_REQUEST['meta_keywords']) || empty($_REQUEST['meta_keywords'])) {
244
			return "Meta keywords wasn't set!";
245
		}
246
247
		$keywords = htmlentities($_REQUEST['meta_keywords']);
248
249
		if (!isset($_REQUEST['meta_robots']) || empty($_REQUEST['meta_robots'])) {
250
			return "Meta robots wasn't set!";
251
		}
252
253
		$robots = htmlentities($_REQUEST['meta_robots']);
254
255
		$canoncials = "";
256
257
		if (isset($_REQUEST['has_canoncials']) && isset($_REQUEST['meta_canoncials']) && !empty($_REQUEST['meta_canoncials'])) {
258
			$canoncials = $_REQUEST['meta_canoncials'];
259
		}
260
261
		$sitemap = 0;
262
263
		if (isset($_REQUEST['sitemap'])) {
264
			$sitemap = 1;
265
		}
266
267
		if (!isset($_REQUEST['sitemap_changefreq']) || empty($_REQUEST['sitemap_changefreq'])) {
268
			return "Sitemap change frequency wasn't set!";
269
		}
270
271
		$sitemap_changefreq = $_REQUEST['sitemap_changefreq'];
272
273
		if (!in_array($sitemap_changefreq, $this->sitemap_change_frequencies)) {
274
			return "Invalide value for sitemap change frequency: " . $sitemap_changefreq;
275
		}
276
277
		if (!isset($_REQUEST['sitemap_priority']) || empty($_REQUEST['sitemap_priority'])) {
278
			return "Sitemap priority wasn't set!";
279
		}
280
281
		$sitemap_priority = (float) $_REQUEST['sitemap_priority'];
282
283
		if ($sitemap_priority < 0) {
284
			return "Minimum value of sitemap priority is 0.";
285
		}
286
287
		if ($sitemap_priority > 1) {
288
			return "Maximum value of sitemap priority is 1.";
289
		}
290
291
		if (!isset($_REQUEST['og_type']) || empty($_REQUEST['og_type'])) {
292
			return "OpenGraph type wasn't set!";
293
		}
294
295
		$og_type = $_REQUEST['og_type'];
296
297
		//update page in database
298
		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(
299
			'title' => $title,
300
			'content' => $content,
301
			'pageID' => $page->getPageID(),
302
			'parent' => $parent,
303
			'design' => $design,
304
			'template' => $template,
305
			'sitemap' => $sitemap,
306
			'sitemap_changefreq' => $sitemap_changefreq,
307
			'sitemap_priority' => $sitemap_priority,
308
			'keywords' => $keywords,
309
			'robots' => $robots,
310
			'canoncials' => $canoncials,
311
			'og_type' => $og_type
312
		));
313
314
		//clear cache
315
		$page->clearCache();
316
317
		//reload page from database
318
		$page->loadByID($page->getPageID(), false);
319
320
		//TODO: remove this line later
321
		Cache::clear("pages");
322
323
		return true;
324
	}
325
326
	protected function publish (Page &$page) {
327
		//check permissions for publishing
328
		if (PermissionChecker::current()->hasRight("can_publish_all_pages") || (PermissionChecker::current()->hasRight("can_publish_own_pages") && $page->getAuthorID() == User::current()->getID())) {
329
			//update page in database
330
			Database::getInstance()->execute("UPDATE `{praefix}pages` SET `published` = '1' WHERE `id` = :pageID; ", array(
331
				'pageID' => $page->getPageID()
332
			));
333
334
			//clear cache
335
			$page->clearCache();
336
337
			//reload page from database
338
			$page->loadByID($page->getPageID(), false);
339
340
			//TODO: remove this line later
341
			Cache::clear("pages");
342
343
			return true;
344
		} else {
345
			return "You don't have the permissions to publish this page!";
346
		}
347
	}
348
349
	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

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