mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
MINOR Moved ContentController, ModelAsController, NestedController, RootURLController (and related tests) to "cms" module
This commit is contained in:
parent
f6c5308d3e
commit
5bf5b744d8
@ -23,7 +23,6 @@ Director::addRules(10, array(
|
||||
//'Security/$Action/$ID' => 'Security',
|
||||
'db//$Action' => 'DatabaseAdmin',
|
||||
'$Controller//$Action/$ID/$OtherID' => '*',
|
||||
'' => 'RootURLController',
|
||||
'api/v1/live' => 'VersionedRestfulServer',
|
||||
'api/v1' => 'RestfulServer',
|
||||
'soap/v1' => 'SOAPModelAccess',
|
||||
|
@ -1,527 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The most common kind of controller; effectively a controller linked to a {@link DataObject}.
|
||||
*
|
||||
* ContentControllers are most useful in the content-focused areas of a site. This is generally
|
||||
* the bulk of a site; however, they may be less appropriate in, for example, the user management
|
||||
* section of an application.
|
||||
*
|
||||
* On its own, content controller does very little. Its constructor is passed a {@link DataObject}
|
||||
* which is stored in $this->dataRecord. Any unrecognised method calls, for example, Title()
|
||||
* and Content(), will be passed along to the data record,
|
||||
*
|
||||
* Subclasses of ContentController are generally instantiated by ModelAsController; this will create
|
||||
* a controller based on the URLSegment action variable, by looking in the SiteTree table.
|
||||
*
|
||||
* @todo Can this be used for anything other than SiteTree controllers?
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage control
|
||||
*/
|
||||
class ContentController extends Controller {
|
||||
|
||||
protected $dataRecord;
|
||||
|
||||
static $url_handlers = array(
|
||||
'widget/$ID!' => 'handleWidget'
|
||||
);
|
||||
|
||||
public static $allowed_actions = array(
|
||||
'successfullyinstalled',
|
||||
'deleteinstallfiles' // secured through custom code
|
||||
);
|
||||
|
||||
/**
|
||||
* The ContentController will take the URLSegment parameter from the URL and use that to look
|
||||
* up a SiteTree record.
|
||||
*/
|
||||
public function __construct($dataRecord = null) {
|
||||
if(!$dataRecord) {
|
||||
$dataRecord = new Page();
|
||||
if($this->hasMethod("Title")) $dataRecord->Title = $this->Title();
|
||||
$dataRecord->URLSegment = get_class($this);
|
||||
$dataRecord->ID = -1;
|
||||
}
|
||||
|
||||
$this->dataRecord = $dataRecord;
|
||||
$this->failover = $this->dataRecord;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the link to this controller, but force the expanded link to be returned so that form methods and
|
||||
* similar will function properly.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Link($action = null) {
|
||||
return $this->data()->Link(($action ? $action : true));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------//
|
||||
// These flexible data methods remove the need for custom code to do simple stuff
|
||||
|
||||
/**
|
||||
* Return the children of a given page. The parent reference can either be a page link or an ID.
|
||||
*
|
||||
* @param string|int $parentRef
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
public function ChildrenOf($parentRef) {
|
||||
$parent = SiteTree::get_by_link($parentRef);
|
||||
|
||||
if(!$parent && is_numeric($parentRef)) {
|
||||
$parent = DataObject::get_by_id('SiteTree', Convert::raw2sql($parentRef));
|
||||
}
|
||||
|
||||
if($parent) return $parent->Children();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
public function Page($link) {
|
||||
return SiteTree::get_by_link($link);
|
||||
}
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
|
||||
// If we've accessed the homepage as /home/, then we should redirect to /.
|
||||
if($this->dataRecord && $this->dataRecord instanceof SiteTree
|
||||
&& RootURLController::should_be_on_root($this->dataRecord) && (!isset($this->urlParams['Action']) || !$this->urlParams['Action'] )
|
||||
&& !$_POST && !$_FILES && !Director::redirected_to() ) {
|
||||
$getVars = $_GET;
|
||||
unset($getVars['url']);
|
||||
if($getVars) $url = "?" . http_build_query($getVars);
|
||||
else $url = "";
|
||||
Director::redirect($url, 301);
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->dataRecord) $this->dataRecord->extend('contentcontrollerInit', $this);
|
||||
else singleton('SiteTree')->extend('contentcontrollerInit', $this);
|
||||
|
||||
if(Director::redirected_to()) return;
|
||||
|
||||
// Check page permissions
|
||||
if($this->dataRecord && $this->URLSegment != 'Security' && !$this->dataRecord->canView()) {
|
||||
return Security::permissionFailure($this);
|
||||
}
|
||||
|
||||
// Draft/Archive security check - only CMS users should be able to look at stage/archived content
|
||||
if($this->URLSegment != 'Security' && !Session::get('unsecuredDraftSite') && (Versioned::current_archived_date() || (Versioned::current_stage() && Versioned::current_stage() != 'Live'))) {
|
||||
if(!$this->dataRecord->canViewStage(Versioned::current_stage())) {
|
||||
$link = $this->Link();
|
||||
$message = _t("ContentController.DRAFT_SITE_ACCESS_RESTRICTION", 'You must log in with your CMS password in order to view the draft or archived content. <a href="%s">Click here to go back to the published site.</a>');
|
||||
Session::clear('currentStage');
|
||||
Session::clear('archiveDate');
|
||||
|
||||
return Security::permissionFailure($this, sprintf($message, Controller::join_links($link, "?stage=Live")));
|
||||
}
|
||||
}
|
||||
|
||||
// Use theme from the site config
|
||||
if(($config = SiteConfig::current_site_config()) && $config->Theme) {
|
||||
SSViewer::set_theme($config->Theme);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to
|
||||
* fall over to a child controller in order to provide functionality for nested URLs.
|
||||
*
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function handleRequest(SS_HTTPRequest $request) {
|
||||
$child = null;
|
||||
$action = $request->param('Action');
|
||||
|
||||
// If nested URLs are enabled, and there is no action handler for the current request then attempt to pass
|
||||
// control to a child controller. This allows for the creation of chains of controllers which correspond to a
|
||||
// nested URL.
|
||||
if($action && SiteTree::nested_urls() && !$this->hasAction($action)) {
|
||||
// See ModelAdController->getNestedController() for similar logic
|
||||
Translatable::disable_locale_filter();
|
||||
// look for a page with this URLSegment
|
||||
$child = DataObject::get_one('SiteTree', sprintf (
|
||||
"\"ParentID\" = %s AND \"URLSegment\" = '%s'", $this->ID, Convert::raw2sql($action)
|
||||
));
|
||||
Translatable::enable_locale_filter();
|
||||
|
||||
// if we can't find a page with this URLSegment try to find one that used to have
|
||||
// that URLSegment but changed. See ModelAsController->getNestedController() for similiar logic.
|
||||
if(!$child){
|
||||
$child = ModelAsController::find_old_page($action,$this->ID);
|
||||
if($child){
|
||||
$response = new SS_HTTPResponse();
|
||||
$params = $request->getVars();
|
||||
if(isset($params['url'])) unset($params['url']);
|
||||
$response->redirect(
|
||||
Controller::join_links(
|
||||
$child->Link(
|
||||
Controller::join_links(
|
||||
$request->param('ID'), // 'ID' is the new 'URLSegment', everything shifts up one position
|
||||
$request->param('OtherID')
|
||||
)
|
||||
),
|
||||
// Needs to be in separate join links to avoid urlencoding
|
||||
($params) ? '?' . http_build_query($params) : null
|
||||
),
|
||||
301
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we found a page with this URLSegment.
|
||||
if($child) {
|
||||
$request->shiftAllParams();
|
||||
$request->shift();
|
||||
|
||||
$response = ModelAsController::controller_for($child)->handleRequest($request);
|
||||
} else {
|
||||
// If a specific locale is requested, and it doesn't match the page found by URLSegment,
|
||||
// look for a translation and redirect (see #5001). Only happens on the last child in
|
||||
// a potentially nested URL chain.
|
||||
if($request->getVar('locale') && $this->dataRecord && $this->dataRecord->Locale != $request->getVar('locale')) {
|
||||
$translation = $this->dataRecord->getTranslation($request->getVar('locale'));
|
||||
if($translation) {
|
||||
$response = new SS_HTTPResponse();
|
||||
$response->redirect($translation->Link(), 301);
|
||||
throw new SS_HTTPResponse_Exception($response);
|
||||
}
|
||||
}
|
||||
|
||||
Director::set_current_page($this->data());
|
||||
$response = parent::handleRequest($request);
|
||||
Director::set_current_page(null);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses ErrorPage::response_for()
|
||||
*/
|
||||
public function httpError($code, $message = null) {
|
||||
if($this->request->isMedia() || !$response = ErrorPage::response_for($code)) {
|
||||
parent::httpError($code, $message);
|
||||
} else {
|
||||
throw new SS_HTTPResponse_Exception($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles widgets attached to a page through one or more {@link WidgetArea} elements.
|
||||
* Iterated through each $has_one relation with a {@link WidgetArea}
|
||||
* and looks for connected widgets by their database identifier.
|
||||
* Assumes URLs in the following format: <URLSegment>/widget/<Widget-ID>.
|
||||
*
|
||||
* @return RequestHandler
|
||||
*/
|
||||
function handleWidget() {
|
||||
$SQL_id = $this->request->param('ID');
|
||||
if(!$SQL_id) return false;
|
||||
|
||||
// find WidgetArea relations
|
||||
$widgetAreaRelations = array();
|
||||
$hasOnes = $this->dataRecord->has_one();
|
||||
if(!$hasOnes) return false;
|
||||
foreach($hasOnes as $hasOneName => $hasOneClass) {
|
||||
if($hasOneClass == 'WidgetArea' || is_subclass_of($hasOneClass, 'WidgetArea')) {
|
||||
$widgetAreaRelations[] = $hasOneName;
|
||||
}
|
||||
}
|
||||
|
||||
// find widget
|
||||
$widget = null;
|
||||
foreach($widgetAreaRelations as $widgetAreaRelation) {
|
||||
if($widget) break;
|
||||
$widget = $this->dataRecord->$widgetAreaRelation()->Widgets(
|
||||
sprintf('"Widget"."ID" = %d', $SQL_id)
|
||||
)->First();
|
||||
}
|
||||
if(!$widget) user_error('No widget found', E_USER_ERROR);
|
||||
|
||||
// find controller
|
||||
$controllerClass = '';
|
||||
foreach(array_reverse(ClassInfo::ancestry($widget->class)) as $widgetClass) {
|
||||
$controllerClass = "{$widgetClass}_Controller";
|
||||
if(class_exists($controllerClass)) break;
|
||||
}
|
||||
if(!$controllerClass) user_error(
|
||||
sprintf('No controller available for %s', $widget->class),
|
||||
E_USER_ERROR
|
||||
);
|
||||
|
||||
return new $controllerClass($widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the project name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function project() {
|
||||
global $project;
|
||||
return $project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated database record
|
||||
*/
|
||||
public function data() {
|
||||
return $this->dataRecord;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Returns a fixed navigation menu of the given level.
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
public function getMenu($level = 1) {
|
||||
if($level == 1) {
|
||||
$result = DataObject::get("SiteTree", "\"ShowInMenus\" = 1 AND \"ParentID\" = 0");
|
||||
|
||||
} else {
|
||||
$parent = $this->data();
|
||||
$stack = array($parent);
|
||||
|
||||
if($parent) {
|
||||
while($parent = $parent->Parent) {
|
||||
array_unshift($stack, $parent);
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($stack[$level-2])) $result = $stack[$level-2]->Children();
|
||||
}
|
||||
|
||||
$visible = array();
|
||||
|
||||
// Remove all entries the can not be viewed by the current user
|
||||
// We might need to create a show in menu permission
|
||||
if(isset($result)) {
|
||||
foreach($result as $page) {
|
||||
if($page->canView()) {
|
||||
$visible[] = $page;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DataObjectSet($visible);
|
||||
}
|
||||
|
||||
public function Menu($level) {
|
||||
return $this->getMenu($level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default log-in form.
|
||||
*
|
||||
* @todo Check if here should be returned just the default log-in form or
|
||||
* all available log-in forms (also OpenID...)
|
||||
*/
|
||||
public function LoginForm() {
|
||||
return MemberAuthenticator::get_login_form($this);
|
||||
}
|
||||
|
||||
public function SilverStripeNavigator() {
|
||||
$member = Member::currentUser();
|
||||
$items = '';
|
||||
$message = '';
|
||||
|
||||
if(Director::isDev() || Permission::check('CMS_ACCESS_CMSMain') || Permission::check('VIEW_DRAFT_CONTENT')) {
|
||||
if($this->dataRecord) {
|
||||
Requirements::css(SAPPHIRE_DIR . '/css/SilverStripeNavigator.css');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery/jquery.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-livequery/jquery.livequery.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/SilverStripeNavigator.js');
|
||||
|
||||
$return = $nav = SilverStripeNavigator::get_for_record($this->dataRecord);
|
||||
$items = $return['items'];
|
||||
$message = $return['message'];
|
||||
}
|
||||
|
||||
if($member) {
|
||||
$firstname = Convert::raw2xml($member->FirstName);
|
||||
$surname = Convert::raw2xml($member->Surname);
|
||||
$logInMessage = _t('ContentController.LOGGEDINAS', 'Logged in as') ." {$firstname} {$surname} - <a href=\"Security/logout\">". _t('ContentController.LOGOUT', 'Log out'). "</a>";
|
||||
} else {
|
||||
$logInMessage = _t('ContentController.NOTLOGGEDIN', 'Not logged in') ." - <a href=\"Security/login\">". _t('ContentController.LOGIN', 'Login') ."</a>";
|
||||
}
|
||||
$viewPageIn = _t('ContentController.VIEWPAGEIN', 'View Page in:');
|
||||
|
||||
return <<<HTML
|
||||
<div id="SilverStripeNavigator">
|
||||
<div class="holder">
|
||||
<div id="logInStatus">
|
||||
$logInMessage
|
||||
</div>
|
||||
|
||||
<div id="switchView" class="bottomTabs">
|
||||
<div class="blank">$viewPageIn </div>
|
||||
$items
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
$message
|
||||
HTML;
|
||||
|
||||
// On live sites we should still see the archived message
|
||||
} else {
|
||||
if($date = Versioned::current_archived_date()) {
|
||||
Requirements::css(SAPPHIRE_DIR . '/css/SilverStripeNavigator.css');
|
||||
$dateObj = Object::create('Datetime', $date, null);
|
||||
// $dateObj->setVal($date);
|
||||
return "<div id=\"SilverStripeNavigatorMessage\">". _t('ContentController.ARCHIVEDSITEFROM') ."<br>" . $dateObj->Nice() . "</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SiteConfig() {
|
||||
if(method_exists($this->dataRecord, 'getSiteConfig')) {
|
||||
return $this->dataRecord->getSiteConfig();
|
||||
} else {
|
||||
return SiteConfig::current_site_config();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the xml:lang and lang attributes.
|
||||
*
|
||||
* @deprecated 2.5 Use ContentLocale() instead and write attribute names suitable to XHTML/HTML
|
||||
* templates directly in the template.
|
||||
*/
|
||||
function LangAttributes() {
|
||||
$locale = $this->ContentLocale();
|
||||
return "xml:lang=\"$locale\" lang=\"$locale\"";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an RFC1766 compliant locale string, e.g. 'fr-CA'.
|
||||
* Inspects the associated {@link dataRecord} for a {@link SiteTree->Locale} value if present,
|
||||
* and falls back to {@link Translatable::get_current_locale()} or {@link i18n::default_locale()},
|
||||
* depending if Translatable is enabled.
|
||||
*
|
||||
* Suitable for insertion into lang= and xml:lang=
|
||||
* attributes in HTML or XHTML output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function ContentLocale() {
|
||||
if($this->dataRecord && $this->dataRecord->hasExtension('Translatable')) {
|
||||
$locale = $this->dataRecord->Locale;
|
||||
} elseif(Object::has_extension('SiteTree', 'Translatable')) {
|
||||
$locale = Translatable::get_current_locale();
|
||||
} else {
|
||||
$locale = i18n::get_locale();
|
||||
}
|
||||
|
||||
return i18n::convert_rfc1766($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* This action is called by the installation system
|
||||
*/
|
||||
function successfullyinstalled() {
|
||||
// The manifest should be built by now, so it's safe to publish the 404 page
|
||||
$fourohfour = Versioned::get_one_by_stage('ErrorPage', 'Stage', '"ErrorCode" = 404');
|
||||
if($fourohfour) {
|
||||
$fourohfour->write();
|
||||
$fourohfour->publish("Stage", "Live");
|
||||
}
|
||||
|
||||
// TODO Allow this to work when allow_url_fopen=0
|
||||
if(isset($_SESSION['StatsID']) && $_SESSION['StatsID']) {
|
||||
$url = 'http://ss2stat.silverstripe.com/Installation/installed?ID=' . $_SESSION['StatsID'];
|
||||
@file_get_contents($url);
|
||||
}
|
||||
|
||||
$title = new Varchar("Title");
|
||||
$content = new HTMLText("Content");
|
||||
$username = Session::get('username');
|
||||
$password = Session::get('password');
|
||||
$title->setValue("Installation Successful");
|
||||
global $project;
|
||||
$tutorialOnly = ($project == 'tutorial') ? "<p>This website is a simplistic version of a SilverStripe 2 site. To extend this, please take a look at <a href=\"http://doc.silverstripe.org/doku.php?id=tutorials\">our new tutorials</a>.</p>" : '';
|
||||
$content->setValue(<<<HTML
|
||||
<p style="margin: 1em 0"><b>Congratulations, SilverStripe has been successfully installed.</b></p>
|
||||
|
||||
$tutorialOnly
|
||||
<p>You can start editing your site's content by opening <a href="admin/">the CMS</a>. <br />
|
||||
Email: $username<br />
|
||||
Password: $password<br />
|
||||
</p>
|
||||
<div style="background:#ddd; border:1px solid #ccc; padding:5px; margin:5px;"><img src="cms/images/dialogs/alert.gif" style="border: none; margin-right: 10px; float: left;" /><p style="color:red;">For security reasons you should now delete the install files, unless you are planning to reinstall later (<em>requires admin login, see above</em>). The web server also now only needs write access to the "assets" folder, you can remove write access from all other folders. <a href="home/deleteinstallfiles" style="text-align: center;">Click here to delete the install files.</a></p></div>
|
||||
HTML
|
||||
);
|
||||
|
||||
return array(
|
||||
"Title" => $title,
|
||||
"Content" => $content,
|
||||
);
|
||||
}
|
||||
|
||||
function deleteinstallfiles() {
|
||||
if(!Permission::check("ADMIN")) return Security::permissionFailure($this);
|
||||
|
||||
$title = new Varchar("Title");
|
||||
$content = new HTMLText("Content");
|
||||
$tempcontent = '';
|
||||
$username = Session::get('username');
|
||||
$password = Session::get('password');
|
||||
|
||||
// We can't delete index.php as it might be necessary for URL routing without mod_rewrite.
|
||||
// There's no safe way to detect usage of mod_rewrite across webservers,
|
||||
// so we have to assume the file is required.
|
||||
$installfiles = array(
|
||||
'install.php',
|
||||
'config-form.css',
|
||||
'config-form.html',
|
||||
'index.html'
|
||||
);
|
||||
|
||||
foreach($installfiles as $installfile) {
|
||||
if(file_exists(BASE_PATH . '/' . $installfile)) {
|
||||
@unlink(BASE_PATH . '/' . $installfile);
|
||||
}
|
||||
|
||||
if(file_exists(BASE_PATH . '/' . $installfile)) {
|
||||
$unsuccessful[] = $installfile;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($unsuccessful)) {
|
||||
$title->setValue("Unable to delete installation files");
|
||||
$tempcontent = "<p style=\"margin: 1em 0\">Unable to delete installation files. Please delete the files below manually:</p><ul>";
|
||||
foreach($unsuccessful as $unsuccessfulFile) {
|
||||
$tempcontent .= "<li>$unsuccessfulFile</li>";
|
||||
}
|
||||
$tempcontent .= "</ul>";
|
||||
} else {
|
||||
$title->setValue("Deleted installation files");
|
||||
$tempcontent = <<<HTML
|
||||
<p style="margin: 1em 0">Installation files have been successfully deleted.</p>
|
||||
HTML
|
||||
;
|
||||
}
|
||||
|
||||
$tempcontent .= <<<HTML
|
||||
<p style="margin: 1em 0">You can start editing your site's content by opening <a href="admin/">the CMS</a>. <br />
|
||||
Email: $username<br />
|
||||
Password: $password<br />
|
||||
</p>
|
||||
HTML
|
||||
;
|
||||
$content->setValue($tempcontent);
|
||||
|
||||
return array(
|
||||
"Title" => $title,
|
||||
"Content" => $content,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* ModelAsController deals with mapping the initial request to the first {@link SiteTree}/{@link ContentController}
|
||||
* pair, which are then used to handle the request.
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage control
|
||||
*/
|
||||
class ModelAsController extends Controller implements NestedController {
|
||||
|
||||
/**
|
||||
* Get the appropriate {@link ContentController} for handling a {@link SiteTree} object, link it to the object and
|
||||
* return it.
|
||||
*
|
||||
* @param SiteTree $sitetree
|
||||
* @param string $action
|
||||
* @return ContentController
|
||||
*/
|
||||
public static function controller_for(SiteTree $sitetree, $action = null) {
|
||||
if($sitetree->class == 'SiteTree') $controller = "ContentController";
|
||||
else $controller = "{$sitetree->class}_Controller";
|
||||
|
||||
if($action && class_exists($controller . '_' . ucfirst($action))) {
|
||||
$controller = $controller . '_' . ucfirst($action);
|
||||
}
|
||||
|
||||
return class_exists($controller) ? new $controller($sitetree) : $sitetree;
|
||||
}
|
||||
|
||||
public function init() {
|
||||
singleton('SiteTree')->extend('modelascontrollerInit', $this);
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses ModelAsController::getNestedController()
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function handleRequest(SS_HTTPRequest $request) {
|
||||
$this->request = $request;
|
||||
|
||||
$this->pushCurrent();
|
||||
|
||||
// Create a response just in case init() decides to redirect
|
||||
$this->response = new SS_HTTPResponse();
|
||||
|
||||
$this->init();
|
||||
|
||||
// If we had a redirection or something, halt processing.
|
||||
if($this->response->isFinished()) {
|
||||
$this->popCurrent();
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
// If the database has not yet been created, redirect to the build page.
|
||||
if(!DB::isActive() || !ClassInfo::hasTable('SiteTree')) {
|
||||
$this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null));
|
||||
$this->popCurrent();
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->getNestedController();
|
||||
|
||||
if($result instanceof RequestHandler) {
|
||||
$result = $result->handleRequest($this->request);
|
||||
} else if(!($result instanceof SS_HTTPResponse)) {
|
||||
user_error("ModelAsController::getNestedController() returned bad object type '" .
|
||||
get_class($result)."'", E_USER_WARNING);
|
||||
}
|
||||
} catch(SS_HTTPResponse_Exception $responseException) {
|
||||
$result = $responseException->getResponse();
|
||||
}
|
||||
|
||||
$this->popCurrent();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContentController
|
||||
*/
|
||||
public function getNestedController() {
|
||||
$request = $this->request;
|
||||
|
||||
if(!$URLSegment = $request->param('URLSegment')) {
|
||||
throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.');
|
||||
}
|
||||
|
||||
// Find page by link, regardless of current locale settings
|
||||
Translatable::disable_locale_filter();
|
||||
$sitetree = DataObject::get_one(
|
||||
'SiteTree',
|
||||
sprintf(
|
||||
'"URLSegment" = \'%s\' %s',
|
||||
Convert::raw2sql($URLSegment),
|
||||
(SiteTree::nested_urls() ? 'AND "ParentID" = 0' : null)
|
||||
)
|
||||
);
|
||||
Translatable::enable_locale_filter();
|
||||
|
||||
if(!$sitetree) {
|
||||
// If a root page has been renamed, redirect to the new location.
|
||||
// See ContentController->handleRequest() for similiar logic.
|
||||
$redirect = self::find_old_page($URLSegment);
|
||||
if($redirect = self::find_old_page($URLSegment)) {
|
||||
$params = $request->getVars();
|
||||
if(isset($params['url'])) unset($params['url']);
|
||||
$this->response = new SS_HTTPResponse();
|
||||
$this->response->redirect(
|
||||
Controller::join_links(
|
||||
$redirect->Link(
|
||||
Controller::join_links(
|
||||
$request->param('Action'),
|
||||
$request->param('ID'),
|
||||
$request->param('OtherID')
|
||||
)
|
||||
),
|
||||
// Needs to be in separate join links to avoid urlencoding
|
||||
($params) ? '?' . http_build_query($params) : null
|
||||
),
|
||||
301
|
||||
);
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
if($response = ErrorPage::response_for(404)) {
|
||||
return $response;
|
||||
} else {
|
||||
$this->httpError(404, 'The requested page could not be found.');
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce current locale setting to the loaded SiteTree object
|
||||
if($sitetree->Locale) Translatable::set_current_locale($sitetree->Locale);
|
||||
|
||||
if(isset($_REQUEST['debug'])) {
|
||||
Debug::message("Using record #$sitetree->ID of type $sitetree->class with link {$sitetree->Link()}");
|
||||
}
|
||||
|
||||
return self::controller_for($sitetree, $this->request->param('Action'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $URLSegment A subset of the url. i.e in /home/contact/ home and contact are URLSegment.
|
||||
* @param int $parentID The ID of the parent of the page the URLSegment belongs to.
|
||||
* @return SiteTree
|
||||
*/
|
||||
static function find_old_page($URLSegment,$parentID = 0, $ignoreNestedURLs = false) {
|
||||
$URLSegment = Convert::raw2sql($URLSegment);
|
||||
|
||||
$useParentIDFilter = SiteTree::nested_urls() && $parentID;
|
||||
|
||||
// First look for a non-nested page that has a unique URLSegment and can be redirected to.
|
||||
if(SiteTree::nested_urls()) {
|
||||
$pages = DataObject::get(
|
||||
'SiteTree',
|
||||
"\"URLSegment\" = '$URLSegment'" . ($useParentIDFilter ? ' AND "ParentID" = ' . (int)$parentID : '')
|
||||
);
|
||||
if($pages && $pages->Count() == 1) return $pages->First();
|
||||
}
|
||||
|
||||
// Get an old version of a page that has been renamed.
|
||||
$query = new SQLQuery (
|
||||
'"RecordID"',
|
||||
'"SiteTree_versions"',
|
||||
"\"URLSegment\" = '$URLSegment' AND \"WasPublished\" = 1" . ($useParentIDFilter ? ' AND "ParentID" = ' . (int)$parentID : ''),
|
||||
'"LastEdited" DESC',
|
||||
null,
|
||||
null,
|
||||
1
|
||||
);
|
||||
$record = $query->execute()->first();
|
||||
|
||||
if($record && ($oldPage = DataObject::get_by_id('SiteTree', $record['RecordID']))) {
|
||||
// Run the page through an extra filter to ensure that all decorators are applied.
|
||||
if(SiteTree::get_by_link($oldPage->RelativeLink())) return $oldPage;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Interface that is implemented by controllers that are designed to hand control over to another controller.
|
||||
* ModelAsController, which selects up a SiteTree object and passes control over to a suitable subclass of ContentController, is a good
|
||||
* example of this.
|
||||
* @package sapphire
|
||||
* @subpackage control
|
||||
*/
|
||||
interface NestedController {
|
||||
public function getNestedController();
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,121 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage control
|
||||
*/
|
||||
class RootURLController extends Controller {
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $is_at_root = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $default_homepage_link = 'home';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $cached_homepage_link;
|
||||
|
||||
/**
|
||||
* Get the full form (e.g. /home/) relative link to the home page for the current HTTP_HOST value. Note that the
|
||||
* link is trimmed of leading and trailing slashes before returning to ensure consistency.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_homepage_link() {
|
||||
if(!self::$cached_homepage_link) {
|
||||
$host = str_replace('www.', null, $_SERVER['HTTP_HOST']);
|
||||
$SQL_host = Convert::raw2sql($host);
|
||||
|
||||
$query = new SQLQuery (array('"ID"', '"HomepageForDomain"'), '"SiteTree"', "(\"HomepageForDomain\" LIKE '%$SQL_host%')", "\"Sort\"", null, null);
|
||||
singleton("SiteTree")->getExtensionInstance('Versioned')->augmentSQL($query);
|
||||
$candidates = $query->execute()->map();
|
||||
|
||||
if($candidates) foreach($candidates as $id => $domainString) {
|
||||
if(preg_match('/(,|^) *' . preg_quote($host) . ' *(,|$)/', $domainString)) {
|
||||
self::$cached_homepage_link = trim(DataObject::get_by_id('SiteTree', $id)->RelativeLink(true), '/');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!self::$cached_homepage_link) {
|
||||
if (
|
||||
Object::has_extension('SiteTree', 'Translatable')
|
||||
&& $link = Translatable::get_homepage_link_by_locale(Translatable::get_current_locale())
|
||||
) {
|
||||
self::$cached_homepage_link = $link;
|
||||
} else {
|
||||
self::$cached_homepage_link = self::get_default_homepage_link();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$cached_homepage_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the link that denotes the homepage if there is not one explicitly defined for this HTTP_HOST value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_homepage_link() {
|
||||
return self::$default_homepage_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if a request to a certain page should be redirected to the site root (i.e. if the page acts as the
|
||||
* home page).
|
||||
*
|
||||
* @param SiteTree $page
|
||||
* @return bool
|
||||
*/
|
||||
public static function should_be_on_root(SiteTree $page) {
|
||||
if(!self::$is_at_root && self::get_homepage_link() == trim($page->RelativeLink(true), '/')) {
|
||||
return !(
|
||||
$page->hasExtension('Translatable') && $page->Locale && $page->Locale != Translatable::default_locale()
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the cached homepage link value - useful for testing.
|
||||
*/
|
||||
public static function reset() {
|
||||
self::$cached_homepage_link = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SS_HTTPRequest $request
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function handleRequest(SS_HTTPRequest $request) {
|
||||
self::$is_at_root = true;
|
||||
|
||||
$this->pushCurrent();
|
||||
$this->init();
|
||||
|
||||
if(!DB::isActive() || !ClassInfo::hasTable('SiteTree')) {
|
||||
$this->response = new SS_HTTPResponse();
|
||||
$this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null));
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
$request = new SS_HTTPRequest (
|
||||
$request->httpMethod(), self::get_homepage_link() . '/', $request->getVars(), $request->postVars()
|
||||
);
|
||||
$request->match('$URLSegment//$Action', true);
|
||||
|
||||
$controller = new ModelAsController();
|
||||
$result = $controller->handleRequest($request);
|
||||
|
||||
$this->popCurrent();
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
|
||||
<!-- very simple template that exists mainly so that edge cases like test execution don't fail -->
|
||||
<head>
|
||||
<% base_tag %>
|
||||
$MetaTags
|
||||
</head>
|
||||
<body>
|
||||
<h1>$Title</h1>
|
||||
$Content
|
||||
$Form
|
||||
|
||||
<p><i>Generated with the default ContentController.ss template</i></p>
|
||||
</body>
|
||||
</html>
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ContentControllerPermissionTest extends FunctionalTest {
|
||||
|
||||
protected $usesDatabase = true;
|
||||
|
||||
protected $autoFollowRedirection = false;
|
||||
|
||||
public function testCanViewStage() {
|
||||
$page = new Page();
|
||||
$page->URLSegment = 'testpage';
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
|
||||
$response = $this->get('/testpage');
|
||||
$this->assertEquals($response->getStatusCode(), 200);
|
||||
|
||||
$response = $this->get('/testpage/?stage=Live');
|
||||
$this->assertEquals($response->getStatusCode(), 200);
|
||||
|
||||
$response = $this->get('/testpage/?stage=Stage');
|
||||
// should redirect to login
|
||||
$this->assertEquals($response->getStatusCode(), 302);
|
||||
|
||||
$this->logInWithPermission('CMS_ACCESS_CMSMain');
|
||||
|
||||
$response = $this->get('/testpage/?stage=Stage');
|
||||
$this->assertEquals($response->getStatusCode(), 200);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ContentControllerTest extends FunctionalTest {
|
||||
|
||||
public static $fixture_file = 'sapphire/tests/control/ContentControllerTest.yml';
|
||||
|
||||
public static $use_draft_site = true;
|
||||
|
||||
/**
|
||||
* Test that nested pages, basic actions, and nested/non-nested URL switching works properly
|
||||
*/
|
||||
|
||||
public function testNestedPages() {
|
||||
RootURLController::reset();
|
||||
SiteTree::enable_nested_urls();
|
||||
|
||||
$this->assertEquals('Home Page', $this->get('/')->getBody());
|
||||
$this->assertEquals('Home Page', $this->get('/home/index/')->getBody());
|
||||
$this->assertEquals('Home Page', $this->get('/home/second-index/')->getBody());
|
||||
|
||||
$this->assertEquals('Second Level Page', $this->get('/home/second-level/')->getBody());
|
||||
$this->assertEquals('Second Level Page', $this->get('/home/second-level/index/')->getBody());
|
||||
$this->assertEquals('Second Level Page', $this->get('/home/second-level/second-index/')->getBody());
|
||||
|
||||
$this->assertEquals('Third Level Page', $this->get('/home/second-level/third-level/')->getBody());
|
||||
$this->assertEquals('Third Level Page', $this->get('/home/second-level/third-level/index/')->getBody());
|
||||
$this->assertEquals('Third Level Page', $this->get('/home/second-level/third-level/second-index/')->getBody());
|
||||
|
||||
RootURLController::reset();
|
||||
SiteTree::disable_nested_urls();
|
||||
|
||||
$this->assertEquals('Home Page', $this->get('/')->getBody());
|
||||
$this->assertEquals('Home Page', $this->get('/home/')->getBody());
|
||||
$this->assertEquals('Home Page', $this->get('/home/second-index/')->getBody());
|
||||
|
||||
$this->assertEquals('Second Level Page', $this->get('/second-level/')->getBody());
|
||||
$this->assertEquals('Second Level Page', $this->get('/second-level/index/')->getBody());
|
||||
$this->assertEquals('Second Level Page', $this->get('/second-level/second-index/')->getBody());
|
||||
|
||||
$this->assertEquals('Third Level Page', $this->get('/third-level/')->getBody());
|
||||
$this->assertEquals('Third Level Page', $this->get('/third-level/index/')->getBody());
|
||||
$this->assertEquals('Third Level Page', $this->get('/third-level/second-index/')->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link ContentController::ChildrenOf()}
|
||||
*/
|
||||
public function testChildrenOf() {
|
||||
$controller = new ContentController();
|
||||
|
||||
SiteTree::enable_nested_urls();
|
||||
|
||||
$this->assertEquals(1, $controller->ChildrenOf('/')->Count());
|
||||
$this->assertEquals(1, $controller->ChildrenOf('/home/')->Count());
|
||||
$this->assertEquals(2, $controller->ChildrenOf('/home/second-level/')->Count());
|
||||
$this->assertEquals(0, $controller->ChildrenOf('/home/second-level/third-level/')->Count());
|
||||
|
||||
SiteTree::disable_nested_urls();
|
||||
|
||||
$this->assertEquals(1, $controller->ChildrenOf('/')->Count());
|
||||
$this->assertEquals(1, $controller->ChildrenOf('/home/')->Count());
|
||||
$this->assertEquals(2, $controller->ChildrenOf('/second-level/')->Count());
|
||||
$this->assertEquals(0, $controller->ChildrenOf('/third-level/')->Count());
|
||||
}
|
||||
|
||||
public function testDeepNestedURLs() {
|
||||
SiteTree::enable_nested_urls();
|
||||
|
||||
$page = new Page();
|
||||
$page->URLSegment = 'base-page';
|
||||
$page->write();
|
||||
|
||||
for($i = 0; $i < 10; $i++) {
|
||||
$parentID = $page->ID;
|
||||
|
||||
$page = new ContentControllerTest_Page();
|
||||
$page->ParentID = $parentID;
|
||||
$page->Title = "Page Level $i";
|
||||
$page->URLSegment = "level-$i";
|
||||
$page->write();
|
||||
|
||||
$relativeLink = Director::makeRelative($page->Link());
|
||||
$this->assertEquals($page->Title, $this->get($relativeLink)->getBody());
|
||||
}
|
||||
|
||||
|
||||
SiteTree::disable_nested_urls();
|
||||
}
|
||||
|
||||
public function testViewDraft(){
|
||||
|
||||
// test when user does not have permission, should get login form
|
||||
$this->logInWithPermission('EDITOR');
|
||||
$this->assertEquals('403', $this->get('/contact/?stage=Stage')->getstatusCode());
|
||||
|
||||
|
||||
// test when user does have permission, should show page title and header ok.
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$this->assertEquals('200', $this->get('/contact/?stage=Stage')->getstatusCode());
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testLinkShortcodes() {
|
||||
$linkedPage = new SiteTree();
|
||||
$linkedPage->URLSegment = 'linked-page';
|
||||
$linkedPage->write();
|
||||
$linkedPage->publish('Stage', 'Live');
|
||||
|
||||
$page = new SiteTree();
|
||||
$page->URLSegment = 'linking-page';
|
||||
$page->Content = sprintf('<a href="[sitetree_link id=%s]">Testlink</a>', $linkedPage->ID);
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
|
||||
$this->assertContains(
|
||||
sprintf('<a href="%s">Testlink</a>', $linkedPage->Link()),
|
||||
$this->get($page->RelativeLink())->getBody(),
|
||||
'"sitetree_link" shortcodes get parsed properly'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ContentControllerTest_Page extends Page { }
|
||||
|
||||
class ContentControllerTest_Page_Controller extends Page_Controller {
|
||||
|
||||
public static $allowed_actions = array (
|
||||
'second_index'
|
||||
);
|
||||
|
||||
public function index() {
|
||||
return $this->Title;
|
||||
}
|
||||
|
||||
public function second_index() {
|
||||
return $this->index();
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
Group:
|
||||
editors:
|
||||
Title: Editors
|
||||
admins:
|
||||
Title: Administrators
|
||||
|
||||
Permission:
|
||||
admins:
|
||||
Code: VIEW_DRAFT_CONTENT
|
||||
Group: =>Group.admins
|
||||
editors:
|
||||
Group: =>Group.editors
|
||||
|
||||
Member:
|
||||
editor:
|
||||
FirstName: Test
|
||||
Surname: Editor
|
||||
Groups: =>Group.editors
|
||||
admin:
|
||||
FirstName: Test
|
||||
Surname: Administrator
|
||||
Groups: =>Group.admins
|
||||
|
||||
|
||||
ContentControllerTest_Page:
|
||||
root_page:
|
||||
Title: Home Page
|
||||
URLSegment: home
|
||||
second_level_page:
|
||||
Title: Second Level Page
|
||||
URLSegment: second-level
|
||||
Parent: =>ContentControllerTest_Page.root_page
|
||||
third_level_page:
|
||||
Title: Third Level Page
|
||||
URLSegment: third-level
|
||||
Parent: =>ContentControllerTest_Page.second_level_page
|
||||
third_level_page_2:
|
||||
Title: Third Level Page Two
|
||||
URLSegment: third-level-2
|
||||
Parent: =>ContentControllerTest_Page.second_level_page
|
||||
contact_page:
|
||||
Title: Contact Page
|
||||
URLSegment: contact
|
||||
CanViewType: OnlyTheseUsers
|
||||
EditorGroups: =>Group.admins
|
||||
|
@ -1,237 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ModelAsControllerTest extends FunctionalTest {
|
||||
|
||||
protected $usesDatabase = true;
|
||||
|
||||
static $fixture_file = 'sapphire/tests/ModelAsControllerTest.yml';
|
||||
|
||||
protected $autoFollowRedirection = false;
|
||||
|
||||
protected $orig = array();
|
||||
|
||||
/**
|
||||
* New tests require nested urls to be enabled, but the site might not
|
||||
* support nested URLs.
|
||||
* This setup will enable nested-urls for this test and resets the state
|
||||
* after the tests have been performed.
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->orig['nested_urls'] = SiteTree::nested_urls();
|
||||
SiteTree::enable_nested_urls();
|
||||
}
|
||||
|
||||
/**
|
||||
* New tests require nested urls to be enabled, but the site might not
|
||||
* support nested URLs.
|
||||
* This setup will enable nested-urls for this test and resets the state
|
||||
* after the tests have been performed.
|
||||
*/
|
||||
function tearDown() {
|
||||
|
||||
if (isset($this->orig['nested_urls']) && !$this->orig['nested_urls']) {
|
||||
SiteTree::disable_nested_urls();
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
|
||||
protected function generateNestedPagesFixture() {
|
||||
$level1 = new Page();
|
||||
$level1->Title = 'First Level';
|
||||
$level1->URLSegment = 'level1';
|
||||
$level1->write();
|
||||
$level1->publish('Stage', 'Live');
|
||||
|
||||
$level1->URLSegment = 'newlevel1';
|
||||
$level1->write();
|
||||
$level1->publish('Stage', 'Live');
|
||||
|
||||
$level2 = new Page();
|
||||
$level2->Title = 'Second Level';
|
||||
$level2->URLSegment = 'level2';
|
||||
$level2->ParentID = $level1->ID;
|
||||
$level2->write();
|
||||
$level2->publish('Stage', 'Live');
|
||||
|
||||
$level2->URLSegment = 'newlevel2';
|
||||
$level2->write();
|
||||
$level2->publish('Stage', 'Live');
|
||||
|
||||
$level3 = New Page();
|
||||
$level3->Title = "Level 3";
|
||||
$level3->URLSegment = 'level3';
|
||||
$level3->ParentID = $level2->ID;
|
||||
$level3->write();
|
||||
$level3->publish('Stage','Live');
|
||||
|
||||
$level3->URLSegment = 'newlevel3';
|
||||
$level3->write();
|
||||
$level3->publish('Stage','Live');
|
||||
}
|
||||
|
||||
/**
|
||||
* We're building up a page hierarchy ("nested URLs") and rename
|
||||
* all the individual pages afterwards. The assumption is that
|
||||
* all pages will be found by their old segments.
|
||||
*
|
||||
* NOTE: This test requires nested_urls
|
||||
*
|
||||
* Original: level1/level2/level3
|
||||
* Republished as: newlevel1/newlevel2/newlevel3
|
||||
*/
|
||||
public function testRedirectsNestedRenamedPages(){
|
||||
$this->generateNestedPagesFixture();
|
||||
|
||||
// check a first level URLSegment
|
||||
$response = $this->get('level1/action');
|
||||
$this->assertEquals($response->getStatusCode(),301);
|
||||
$this->assertEquals(
|
||||
Controller::join_links(Director::baseURL() . 'newlevel1/action'),
|
||||
$response->getHeader('Location')
|
||||
);
|
||||
|
||||
// check second level URLSegment
|
||||
$response = $this->get('newlevel1/level2');
|
||||
$this->assertEquals($response->getStatusCode(),301 );
|
||||
$this->assertEquals(
|
||||
Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/'),
|
||||
$response->getHeader('Location')
|
||||
);
|
||||
|
||||
// check third level URLSegment
|
||||
$response = $this->get('newlevel1/newlevel2/level3');
|
||||
$this->assertEquals($response->getStatusCode(), 301);
|
||||
$this->assertEquals(
|
||||
Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/'),
|
||||
$response->getHeader('Location')
|
||||
);
|
||||
|
||||
$response = $this->get('newlevel1/newlevel2/level3');
|
||||
}
|
||||
|
||||
public function testRedirectionForPreNestedurlsBookmarks(){
|
||||
$this->generateNestedPagesFixture();
|
||||
|
||||
// Up-to-date URLs will be redirected to the appropriate subdirectory
|
||||
$response = $this->get('newlevel3');
|
||||
$this->assertEquals(301, $response->getStatusCode());
|
||||
$this->assertEquals(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/',
|
||||
$response->getHeader("Location"));
|
||||
|
||||
// So will the legacy ones
|
||||
$response = $this->get('level3');
|
||||
$this->assertEquals(301, $response->getStatusCode());
|
||||
$this->assertEquals(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/',
|
||||
$response->getHeader("Location"));
|
||||
}
|
||||
|
||||
function testDoesntRedirectToNestedChildrenOutsideOfOwnHierarchy() {
|
||||
$this->generateNestedPagesFixture();
|
||||
|
||||
$otherParent = new Page(array(
|
||||
'URLSegment' => 'otherparent'
|
||||
));
|
||||
$otherParent->write();
|
||||
$otherParent->publish('Stage', 'Live');
|
||||
|
||||
$response = $this->get('level1/otherparent');
|
||||
$this->assertEquals($response->getStatusCode(), 301);
|
||||
|
||||
$response = $this->get('newlevel1/otherparent');
|
||||
$this->assertEquals(
|
||||
$response->getStatusCode(),
|
||||
404,
|
||||
'Requesting an unrelated page on a renamed parent should be interpreted as a missing action, not a redirect'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* NOTE: This test requires nested_urls
|
||||
*
|
||||
*/
|
||||
function testRedirectsNestedRenamedPagesWithGetParameters() {
|
||||
$this->generateNestedPagesFixture();
|
||||
|
||||
// check third level URLSegment
|
||||
$response = $this->get('newlevel1/newlevel2/level3/?foo=bar&test=test');
|
||||
$this->assertEquals($response->getStatusCode(), 301);
|
||||
$this->assertEquals(
|
||||
Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/', '?foo=bar&test=test'),
|
||||
$response->getHeader('Location')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* NOTE: This test requires nested_urls
|
||||
*
|
||||
*/
|
||||
function testDoesntRedirectToNestedRenamedPageWhenNewExists() {
|
||||
$this->generateNestedPagesFixture();
|
||||
|
||||
$otherLevel1 = new Page(array(
|
||||
'Title' => "Other Level 1",
|
||||
'URLSegment' => 'level1'
|
||||
));
|
||||
$otherLevel1->write();
|
||||
$otherLevel1->publish('Stage', 'Live');
|
||||
|
||||
$response = $this->get('level1');
|
||||
$this->assertEquals(
|
||||
$response->getStatusCode(),
|
||||
200
|
||||
);
|
||||
|
||||
$response = $this->get('level1/newlevel2');
|
||||
$this->assertEquals(
|
||||
$response->getStatusCode(),
|
||||
404,
|
||||
'The old newlevel2/ URLSegment is checked as an action on the new page, which shouldnt exist.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* NOTE: This test requires nested_urls
|
||||
*
|
||||
*/
|
||||
function testFindOldPage(){
|
||||
$page = new Page();
|
||||
$page->Title = 'First Level';
|
||||
$page->URLSegment = 'oldurl';
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
|
||||
$page->URLSegment = 'newurl';
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
|
||||
$response = ModelAsController::find_old_page('oldurl');
|
||||
$this->assertEquals('First Level',$response->Title);
|
||||
|
||||
$page2 = new Page();
|
||||
$page2->Title = 'Second Level Page';
|
||||
$page2->URLSegment = 'oldpage2';
|
||||
$page2->ParentID = $page->ID;
|
||||
$page2->write();
|
||||
$page2->publish('Stage', 'Live');
|
||||
|
||||
$page2->URLSegment = 'newpage2';
|
||||
$page2->write();
|
||||
$page2->publish('Stage', 'Live');
|
||||
|
||||
$response = ModelAsController::find_old_page('oldpage2',$page2->ParentID);
|
||||
$this->assertEquals('Second Level Page',$response->Title);
|
||||
|
||||
$response = ModelAsController::find_old_page('oldpage2',$page2->ID);
|
||||
$this->assertEquals(false, $response );
|
||||
}
|
||||
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class RootURLControllerTest extends SapphireTest {
|
||||
static $fixture_file = 'sapphire/tests/control/RootURLControllerTest.yml';
|
||||
|
||||
function testHomepageForDomain() {
|
||||
$originalHost = $_SERVER['HTTP_HOST'];
|
||||
|
||||
// Tests matching an HTTP_HOST value to URLSegment homepage values
|
||||
$tests = array(
|
||||
'page.co.nz' => 'page1',
|
||||
'www.page.co.nz' => 'page1',
|
||||
'help.com' => 'page1',
|
||||
'www.help.com' => 'page1',
|
||||
'something.com' => 'page1',
|
||||
'www.something.com' => 'page1',
|
||||
|
||||
'other.co.nz' => 'page2',
|
||||
'www.other.co.nz' => 'page2',
|
||||
'right' => 'page2',
|
||||
'www. right' => 'page2',
|
||||
|
||||
'only.com' => 'page3',
|
||||
'www.only.com' => 'page3',
|
||||
|
||||
'www.somethingelse.com' => 'home',
|
||||
'somethingelse.com' => 'home',
|
||||
|
||||
// Test some potential false matches to page2 and page3
|
||||
'alternate.only.com' => 'home',
|
||||
'www.alternate.only.com' => 'home',
|
||||
'alternate.something.com' => 'home',
|
||||
);
|
||||
|
||||
foreach($tests as $domain => $urlSegment) {
|
||||
RootURLController::reset();
|
||||
$_SERVER['HTTP_HOST'] = $domain;
|
||||
|
||||
$this->assertEquals(
|
||||
$urlSegment,
|
||||
RootURLController::get_homepage_link(),
|
||||
"Testing $domain matches $urlSegment"
|
||||
);
|
||||
}
|
||||
|
||||
$_SERVER['HTTP_HOST'] = $originalHost;
|
||||
}
|
||||
|
||||
public function testGetHomepageLink() {
|
||||
$default = $this->objFromFixture('Page', 'home');
|
||||
$nested = $this->objFromFixture('Page', 'nested');
|
||||
|
||||
SiteTree::disable_nested_urls();
|
||||
$this->assertEquals('home', RootURLController::get_homepage_link());
|
||||
SiteTree::enable_nested_urls();
|
||||
$this->assertEquals('home', RootURLController::get_homepage_link());
|
||||
|
||||
$nested->HomepageForDomain = str_replace('www.', null, $_SERVER['HTTP_HOST']);
|
||||
$nested->write();
|
||||
|
||||
RootURLController::reset();
|
||||
SiteTree::disable_nested_urls();
|
||||
$this->assertEquals('nested-home', RootURLController::get_homepage_link());
|
||||
|
||||
RootURLController::reset();
|
||||
SiteTree::enable_nested_urls();
|
||||
$this->assertEquals('home/nested-home', RootURLController::get_homepage_link());
|
||||
|
||||
$nested->HomepageForDomain = null;
|
||||
$nested->write();
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
Page:
|
||||
home:
|
||||
Title: Home
|
||||
nested:
|
||||
Title: Nested Home
|
||||
Parent: =>Page.home
|
||||
page1:
|
||||
Title: First Page
|
||||
URLSegment: page1
|
||||
HomepageForDomain: page.co.nz, help.com,something.com, www.something.com
|
||||
page2:
|
||||
Title: Second Page
|
||||
URLSegment: page2
|
||||
HomepageForDomain: other.co.nz, right
|
||||
page3:
|
||||
Title: Third Page
|
||||
URLSegment: page3
|
||||
HomepageForDomain: only.com
|
Loading…
Reference in New Issue
Block a user