Completed
Pull Request — master (#1534)
by Damian
03:19
created

ModelAsController::beforeHandleRequest()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 13
Ratio 100 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 13
loc 13
rs 9.2
cc 4
eloc 8
nc 2
nop 2
1
<?php
2
3
use SilverStripe\ORM\DataModel;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DataModel.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
4
use SilverStripe\ORM\DB;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DB.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use SilverStripe\ORM\DataObject;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DataObject.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
7
/**
8
 * ModelAsController deals with mapping the initial request to the first {@link SiteTree}/{@link ContentController}
9
 * pair, which are then used to handle the request.
10
 *
11
 * @package cms
12
 * @subpackage control
13
 */
14
class ModelAsController extends Controller implements NestedController {
15
	private static $extensions = array('OldPageRedirector');
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
16
17
	/**
18
	 * Get the appropriate {@link ContentController} for handling a {@link SiteTree} object, link it to the object and
19
	 * return it.
20
	 *
21
	 * @param SiteTree $sitetree
22
	 * @param string $action
23
	 * @return ContentController
24
	 */
25
	public static function controller_for(SiteTree $sitetree, $action = null) {
26
		if ($sitetree->class == 'SiteTree') {
27
			$controller = "ContentController";
28
		} else {
29
			$ancestry = ClassInfo::ancestry($sitetree->class);
30
			while ($class = array_pop($ancestry)) {
31
				if (class_exists($class . "_Controller")) break;
32
			}
33
			$controller = ($class !== null) ? "{$class}_Controller" : "ContentController";
34
		}
35
36
		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...
37
			$controller = $controller . '_' . ucfirst($action);
38
		}
39
40
		return class_exists($controller) ? Injector::inst()->create($controller, $sitetree) : $sitetree;
41
	}
42
43
	public function init() {
44
		singleton('SiteTree')->extend('modelascontrollerInit', $this);
45
		parent::init();
46
	}
47
48 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...
49
		parent::beforeHandleRequest($request, $model);
50
		// If the database has not yet been created, redirect to the build page.
51
		if(!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
52
			$this->getResponse()->redirect(Controller::join_links(
53
				Director::absoluteBaseURL(),
54
				'dev/build',
55
				'?' . http_build_query(array(
56
					'returnURL' => isset($_GET['url']) ? $_GET['url'] : null,
57
				))
58
			));
59
		}
60
	}
61
62
	/**
63
	 * @uses ModelAsController::getNestedController()
64
	 * @param SS_HTTPRequest $request
65
	 * @param DataModel $model
66
	 * @return SS_HTTPResponse
67
	 */
68
	public function handleRequest(SS_HTTPRequest $request, DataModel $model) {
69
		$this->beforeHandleRequest($request, $model);
70
71
		// If we had a redirection or something, halt processing.
72
		if($this->getResponse()->isFinished()) {
73
			$this->popCurrent();
74
			return $this->getResponse();
75
		}
76
77
		// If the database has not yet been created, redirect to the build page.
78 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...
79
			$this->getResponse()->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null));
80
			$this->popCurrent();
81
82
			return $this->getResponse();
83
		}
84
85
		try {
86
			$result = $this->getNestedController();
87
88
			if($result instanceof RequestHandler) {
89
				$result = $result->handleRequest($this->getRequest(), $model);
90
			} else if(!($result instanceof SS_HTTPResponse)) {
91
				user_error("ModelAsController::getNestedController() returned bad object type '" .
92
					get_class($result)."'", E_USER_WARNING);
93
			}
94
		} catch(SS_HTTPResponse_Exception $responseException) {
95
			$result = $responseException->getResponse();
96
		}
97
98
		$this->popCurrent();
99
		return $result;
100
	}
101
102
	/**
103
	 * @return ContentController
104
	 * @throws Exception If URLSegment not passed in as a request parameter.
105
	 */
106
	public function getNestedController() {
107
		$request = $this->getRequest();
108
109
		if(!$URLSegment = $request->param('URLSegment')) {
110
			throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.');
111
		}
112
113
		// Find page by link, regardless of current locale settings
114
		if(class_exists('Translatable')) Translatable::disable_locale_filter();
115
116
		// Select child page
117
		$conditions = array('"SiteTree"."URLSegment"' => rawurlencode($URLSegment));
118
		if(SiteTree::config()->nested_urls) {
119
			$conditions[] = array('"SiteTree"."ParentID"' => 0);
120
		}
121
		$sitetree = DataObject::get_one('SiteTree', $conditions);
122
123
		// Check translation module
124
		// @todo Refactor out module specific code
125
		if(class_exists('Translatable')) Translatable::enable_locale_filter();
126
127
		if(!$sitetree) {
128
			$this->httpError(404, 'The requested page could not be found.');
129
		}
130
131
		// Enforce current locale setting to the loaded SiteTree object
132
		if(class_exists('Translatable') && $sitetree->Locale) Translatable::set_current_locale($sitetree->Locale);
133
134
		if(isset($_REQUEST['debug'])) {
135
			Debug::message("Using record #$sitetree->ID of type $sitetree->class with link {$sitetree->Link()}");
136
		}
137
138
		return self::controller_for($sitetree, $this->getRequest()->param('Action'));
139
	}
140
141
	/**
142
	 * @deprecated 4.0 Use OldPageRedirector::find_old_page instead
143
	 *
144
	 * @param string $URLSegment A subset of the url. i.e in /home/contact/ home and contact are URLSegment.
145
	 * @param int $parent The ID of the parent of the page the URLSegment belongs to.
146
	 * @param bool $ignoreNestedURLs
147
	 * @return SiteTree
148
	 */
149
	static public function find_old_page($URLSegment, $parent = null, $ignoreNestedURLs = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $ignoreNestedURLs is not used and could be removed.

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

Loading history...
150
		Deprecation::notice('4.0', 'Use OldPageRedirector::find_old_page instead');
151
		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...
152
			$parent = SiteTree::get()->byId($parent);
153
		}
154
		$url = OldPageRedirector::find_old_page(array($URLSegment), $parent);
155
		return SiteTree::get_by_link($url);
156
	}
157
}
158