Completed
Push — master ( 91444b...ac9540 )
by Ingo
03:27
created

ModelAsController::handleRequest()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 34
Code Lines 20

Duplication

Lines 6
Ratio 17.65 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 6
loc 34
rs 5.3846
c 2
b 0
f 0
cc 8
eloc 20
nc 8
nop 2
1
<?php
2
3
namespace SilverStripe\CMS\Controllers;
4
5
use SilverStripe\CMS\Model\SiteTree;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Control\NestedController;
9
use SilverStripe\Control\RequestHandler;
10
use SilverStripe\Control\SS_HTTPRequest;
11
use SilverStripe\Control\SS_HTTPResponse;
12
use SilverStripe\Control\SS_HTTPResponse_Exception;
13
use SilverStripe\Core\ClassInfo;
14
use SilverStripe\Core\Injector\Injector;
15
use SilverStripe\Dev\Debug;
16
use SilverStripe\Dev\Deprecation;
17
use SilverStripe\ORM\DataModel;
18
use SilverStripe\ORM\DataObject;
19
use SilverStripe\ORM\DB;
20
use Exception;
21
use Translatable;
22
23
/**
24
 * ModelAsController deals with mapping the initial request to the first {@link SiteTree}/{@link ContentController}
25
 * pair, which are then used to handle the request.
26
 */
27
class ModelAsController extends Controller implements NestedController {
28
29
	private static $extensions = array('SilverStripe\\CMS\\Controllers\\OldPageRedirector');
30
31
	/**
32
	 * Get the appropriate {@link ContentController} for handling a {@link SiteTree} object, link it to the object and
33
	 * return it.
34
	 *
35
	 * @param SiteTree $sitetree
36
	 * @param string $action
37
	 * @return ContentController
38
	 */
39
	public static function controller_for(SiteTree $sitetree, $action = null) {
40
		if ($sitetree->class == 'SilverStripe\\CMS\\Model\\SiteTree') {
41
			$controller = "SilverStripe\\CMS\\Controllers\\ContentController";
42
		} else {
43
			$ancestry = ClassInfo::ancestry($sitetree->class);
44
			while ($class = array_pop($ancestry)) {
45
				if (class_exists($class . "_Controller")) {
46
					break;
47
				}
48
			}
49
			$controller = ($class !== null)
50
				? "{$class}_Controller"
51
				: "SilverStripe\\CMS\\Controllers\\ContentController";
52
		}
53
54
		if($action && class_exists($controller . '_' . ucfirst($action))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $action of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
55
			$controller = $controller . '_' . ucfirst($action);
56
		}
57
58
		return class_exists($controller) ? Injector::inst()->create($controller, $sitetree) : $sitetree;
59
	}
60
61
	public function init() {
62
		singleton('SilverStripe\\CMS\\Model\\SiteTree')->extend('modelascontrollerInit', $this);
63
		parent::init();
64
	}
65
66 View Code Duplication
	protected function beforeHandleRequest(SS_HTTPRequest $request, DataModel $model) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
67
		parent::beforeHandleRequest($request, $model);
68
		// If the database has not yet been created, redirect to the build page.
69
		/** @skipUpgrade */
70
		if(!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
71
			$this->getResponse()->redirect(Controller::join_links(
72
				Director::absoluteBaseURL(),
73
				'dev/build',
74
				'?' . http_build_query(array(
75
					'returnURL' => isset($_GET['url']) ? $_GET['url'] : null,
76
				))
77
			));
78
		}
79
	}
80
81
	/**
82
	 * @uses ModelAsController::getNestedController()
83
	 * @param SS_HTTPRequest $request
84
	 * @param DataModel $model
85
	 * @return SS_HTTPResponse
86
	 */
87
	public function handleRequest(SS_HTTPRequest $request, DataModel $model) {
88
		$this->beforeHandleRequest($request, $model);
89
90
		// If we had a redirection or something, halt processing.
91
		if($this->getResponse()->isFinished()) {
92
			$this->popCurrent();
93
			return $this->getResponse();
94
		}
95
96
		// If the database has not yet been created, redirect to the build page.
97
		/** @skipUpgrade */
98 View Code Duplication
		if(!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
99
			$this->getResponse()->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null));
100
			$this->popCurrent();
101
102
			return $this->getResponse();
103
		}
104
105
		try {
106
			$result = $this->getNestedController();
107
108
			if($result instanceof RequestHandler) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\Control\RequestHandler does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
109
				$result = $result->handleRequest($this->getRequest(), $model);
110
			} else if(!($result instanceof SS_HTTPResponse)) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\Control\SS_HTTPResponse does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
111
				user_error("ModelAsController::getNestedController() returned bad object type '" .
112
					get_class($result)."'", E_USER_WARNING);
113
			}
114
		} catch(SS_HTTPResponse_Exception $responseException) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\Control\SS_HTTPResponse_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
115
			$result = $responseException->getResponse();
116
		}
117
118
		$this->popCurrent();
119
		return $result;
120
	}
121
122
	/**
123
	 * @return ContentController
124
	 * @throws Exception If URLSegment not passed in as a request parameter.
125
	 */
126
	public function getNestedController() {
127
		$request = $this->getRequest();
128
129
		if(!$URLSegment = $request->param('URLSegment')) {
130
			throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.');
131
		}
132
133
		// Find page by link, regardless of current locale settings
134
		if(class_exists('Translatable')) Translatable::disable_locale_filter();
135
136
		// Select child page
137
		$conditions = array('"SiteTree"."URLSegment"' => rawurlencode($URLSegment));
138
		if(SiteTree::config()->nested_urls) {
139
			$conditions[] = array('"SiteTree"."ParentID"' => 0);
140
		}
141
		/** @var SiteTree $sitetree */
142
		$sitetree = DataObject::get_one('SilverStripe\\CMS\\Model\\SiteTree', $conditions);
143
144
		// Check translation module
145
		// @todo Refactor out module specific code
146
		if(class_exists('Translatable')) Translatable::enable_locale_filter();
147
148
		if(!$sitetree) {
149
			$this->httpError(404, 'The requested page could not be found.');
150
		}
151
152
		// Enforce current locale setting to the loaded SiteTree object
153
		if(class_exists('Translatable') && $sitetree->Locale) Translatable::set_current_locale($sitetree->Locale);
154
155
		if(isset($_REQUEST['debug'])) {
156
			Debug::message("Using record #$sitetree->ID of type $sitetree->class with link {$sitetree->Link()}");
157
		}
158
159
		return self::controller_for($sitetree, $this->getRequest()->param('Action'));
160
	}
161
162
	/**
163
	 * @deprecated 4.0 Use OldPageRedirector::find_old_page instead
164
	 *
165
	 * @param string $URLSegment A subset of the url. i.e in /home/contact/ home and contact are URLSegment.
166
	 * @param int $parent The ID of the parent of the page the URLSegment belongs to.
167
	 * @param bool $ignoreNestedURLs
168
	 * @return SiteTree
169
	 */
170
	static public function find_old_page($URLSegment, $parent = null, $ignoreNestedURLs = false) {
171
		Deprecation::notice('4.0', 'Use OldPageRedirector::find_old_page instead');
172
		if ($parent) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
173
			$parent = SiteTree::get()->byID($parent);
174
		}
175
		$url = OldPageRedirector::find_old_page(array($URLSegment), $parent);
176
		return SiteTree::get_by_link($url);
177
	}
178
}
179