Completed
Push — master ( 710595...d3cb02 )
by Justin
05:32
created

PageEditPage::save()   D

Complexity

Conditions 22
Paths 13

Size

Total Lines 82
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 0 Features 4
Metric Value
cc 22
eloc 40
c 9
b 0
f 4
nc 13
nop 1
dl 0
loc 82
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
	public function getContent(): string {
31
		$template = new DwooTemplate("pages/editpage");
32
33
		//check, if pageID is set
34
		if (!isset($_REQUEST['edit']) || empty($_REQUEST['edit'])) {
35
			//show error
36
			return $this->showError("No pageID was set!");
37
		}
38
39
		$pageID = (int) $_REQUEST['edit'];
40
41
		$page = new Page();
42
		$page->loadByID($pageID);
43
44
		//first check permissions
45
		if (!PermissionChecker::current()->hasRight("can_edit_all_pages") && !(PermissionChecker::current()->hasRight("can_edit_own_pages") && $page->getAuthorID() == User::current()->getID())) {
46
			//user doesn't have permissions to edit this page
47
			return $this->showError("You don't have permissions to edit this page!");
48
		}
49
50
		//first, lock page
51
		Page::lockPage($page->getPageID(), User::current()->getID());
52
53
		$success_messages = array();
54
		$error_messages = array();
55
56
		//save page
57
		if (isset($_REQUEST['submit'])) {
58
			if ($_REQUEST['submit'] === "Save") {
59
				//save page
60
				$res = $this->save($page);
61
62
				if ($res === true) {
63
					$success_messages[] = "Saved page successfully!";
64
				} else {
65
					$error_messages[] = $res;
66
				}
67
			} else if ($_REQUEST['submit'] === "SaveUnlock") {
68
				//save page
69
				$res = $this->save($page);
70
71
				if ($res === true) {
72
					//unlock page
73
					Page::unlockPage($page->getPageID());
74
75
					//redirect to admin/pages
76
					header("Location: " . DomainUtils::generateURL("admin/pages"));
77
78
					ob_flush();
79
					ob_end_flush();
80
81
					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...
82
				} else {
83
					$error_messages[] = $res;
84
				}
85
			} else if ($_REQUEST['submit'] === "Publish") {
86
				//save page
87
				$res = $this->save($page);
88
89
				if ($res === true) {
90
					$success_messages[] = "Saved page successfully!";
91
				} else {
92
					$error_messages[] = $res;
93
				}
94
95
				//publish page
96
				$res = $this->publish($page);
97
98
				if ($res === true) {
99
					$success_messages[] = "Page published successfully!";
100
				} else {
101
					$error_messages[] = $res;
102
				}
103
			}
104
		}
105
106
		$template->assign("action_url", DomainUtils::generateURL($this->getPage()->getAlias(), array("edit" => $pageID)));
107
108
		$template->assign("page", array(
109
			'id' => $page->getPageID(),
110
			'alias' => "/" . $page->getAlias(),
111
			'title' => $page->getTitle(),
112
			'content' => $page->getContent(),
113
			'is_published' => $page->isPublished(),
114
			'can_publish' => (!$page->isPublished() && (PermissionChecker::current()->hasRight("can_publish_all_pages") || (PermissionChecker::current()->hasRight("can_publish_own_pages") && $page->getAuthorID() == User::current()->getID()))),
115
			'can_change_owner' => (PermissionChecker::current()->hasRight("can_change_page_owner") || $page->getAuthorID() == User::current()->getID()),
116
			'folder' => $page->getFolder(),
117
			'preview_url' => DomainUtils::generateURL($page->getAlias(), array("preview" => "true")),
118
			'current_style' => $page->getStyle(),
119
			'template' => $page->getCustomTemplate(),
120
			'has_custom_template' => $page->hasCustomTemplate(),
121
			'parent' => $page->getParentID(),
122
			'meta_description' => $page->getMetaDescription(),
123
			'meta_keywords' => $page->getMetaKeywords(),
124
			'meta_robots' => $page->getMetaRobotsOptions(),
125
			'meta_canonicals' => $page->getMetaCanonicals(),
126
			'has_canoncials' => !empty($page->getMetaCanonicals()),
127
			'sitemap' => $page->isSitemapEnabled(),
128
			'sitemap_changefreq' => $page->getSitemapChangeFreq(),
129
			'sitemap_priority' => $page->getSitemapPriority(),
130
			'og_type' => $page->getOgType()
131
		));
132
133
		//set available styles
134
		$template->assign("styles", StyleController::listAllStyles());
135
136
		//get all pages from database
137
		$pages = array();
138
		$rows = Database::getInstance()->listRows("SELECT `id`, `alias` FROM `{praefix}pages` WHERE `editable` = '1' AND `activated` = '1'; ");
139
140
		foreach ($rows as $row) {
141
			$pages[] = array(
142
				'id' => $row['id'],
143
				'alias' => $row['alias']
144
			);
145
		}
146
147
		$template->assign("parent_pages", $pages);
148
149
		//https://developers.google.com/search/reference/robots_meta_tag?hl=de
150
		$robots_options = array(
151
			"all",
152
			"noindex",
153
			"nofollow",
154
			"none",
155
			"noarchive",
156
			"nosnippet",
157
			"noodp",
158
			"notranslate",
159
			"noimageindex",
160
			"unavailable_after: "
161
		);
162
163
		$template->assign("robots_options", $robots_options);
164
165
		$sitemap_change_frequencies = array(
166
			"AlWAYS", "HOURLY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY", "NEVER"
167
		);
168
169
		$template->assign("sitemap_change_frequencies", $sitemap_change_frequencies);
170
171
		//OpenGraph types,https://developers.facebook.com/docs/reference/opengraph/
172
		$og_types = array("website", "article", "book", "profile");
173
174
		$template->assign("og_types", $og_types);
175
176
		//add support to show additional code from plugins
177
		$additional_code_header = "";
178
		$additional_code_footer = "";
179
180
		Events::throwEvent("page_edit_additional_code_header", array(
181
			'page' => &$page,
182
			'code' => &$additional_code_header
183
		));
184
185
		$template->assign("additional_code_header", $additional_code_footer);
186
187
		Events::throwEvent("page_edit_additional_code_footer", array(
188
			'page' => &$page,
189
			'code' => &$additional_code_footer
190
		));
191
192
		$template->assign("additional_code_footer", $additional_code_footer);
193
194
		$template->assign("errors", $error_messages);
195
		$template->assign("success_messages", $success_messages);
196
197
		return $template->getCode();
198
	}
199
200
	protected function save (Page &$page) {
201
		//first check permissions
202
		if (!PermissionChecker::current()->hasRight("can_edit_all_pages") && !(PermissionChecker::current()->hasRight("can_edit_own_pages") && $page->getAuthorID() == User::current()->getID())) {
203
			//user doesn't have permissions to edit this page
204
			return "You don't have permissions to edit this page!";
205
		}
206
207
		if (!isset($_POST['title']) || empty($_POST['title'])) {
208
			return "No title was set";
209
		}
210
211
		//validate title
212
		$title = htmlentities($_POST['title']);
213
214
		if (!isset($_POST['html_code']) || empty($_POST['html_code'])) {
215
			return "No content was set or content is empty!";
216
		}
217
218
		$content = $_POST['html_code'];
219
220
		//TODO: save page attributes
221
		if (!isset($_REQUEST['parent']) || empty($_REQUEST['parent'])) {
222
			return "Parent page wasn't set!";
223
		}
224
225
		$parent = (int) $_REQUEST['parent'];
226
227
		if (!isset($_REQUEST['design']) || empty($_REQUEST['design'])) {
228
			return "Design wasn't set!";
229
		}
230
231
		$design = $_REQUEST['design'];
232
233
		//TODO: check, if style (design) exists
234
235
		$template = "none";
236
237
		if (isset($_REQUEST['has_custom_template']) && isset($_REQUEST['template']) && !empty($_REQUEST['template'])) {
238
			$template = $_REQUEST['template'];
239
		}
240
241
		if (!isset($_REQUEST['meta_keywords']) || empty($_REQUEST['meta_keywords'])) {
242
			return "Meta keywords wasn't set!";
243
		}
244
245
		$keywords = htmlentities($_REQUEST['meta_keywords']);
246
247
		if (!isset($_REQUEST['meta_robots']) || empty($_REQUEST['meta_robots'])) {
248
			return "Meta robots wasn't set!";
249
		}
250
251
		$robots = htmlentities($_REQUEST['meta_robots']);
252
253
		$canoncials = "";
254
255
		if (isset($_REQUEST['has_canoncials']) && isset($_REQUEST['meta_canoncials']) && !empty($_REQUEST['meta_canoncials'])) {
256
			$canoncials = $_REQUEST['meta_canoncials'];
257
		}
258
259
		//update page in database
260
		Database::getInstance()->execute("UPDATE `{praefix}pages` SET `title` = :title, `content` = :content, `parent` = :parent, `design` = :design, `template` = :template, `meta_keywords` = :keywords, `meta_robots` = :robots, `meta_canonicals` = :canoncials WHERE `id` = :pageID; ", array(
261
			'title' => $title,
262
			'content' => $content,
263
			'pageID' => $page->getPageID(),
264
			'parent' => $parent,
265
			'design' => $design,
266
			'template' => $template,
267
			'keywords' => $keywords,
268
			'robots' => $robots,
269
			'canoncials' => $canoncials
270
		));
271
272
		//clear cache
273
		$page->clearCache();
274
275
		//reload page from database
276
		$page->loadByID($page->getPageID(), false);
277
278
		//TODO: remove this line later
279
		Cache::clear("pages");
280
281
		return true;
282
	}
283
284
	protected function publish (Page &$page) {
285
		//check permissions for publishing
286
		if (PermissionChecker::current()->hasRight("can_publish_all_pages") || (PermissionChecker::current()->hasRight("can_publish_own_pages") && $page->getAuthorID() == User::current()->getID())) {
287
			//update page in database
288
			Database::getInstance()->execute("UPDATE `{praefix}pages` SET `published` = '1' WHERE `id` = :pageID; ", array(
289
				'pageID' => $page->getPageID()
290
			));
291
292
			//clear cache
293
			$page->clearCache();
294
295
			//reload page from database
296
			$page->loadByID($page->getPageID(), false);
297
298
			//TODO: remove this line later
299
			Cache::clear("pages");
300
301
			return true;
302
		} else {
303
			return "You don't have the permissions to publish this page!";
304
		}
305
	}
306
307
	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

307
	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...
308
		//show error
309
		$template = new DwooTemplate("pages/error");
310
		$template->assign("message", "No pageID was set!");
311
		return $template->getCode();
312
	}
313
314
	public function getFooterScripts(): string {
315
		$style_name = Registry::singleton()->getSetting("current_style_name");
316
		$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...
317
318
		$thirdparty_url = Registry::singleton()->getSetting("thirdparty_url");
319
320
		/*return "<!-- CK Editor -->
321
			<script src=\"" . $style_path . "bower_components/ckeditor/ckeditor.js\"></script>
322
			
323
			<script>
324
				$(function () {
325
					// Replace the <textarea id=\"editor1\"> with a CKEditor
326
					// instance, using default configuration.
327
					CKEDITOR.replace('wysiwygEditor', {
328
						height: '500px',
329
						enterMode: CKEDITOR.ENTER_BR
330
					});
331
				});
332
			</script>";*/
333
334
		return "<script src=\"" . $thirdparty_url . "tinymce_4.8.2/js/tinymce/tinymce.min.js\"></script>
335
  				<script>tinymce.init({
336
					  selector: 'textarea',
337
					  height: 500,
338
					  theme: 'modern',
339
					  removed_menuitems: 'newdocument',
340
					  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',
341
					  toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify  | numlist bullist outdent indent  | removeformat',
342
					  image_advtab: true
343
				});
344
				
345
				document.getElementById('customTplCheckbox').onchange = function() {
346
					document.getElementById('inputTpl').disabled = !this.checked;
347
					
348
					if (!this.checked) {
349
						document.getElementById('inputTpl').value = 'none';
350
					}
351
				};
352
				
353
				document.getElementById('customCanoncialsCheckbox').onchange = function() {
354
					document.getElementById('inputCanoncials').disabled = !this.checked;
355
					
356
					if (!this.checked) {
357
						document.getElementById('inputCanoncials').value = '';
358
					}
359
				};
360
				
361
				document.getElementById('inputSitemap').onchange = function() {
362
					document.getElementById('inputSitemapChangeFrequency').disabled = !this.checked;
363
					document.getElementById('inputSitemapPriority').disabled = !this.checked;
364
				};
365
				</script>";
366
	}
367
368
	public function listRequiredPermissions(): array {
369
		return array("can_edit_all_pages", "can_edit_own_pages");
370
	}
371
372
}
373
374
?>
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...
375