Source of file LinkMapping.php
Size: 11,554 Bytes - Last Modified: 2021-12-23T10:06:11+00:00
/var/www/docs.ssmods.com/process/src/src/objects/LinkMapping.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 | <?php namespace nglasl\misdirection; use SilverStripe\CMS\Model\SiteTree; use SilverStripe\Control\Controller; use SilverStripe\Control\Director; use SilverStripe\Control\HTTP; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Config\Config; use SilverStripe\Forms\CheckboxField; use SilverStripe\Forms\DropdownField; use SilverStripe\Forms\FieldGroup; use SilverStripe\Forms\HeaderField; use SilverStripe\Forms\SelectionGroup; use SilverStripe\Forms\TextField; use SilverStripe\Forms\TreeDropdownField; use SilverStripe\ORM\DataObject; use SilverStripe\Security\Permission; use SilverStripe\View\Requirements; use Symbiote\Multisites\Multisites; /** * Simple and regular expression link redirection definitions. * @author Nathan Glasl <nathan@symbiote.com.au> */ class LinkMapping extends DataObject { private static $table_name = 'LinkMapping'; /** * Manually define the redirect page relationship when the CMS module is not present. */ private static $db = array( 'LinkType' => "Enum('Simple, Regular Expression', 'Simple')", 'MappedLink' => 'Varchar(255)', 'IncludesHostname' => 'Boolean', 'Priority' => 'Int', 'RedirectType' => "Enum('Link, Page', 'Link')", 'RedirectLink' => 'Varchar(255)', 'RedirectPageID' => 'Int', 'ResponseCode' => 'Int', 'HostnameRestriction' => 'Varchar(255)' ); private static $defaults = array( 'ResponseCode' => 301 ); /** * Make sure the link mappings are only ordered by priority and specificity when matching. */ private static $default_sort = 'ID DESC'; private static $searchable_fields = array( 'MappedLink', 'LinkType', 'Priority', 'RedirectType' ); private static $summary_fields = array( 'MappedLink', 'LinkSummary', 'Priority', 'RedirectTypeSummary', 'RedirectPageTitle' ); private static $field_labels = array( 'MappedLink' => 'Mapping', 'LinkSummary' => 'Redirection', 'RedirectTypeSummary' => 'Redirect Type', 'RedirectPageTitle' => 'Redirect Page Title' ); /** * Make sure previous link mappings take precedence. */ private static $priority = 'ASC'; /** * Keep track of the initial URL for regular expression pattern replacement. * * @parameter <{URL}> string */ private $matchedURL; public function setMatchedURL($matchedURL) { $this->matchedURL = $matchedURL; } public function canView($member = null) { return true; } public function canEdit($member = null) { return ( Permission::checkMember($member, 'ADMIN') || Permission::checkMember($member, 'CMS_ACCESS_nglasl\misdirection\MisdirectionAdmin') ); } public function canCreate($member = null, $context = array()) { return ( Permission::checkMember($member, 'ADMIN') || Permission::checkMember($member, 'CMS_ACCESS_nglasl\misdirection\MisdirectionAdmin') ); } public function canDelete($member = null) { return ( Permission::checkMember($member, 'ADMIN') || Permission::checkMember($member, 'CMS_ACCESS_nglasl\misdirection\MisdirectionAdmin') ); } /** * Print the mapped URL associated with this link mapping. * * @return string */ public function getTitle() { return $this->MappedLink; } public function getCMSFields() { $fields = parent::getCMSFields(); Requirements::css('nglasl/silverstripe-misdirection: client/css/misdirection.css'); // Remove any fields that are not required in their default state. $fields->removeByName('MappedLink'); $fields->removeByName('IncludesHostname'); $fields->removeByName('Priority'); $fields->removeByName('RedirectType'); $fields->removeByName('RedirectLink'); $fields->removeByName('RedirectPageID'); $fields->removeByName('ResponseCode'); $fields->removeByName('HostnameRestriction'); // Update any fields that are displayed. $fields->dataFieldByName('LinkType')->addExtraClass('link-type')->setTitle('Type'); // Instantiate the required fields. $fields->insertBefore(HeaderField::create( 'MappedLinkHeader', 'Mapping', 3 ), 'LinkType'); // Retrieve the mapped link configuration as a single grouping. $URL = FieldGroup::create( TextField::create( 'MappedLink', '' )->addExtraClass('mapped-link')->setDescription('This should <strong>not</strong> include the <strong>HTTP/S</strong> scheme'), CheckboxField::create( 'IncludesHostname', 'Includes Hostname?' ) )->setTitle('URL'); $fields->addFieldToTab('Root.Main', $URL); // Generate the 1 - 10 priority selection. $range = array(); for($iteration = 1; $iteration <= 10; $iteration++) { $range[$iteration] = $iteration; } $fields->addFieldToTab('Root.Main', DropdownField::create( 'Priority', null, $range )); // Retrieve the redirection configuration as a single grouping. $fields->addFieldToTab('Root.Main', HeaderField::create( 'RedirectionHeader', 'Redirection', 3 )); $redirect = FieldGroup::create(); $redirect->push(TextField::create( 'RedirectLink', '' )->addExtraClass('redirect-link')->setDescription('This requires the <strong>HTTP/S</strong> scheme for an external URL')); // Allow redirect page configuration when the CMS module is present. if(ClassInfo::exists(SiteTree::class)) { // Allow redirect type configuration. if(!$this->RedirectType) { // Initialise the default redirect type. $this->RedirectType = 'Link'; } $fields->addFieldToTab('Root.Main', SelectionGroup::create( 'RedirectType', array( 'Link//To URL' => $redirect, 'Page//To Page' => TreeDropdownField::create( 'RedirectPageID', '', SiteTree::class ) ) )); } else { $redirect->setTitle('To URL'); $fields->addFieldToTab('Root.Main', $redirect); } // Use third party validation against an external URL. if($this->canEdit()) { Requirements::javascript('nglasl/silverstripe-misdirection: client/javascript/misdirection-link-mapping.js'); $redirect->push(CheckboxField::create( 'ValidateExternal', 'Validate External URL?' )->addExtraClass('validate-external')); } // Retrieve the response code selection. $responses = Config::inst()->get(MisDirectionRequestProcessor::class, 'status_codes'); $selection = array(); foreach($responses as $code => $description) { if(($code >= 300) && ($code < 400)) { $selection[$code] = "{$code}: {$description}"; } } $fields->addFieldToTab('Root.Main', DropdownField::create( 'ResponseCode', 'Response Code', $selection )); // The optional hostname restriction is now deprecated. if($this->HostnameRestriction) { $fields->addFieldToTab('Root.Optional', TextField::create( 'HostnameRestriction' )); } // Allow extension customisation. $this->extend('updateLinkMappingCMSFields', $fields); return $fields; } public function validate() { $result = parent::validate(); // Determine whether a regular expression mapping is possible to match against. if($result->isValid() && ($this->LinkType === 'Regular Expression') && (!$this->MappedLink || !is_numeric(@preg_match("%{$this->MappedLink}%", null)))) { $result->addError('Invalid regular expression!'); } // Use third party validation to determine an external URL (https://gist.github.com/dperini/729294 and http://mathiasbynens.be/demo/url-regex). else if($result->isValid() && $this->ValidateExternal && $this->RedirectLink && !MisdirectionService::is_external_URL($this->RedirectLink)) { $result->addError('External URL validation failed!'); } // Allow extension customisation. $this->extend('validateLinkMapping', $result); return $result; } /** * Unify any URLs that may have been defined. */ public function onBeforeWrite() { parent::onBeforeWrite(); $this->MappedLink = MisdirectionService::unify_URL($this->MappedLink); $this->RedirectLink = trim($this->RedirectLink, ' ?/'); $this->HostnameRestriction = MisdirectionService::unify_URL($this->HostnameRestriction); } /** * Retrieve the page associated with this link mapping redirection. * * @return site tree */ public function getRedirectPage() { return (ClassInfo::exists(SiteTree::class) && $this->RedirectPageID) ? SiteTree::get()->byID($this->RedirectPageID) : null; } /** * Retrieve the redirection URL. * * @return string */ public function getLink() { if($this->RedirectType === 'Page') { // Determine the home page URL when appropriate. if(($page = $this->getRedirectPage()) && ($link = ($page->Link() === Director::baseURL()) ? Controller::join_links(Director::baseURL(), 'home/') : $page->Link())) { // This is to support multiple sites, where the absolute page URLs are treated as relative. return MisdirectionService::is_external_URL($link) ? ltrim($link, '/') : $link; } } else { // Apply the regular expression pattern replacement. if($link = (($this->LinkType === 'Regular Expression') && $this->matchedURL) ? preg_replace("%{$this->MappedLink}%i", $this->RedirectLink, $this->matchedURL) : $this->RedirectLink) { // When appropriate, prepend the base URL to match a page redirection. $prepended = Controller::join_links(Director::baseURL(), $link); if(MisdirectionService::is_external_URL($link)) { return ClassInfo::exists(Multisites::class) ? HTTP::setGetVar('misdirected', true, $link) : $link; } // This is needed, otherwise infinitely recursive mappings won't be detected in advance. else if(MisdirectionService::is_external_URL($prepended)) { return $link; } else { return $prepended; } } } // No redirection URL has been found. return null; } /** * Retrieve the redirection hostname. * * @return string */ public function getLinkHost() { if($this->RedirectType === 'Page') { // Determine the home page URL when appropriate. if(($page = $this->getRedirectPage()) && ($link = ($page->Link() === Director::baseURL()) ? Controller::join_links(Director::baseURL(), 'home/') : $page->Link())) { // Determine whether a redirection hostname exists. return MisdirectionService::is_external_URL($link) ? parse_url($link, PHP_URL_HOST) : null; } } else { // Apply the regular expression pattern replacement. if($link = (($this->LinkType === 'Regular Expression') && $this->matchedURL) ? preg_replace("%{$this->MappedLink}%i", $this->RedirectLink, $this->matchedURL) : $this->RedirectLink) { // Determine whether a redirection hostname exists. return MisdirectionService::is_external_URL($link) ? parse_url($link, PHP_URL_HOST) : null; } } // No redirection hostname has been found. return null; } /** * Retrieve the redirection URL for display purposes. * * @return string */ public function getLinkSummary() { return ($link = $this->getLink()) ? trim($link, ' ?/') : '-'; } /** * Retrieve the redirection type for display purposes. * * @return string */ public function getRedirectTypeSummary() { return $this->RedirectType ? $this->RedirectType : '-'; } /** * Retrieve the page title associated with this link mapping redirection. * * @return string */ public function getRedirectPageTitle() { return (($this->RedirectType === 'Page') && ($page = $this->getRedirectPage())) ? $page->Title : '-'; } /** * Determine if the link mapping is live on the current stage. * * @return string */ public function isLive() { return ($this->RedirectType === 'Page') ? ($this->getRedirectPage() ? 'true' : 'false') : '-'; } } |