Version: current

      1 <?php
      2 /**
      3  * A redirector page redirects when the page is visited.
      4  *
      5  * @package cms
      6  * @subpackage content
      7  */
      8 class RedirectorPage extends Page {
      9
     10     static $icon = array("cms/images/treeicons/page-shortcut","file");
     11
     12     static $db = array(
     13         "RedirectionType" => "Enum('Internal,External','Internal')",
     14         "ExternalURL" => "Varchar(2083)" // 2083 is the maximum length of a URL in Internet Explorer.
     15     );
     16
     17     static $defaults = array(
     18         "RedirectionType" => "Internal"
     19     );
     20
     21     static $has_one = array(
     22         "LinkTo" => "SiteTree",
     23     );
     24
     25     static $many_many = array(
     26     );
     27
     28     /**
     29      * Returns this page if the redirect is external, otherwise
     30      * returns the target page.
     31      * @return SiteTree
     32      */
     33     function ContentSource() {
     34         if($this->RedirectionType == 'Internal') {
     35             return $this->LinkTo();
     36         } else {
     37             return $this;
     38         }
     39     }
     40
     41     /**
     42      * Return the the link that should be used for this redirector page, in navigation, etc.
     43      * If the redirectorpage has been appropriately configured, then it will return the redirection
     44      * destination, to prevent unnecessary 30x redirections.  However, if it's misconfigured, then
     45      * it will return a link to itself, which will then display an error message.
     46      */
     47     function Link() {
     48         if($link = $this->redirectionLink()) return $link;
     49         else return $this->regularLink();
     50     }
     51
     52     /**
     53      * Return the normal link directly to this page.  Once you visit this link, a 30x redirection
     54      * will take you to your final destination.
     55      */
     56     function regularLink($action = null) {
     57         return parent::Link($action);
     58     }
     59
     60     /**
     61      * Return the link that we should redirect to.
     62      * Only return a value if there is a legal redirection destination.
     63      */
     64     function redirectionLink() {
     65         if($this->RedirectionType == 'External') {
     66             if($this->ExternalURL) {
     67                 return $this->ExternalURL;
     68             }
     69
     70         } else {
     71             $linkTo = $this->LinkToID ? DataObject::get_by_id("SiteTree", $this->LinkToID) : null;
     72
     73             if($linkTo) {
     74                 // We shouldn't point to ourselves - that would create an infinite loop!  Return null since we have a
     75                 // bad configuration
     76                 if($this->ID == $linkTo->ID) {
     77                     return null;
     78
     79                 // If we're linking to another redirectorpage then just return the URLSegment, to prevent a cycle of redirector
     80                 // pages from causing an infinite loop.  Instead, they will cause a 30x redirection loop in the browser, but
     81                 // this can be handled sufficiently gracefully by the browser.
     82                 } elseif($linkTo instanceof RedirectorPage) {
     83                     return $linkTo->regularLink();
     84
     85                 // For all other pages, just return the link of the page.
     86                 } else {
     87                     return $linkTo->Link();
     88                 }
     89             }
     90         }
     91     }
     92
     93     function syncLinkTracking() {
     94         if ($this->RedirectionType == 'Internal') {
     95             if($this->LinkToID) {
     96                 $this->HasBrokenLink = DataObject::get_by_id('SiteTree', $this->LinkToID) ? false : true;
     97             } else {
     98                 // An incomplete redirector page definitely has a broken link
     99                 $this->HasBrokenLink = true;
    100             }
    101         } else {
    102             // TODO implement checking of a remote site
    103             $this->HasBrokenLink = false;
    104         }
    105     }
    106
    107     function onBeforeWrite() {
    108         parent::onBeforeWrite();
    109
    110         // Prefix the URL with "http://" if no prefix is found
    111         if($this->ExternalURL && (strpos($this->ExternalURL, '://') === false) && substr($this->ExternalURL,0,1) !== '/') {
    112             $this->ExternalURL = 'http://' . $this->ExternalURL;
    113         }
    114     }
    115
    116     function getCMSFields() {
    117         Requirements::javascript(SAPPHIRE_DIR . "/javascript/RedirectorPage.js");
    118
    119         $fields = parent::getCMSFields();
    120         $fields->removeByName('Content', true);
    121         $fields->addFieldsToTab('Root.Content.Main',
    122             array(
    123                 new HeaderField('RedirectorDescHeader',_t('RedirectorPage.HEADER', "This page will redirect users to another page")),
    124                 new OptionsetField(
    125                     "RedirectionType",
    126                     _t('RedirectorPage.REDIRECTTO', "Redirect to"),
    127                     array(
    128                         "Internal" => _t('RedirectorPage.REDIRECTTOPAGE', "A page on your website"),
    129                         "External" => _t('RedirectorPage.REDIRECTTOEXTERNAL', "Another website"),
    130                     ),
    131                     "Internal"
    132                 ),
    133                 new TreeDropdownField(
    134                     "LinkToID",
    135                     _t('RedirectorPage.YOURPAGE', "Page on your website"),
    136                     "SiteTree"
    137                 ),
    138                 new TextField("ExternalURL", _t('RedirectorPage.OTHERURL', "Other website URL"))
    139             )
    140         );
    141
    142         return $fields;
    143     }
    144
    145     // Don't cache RedirectorPages
    146     function subPagesToCache() {
    147         return array();
    148     }
    149 }
    150
    151 /**
    152  * Controller for the {@link RedirectorPage}.
    153  * @package cms
    154  * @subpackage content
    155  */
    156 class RedirectorPage_Controller extends Page_Controller {
    157     function init() {
    158         if($link = $this->redirectionLink()) {
    159             Director::redirect($link, 301);
    160         }
    161
    162         parent::init();
    163     }
    164
    165     /**
    166      * If we ever get this far, it means that the redirection failed.
    167      */
    168     function Content() {
    169         return "<p class=\"message-setupWithoutRedirect\">" .
    170             _t('RedirectorPage.HASBEENSETUP', 'A redirector page has been set up without anywhere to redirect to.') .
    171             "</p>";
    172     }
    173 }

[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. -