Version: current

      1 <?php
      2 /**
      3  * ModelAsController deals with mapping the initial request to the first {@link SiteTree}/{@link ContentController}
      4  * pair, which are then used to handle the request.
      5  *
      6  * @package sapphire
      7  * @subpackage control
      8  */
      9 class ModelAsController extends Controller implements NestedController {
     10
     11     /**
     12      * Get the appropriate {@link ContentController} for handling a {@link SiteTree} object, link it to the object and
     13      * return it.
     14      *
     15      * @param SiteTree $sitetree
     16      * @param string $action
     17      * @return ContentController
     18      */
     19     public static function controller_for(SiteTree $sitetree, $action = null) {
     20         if($sitetree->class == 'SiteTree') $controller = "ContentController";
     21         else $controller = "{$sitetree->class}_Controller";
     22
     23         if($action && class_exists($controller . '_' . ucfirst($action))) {
     24             $controller = $controller . '_' . ucfirst($action);
     25         }
     26
     27         return class_exists($controller) ? new $controller($sitetree) : $sitetree;
     28     }
     29
     30     public function init() {
     31         singleton('SiteTree')->extend('modelascontrollerInit', $this);
     32         parent::init();
     33     }
     34
     35     /**
     36      * @uses ModelAsController::getNestedController()
     37      * @return SS_HTTPResponse
     38      */
     39     public function handleRequest(SS_HTTPRequest $request) {
     40         $this->request = $request;
     41
     42         $this->pushCurrent();
     43
     44         // Create a response just in case init() decides to redirect
     45         $this->response = new SS_HTTPResponse();
     46
     47         $this->init();
     48
     49         // If we had a redirection or something, halt processing.
     50         if($this->response->isFinished()) {
     51             $this->popCurrent();
     52             return $this->response;
     53         }
     54
     55         // If the database has not yet been created, redirect to the build page.
     56         if(!DB::isActive() || !ClassInfo::hasTable('SiteTree')) {
     57             $this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null));
     58             $this->popCurrent();
     59
     60             return $this->response;
     61         }
     62
     63         try {
     64             $result = $this->getNestedController();
     65
     66             if($result instanceof RequestHandler) {
     67                 $result = $result->handleRequest($this->request);
     68             } else if(!($result instanceof SS_HTTPResponse)) {
     69                 user_error("ModelAsController::getNestedController() returned bad object type '" .
     70                     get_class($result)."'", E_USER_WARNING);
     71             }
     72         } catch(SS_HTTPResponse_Exception $responseException) {
     73             $result = $responseException->getResponse();
     74         }
     75
     76         $this->popCurrent();
     77         return $result;
     78     }
     79
     80     /**
     81      * @return ContentController
     82      */
     83     public function getNestedController() {
     84         $request = $this->request;
     85
     86         if(!$URLSegment = $request->param('URLSegment')) {
     87             throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.');
     88         }
     89
     90         // Find page by link, regardless of current locale settings
     91         Translatable::disable_locale_filter();
     92         $sitetree = DataObject::get_one(
     93             'SiteTree',
     94             sprintf(
     95                 '"URLSegment" = \'%s\' %s',
     96                 Convert::raw2sql($URLSegment),
     97                 (SiteTree::nested_urls() ? 'AND "ParentID" = 0' : null)
     98             )
     99         );
    100         Translatable::enable_locale_filter();
    101
    102         if(!$sitetree) {
    103             // If a root page has been renamed, redirect to the new location.
    104             // See ContentController->handleRequest() for similiar logic.
    105             if($redirect = self::find_old_page($URLSegment)) {
    106                 $params = $request->getVars();
    107                 if(isset($params['url'])) unset($params['url']);
    108                 $this->response = new SS_HTTPResponse();
    109                 $this->response->redirect(
    110                     Controller::join_links(
    111                         $redirect->Link(
    112                             Controller::join_links(
    113                                 $request->param('Action'),
    114                                 $request->param('ID'),
    115                                 $request->param('OtherID')
    116                             )
    117                         ),
    118                         // Needs to be in separate join links to avoid urlencoding
    119                         ($params) ? '?' . http_build_query($params) : null
    120                     ),
    121                     301
    122                 );
    123
    124                 return $this->response;
    125             }
    126
    127             if($response = ErrorPage::response_for(404)) {
    128                 return $response;
    129             } else {
    130                 $this->httpError(404, 'The requested page could not be found.');
    131             }
    132         }
    133
    134         // Enforce current locale setting to the loaded SiteTree object
    135         if($sitetree->Locale) Translatable::set_current_locale($sitetree->Locale);
    136
    137         if(isset($_REQUEST['debug'])) {
    138             Debug::message("Using record #$sitetree->ID of type $sitetree->class with link {$sitetree->Link()}");
    139         }
    140
    141         return self::controller_for($sitetree, $this->request->param('Action'));
    142     }
    143
    144     /**
    145      * @param string $URLSegment A subset of the url. i.e in /home/contact/ home and contact are URLSegment.
    146      * @param int $parentID The ID of the parent of the page the URLSegment belongs to.
    147      * @return SiteTree
    148      */
    149     static function find_old_page($URLSegment,$parentID = 0, $ignoreNestedURLs = false) {
    150         $URLSegment = Convert::raw2sql($URLSegment);
    151
    152         $ParentIDFilter = (!$ignoreNestedURLs && SiteTree::nested_urls()) ? ' AND "ParentID" = ' . (int)$parentID : '';
    153
    154         // First get an old version of a page that has been renamed.
    155         $query = new SQLQuery (
    156             '"RecordID"',
    157             '"SiteTree_versions"',
    158             "\"URLSegment\" = '$URLSegment' AND \"WasPublished\" = 1" . $ParentIDFilter,
    159             '"LastEdited" DESC',
    160             null,
    161             null,
    162             1
    163         );
    164         $record = $query->execute()->first();
    165
    166         if($record && ($oldPage = DataObject::get_by_id('SiteTree', $record['RecordID']))) {
    167             // Run the page through an extra filter to ensure that all decorators are applied.
    168             if(SiteTree::get_by_link($oldPage->RelativeLink())) return $oldPage;
    169         }
    170
    171         // Next - find page that has been moved to other parent with some URLSegment but not found in page version history
    172         if(SiteTree::nested_urls()) {
    173             $pages = DataObject::get(
    174                 'SiteTree',
    175                 "\"URLSegment\" = '$URLSegment'"
    176             );
    177             if($pages && $pages->Count() == 1) return $pages->First();
    178         }
    179
    180     }
    181
    182 }
    183

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -