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 cms * @subpackage control */ class ContentController extends Controller { protected $dataRecord; private static $extensions = array('OldPageRedirector'); private static $allowed_actions = array( 'successfullyinstalled', 'deleteinstallfiles', // secured through custom code 'LoginForm' ); /** * 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. * * @param string|null $action Action to link to. * @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 SS_List */ public function ChildrenOf($parentRef) { $parent = SiteTree::get_by_link($parentRef); if(!$parent && is_numeric($parentRef)) { $parent = DataObject::get_by_id('SiteTree', $parentRef); } if($parent) return $parent->Children(); } /** * @param string $link * @return SiteTree */ 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 && !$this->redirectedTo() ) { $getVars = $_GET; unset($getVars['url']); if($getVars) $url = "?" . http_build_query($getVars); else $url = ""; $this->redirect($url, 301); return; } if($this->dataRecord) $this->dataRecord->extend('contentcontrollerInit', $this); else singleton('SiteTree')->extend('contentcontrollerInit', $this); if($this->redirectedTo()) 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->canView()) { Session::clear('currentStage'); Session::clear('archiveDate'); $permissionMessage = sprintf( _t( "ContentController.DRAFT_SITE_ACCESS_RESTRICTION", 'You must log in with your CMS password in order to view the draft or archived content. '. 'Click here to go back to the published site.' ), Controller::join_links($this->Link(), "?stage=Live") ); return Security::permissionFailure($this, $permissionMessage); } } // Use theme from the site config if(($config = SiteConfig::current_site_config()) && $config->Theme) { Config::inst()->update('SSViewer', '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. * * @param SS_HTTPRequest $request * @param DataModel $model * @return SS_HTTPResponse * @throws SS_HTTPResponse_Exception */ public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { $child = null; $action = $request->param('Action'); $this->setDataModel($model); // 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::config()->nested_urls && !$this->hasAction($action)) { // See ModelAdController->getNestedController() for similar logic if(class_exists('Translatable')) Translatable::disable_locale_filter(); // look for a page with this URLSegment $child = $this->model->SiteTree->filter(array( 'ParentID' => $this->ID, 'URLSegment' => rawurlencode($action) ))->first(); if(class_exists('Translatable')) Translatable::enable_locale_filter(); } // we found a page with this URLSegment. if($child) { $request->shiftAllParams(); $request->shift(); $response = ModelAsController::controller_for($child)->handleRequest($request, $model); } 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(class_exists('Translatable')) { 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()); try { $response = parent::handleRequest($request, $model); Director::set_current_page(null); } catch(SS_HTTPResponse_Exception $e) { $this->popCurrent(); Director::set_current_page(null); throw $e; } } return $response; } /** * @uses ErrorPage::response_for() */ public function httpError($code, $message = null) { // Don't use the HTML response for media requests $response = $this->getRequest()->isMedia() ? null : ErrorPage::response_for($code); // Failover to $message if the HTML response is unavailable / inappropriate parent::httpError($code, $response ? $response : $message); } /** * Get the project name * * @return string */ public 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. * @param int $level Menu level to return. * @return ArrayList */ public function getMenu($level = 1) { if($level == 1) { $result = SiteTree::get()->filter(array( "ShowInMenus" => 1, "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 ArrayList($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(CMS_DIR . '/css/SilverStripeNavigator.css'); Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery/jquery.js'); Requirements::javascript(CMS_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} - ". _t('ContentController.LOGOUT', 'Log out'). ""; } else { $logInMessage = sprintf( '%s - %s' , _t('ContentController.NOTLOGGEDIN', 'Not logged in') , Config::inst()->get('Security', 'login_url'), _t('ContentController.LOGIN', 'Login') ."" ); } $viewPageIn = _t('ContentController.VIEWPAGEIN', 'View Page in:'); return <<