2011-07-15 16:05:58 +02:00
< ? php
/**
* Utility class representing links to different views of a record
* for CMS authors , usually for { @ link SiteTree } objects with " stage " and " live " links .
* Useful both in the CMS and alongside the page template ( for logged in authors ) .
2011-07-21 20:00:48 +02:00
* The class can be used for any { @ link DataObject } subclass implementing the { @ link CMSPreviewable } interface .
2011-07-15 16:05:58 +02:00
*
* New item types can be defined by extending the { @ link SilverStripeNavigatorItem } class ,
* for example the " cmsworkflow " module defines a new " future state " item with a date selector
* to view embargoed data at a future point in time . So the item doesn ' t always have to be a simple link .
*
* @ package cms
* @ subpackage content
*/
2011-07-21 20:00:48 +02:00
class SilverStripeNavigator extends ViewableData {
2011-07-15 16:05:58 +02:00
/**
* @ var DataObject
*/
protected $record ;
/**
2014-02-10 21:35:13 +01:00
* @ param DataObject $record
* @ throws InvalidArgumentException if record doesn ' t implement CMSPreviewable
2011-07-15 16:05:58 +02:00
*/
2012-09-19 12:07:46 +02:00
public function __construct ( $record ) {
2011-07-21 20:00:48 +02:00
if ( ! in_array ( 'CMSPreviewable' , class_implements ( $record ))) {
throw new InvalidArgumentException ( 'SilverStripeNavigator: Record of type %s doesn\'t implement CMSPreviewable' , get_class ( $record ));
}
2011-07-15 16:05:58 +02:00
$this -> record = $record ;
}
/**
2011-10-26 07:39:21 +02:00
* @ return SS_List of SilverStripeNavigatorItem
2011-07-15 16:05:58 +02:00
*/
2012-09-19 12:07:46 +02:00
public function getItems () {
2011-07-21 20:00:48 +02:00
$items = array ();
2011-07-15 16:05:58 +02:00
$classes = ClassInfo :: subclassesFor ( 'SilverStripeNavigatorItem' );
array_shift ( $classes );
// Sort menu items according to priority
$i = 0 ;
foreach ( $classes as $class ) {
// Skip base class
if ( $class == 'SilverStripeNavigatorItem' ) continue ;
$i ++ ;
$item = new $class ( $this -> record );
if ( ! $item -> canView ()) continue ;
// This funny litle formula ensures that the first item added with the same priority will be left-most.
$priority = $item -> getPriority () * 100 - 1 ;
// Ensure that we can have duplicates with the same (default) priority
while ( isset ( $items [ $priority ])) $priority ++ ;
$items [ $priority ] = $item ;
}
ksort ( $items );
2011-07-21 20:00:48 +02:00
2012-12-06 04:34:48 +01:00
// Drop the keys and let the ArrayList handle the numbering, so $First, $Last and others work properly.
return new ArrayList ( array_values ( $items ));
2011-07-15 16:05:58 +02:00
}
/**
* @ return DataObject
*/
2012-09-19 12:07:46 +02:00
public function getRecord () {
2011-07-15 16:05:58 +02:00
return $this -> record ;
}
/**
2011-07-21 20:00:48 +02:00
* @ param DataObject $record
2011-07-15 16:05:58 +02:00
* @ return Array template data
*/
2012-09-19 12:07:46 +02:00
static public function get_for_record ( $record ) {
2011-07-15 16:05:58 +02:00
$html = '' ;
$message = '' ;
$navigator = new SilverStripeNavigator ( $record );
$items = $navigator -> getItems ();
foreach ( $items as $item ) {
$text = $item -> getHTML ();
if ( $text ) $html .= $text ;
$newMessage = $item -> getMessage ();
2013-03-18 14:57:20 +01:00
if ( $newMessage && $item -> isActive ()) $message = $newMessage ;
2011-07-15 16:05:58 +02:00
}
return array (
'items' => $html ,
'message' => $message
);
}
}
/**
* Navigator items are links that appear in the $SilverStripeNavigator bar .
2011-07-21 20:00:48 +02:00
* To add an item , extend this class - it will be automatically picked up .
* When instanciating items manually , please ensure to call { @ link canView ()} .
2011-07-15 16:05:58 +02:00
*
* @ package cms
* @ subpackage content
*/
class SilverStripeNavigatorItem extends ViewableData {
/**
* @ param DataObject
*/
protected $record ;
/**
* @ param DataObject
*/
2012-09-19 12:07:46 +02:00
public function __construct ( $record ) {
2011-07-15 16:05:58 +02:00
$this -> record = $record ;
}
/**
* @ return String HTML , mostly a link - but can be more complex as well .
* For example , a " future state " item might show a date selector .
*/
2012-09-19 12:07:46 +02:00
public function getHTML () {}
2012-05-04 01:26:40 +02:00
/**
* @ return String
2012-11-15 02:05:04 +01:00
* Get the Title of an item
2012-05-04 01:26:40 +02:00
*/
2012-11-15 02:05:04 +01:00
public function getTitle () {}
2011-07-15 16:05:58 +02:00
2012-11-29 05:41:01 +01:00
/**
* Machine - friendly name .
*/
public function getName () {
return substr ( get_class ( $this ), strpos ( get_class ( $this ), '_' ) + 1 );
}
2011-07-21 20:00:48 +02:00
/**
* Optional link to a specific view of this record .
* Not all items are simple links , please use { @ link getHTML ()}
* to represent an item in markup unless you know what you ' re doing .
*
* @ return String
*/
2012-09-19 12:07:46 +02:00
public function getLink () {}
2011-07-21 20:00:48 +02:00
2011-07-15 16:05:58 +02:00
/**
* @ return String
*/
2012-09-19 12:07:46 +02:00
public function getMessage () {}
2011-07-15 16:05:58 +02:00
/**
* @ return DataObject
*/
2012-09-19 12:07:46 +02:00
public function getRecord () {
2011-07-15 16:05:58 +02:00
return $this -> record ;
}
/**
* @ return Int
*/
2012-09-19 12:07:46 +02:00
public function getPriority () {
2011-07-15 16:05:58 +02:00
return $this -> stat ( 'priority' );
}
/**
2011-07-21 20:00:48 +02:00
* As items might convey different record states like a " stage " or " live " table ,
* an item can be active ( showing the record in this state ) .
*
* @ return boolean
*/
2012-09-19 12:07:46 +02:00
public function isActive () {
2011-07-21 20:00:48 +02:00
return false ;
}
/**
* Filters items based on member permissions or other criteria ,
* such as if a state is generally available for the current record .
2011-07-15 16:05:58 +02:00
*
* @ param Member
* @ return Boolean
*/
2012-09-19 12:07:46 +02:00
public function canView ( $member = null ) {
2011-07-15 16:05:58 +02:00
return true ;
}
2013-01-25 11:35:48 +01:00
/**
* Counts as " archived " if the current record is a different version from both live and draft .
*
* @ return boolean
*/
public function isArchived () {
if ( ! $this -> record -> hasExtension ( 'Versioned' )) return false ;
if ( ! isset ( $this -> record -> _cached_isArchived )) {
$baseTable = ClassInfo :: baseDataClass ( $this -> record -> class );
$currentDraft = Versioned :: get_one_by_stage (
$baseTable ,
'Stage' ,
sprintf ( '"%s"."ID" = %d' , $baseTable , $this -> record -> ID )
);
$currentLive = Versioned :: get_one_by_stage (
$baseTable ,
'Live' ,
sprintf ( '"%s"."ID" = %d' , $baseTable , $this -> record -> ID )
);
$this -> record -> _cached_isArchived = (
( ! $currentDraft || ( $currentDraft && $this -> record -> Version != $currentDraft -> Version ))
&& ( ! $currentLive || ( $currentLive && $this -> record -> Version != $currentLive -> Version ))
);
2013-02-07 21:44:41 +01:00
}
2013-01-25 11:35:48 +01:00
return $this -> record -> _cached_isArchived ;
}
2011-07-15 16:05:58 +02:00
}
/**
* @ package cms
* @ subpackage content
*/
class SilverStripeNavigatorItem_CMSLink extends SilverStripeNavigatorItem {
2013-03-18 11:47:15 +01:00
/** @config */
private static $priority = 10 ;
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getHTML () {
2011-07-21 20:00:48 +02:00
return sprintf (
'<a href="%s">%s</a>' ,
$this -> record -> CMSEditLink (),
_t ( 'ContentController.CMS' , 'CMS' )
);
2011-07-15 16:05:58 +02:00
}
2012-11-15 02:05:04 +01:00
public function getTitle () {
2012-11-27 00:22:45 +01:00
return _t ( 'ContentController.CMS' , 'CMS' , 'Used in navigation. Should be a short label' );
2012-11-15 02:05:04 +01:00
}
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getLink () {
2011-07-21 20:00:48 +02:00
return $this -> record -> CMSEditLink ();
}
2012-09-19 12:07:46 +02:00
public function isActive () {
2013-02-01 19:16:19 +01:00
return ( Controller :: curr () instanceof LeftAndMain );
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function canView ( $member = null ) {
2013-01-09 21:44:52 +01:00
return (
2011-07-21 20:00:48 +02:00
// Don't show in CMS
2013-02-07 21:44:41 +01:00
! ( Controller :: curr () instanceof LeftAndMain )
2013-01-09 21:44:52 +01:00
// Don't follow redirects in preview, they break the CMS editing form
&& ! ( $this -> record instanceof RedirectorPage )
);
2011-07-15 16:05:58 +02:00
}
}
/**
* @ package cms
* @ subpackage content
*/
class SilverStripeNavigatorItem_StageLink extends SilverStripeNavigatorItem {
2013-03-18 11:47:15 +01:00
/** @config */
private static $priority = 20 ;
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getHTML () {
2011-07-21 20:00:48 +02:00
$draftPage = $this -> getDraftPage ();
if ( $draftPage ) {
$this -> recordLink = Controller :: join_links ( $draftPage -> AbsoluteLink (), " ?stage=Stage " );
2013-03-18 14:57:20 +01:00
return " <a " . ( $this -> isActive () ? 'class="current" ' : '' ) . " href= \" $this->recordLink\ " > " . _t('ContentController.DRAFTSITE', 'Draft Site') . " </ a > " ;
2011-07-15 16:05:58 +02:00
}
}
2012-05-04 01:26:40 +02:00
2012-11-15 02:05:04 +01:00
public function getTitle () {
2012-11-27 00:22:45 +01:00
return _t ( 'ContentController.DRAFT' , 'Draft' , 'Used for the Switch between draft and published view mode. Needs to be a short label' );
2012-05-04 01:26:40 +02:00
}
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getMessage () {
2011-07-21 20:00:48 +02:00
return " <div id= \" SilverStripeNavigatorMessage \" title= \" " . _t ( 'ContentControl.NOTEWONTBESHOWN' , 'Note: this message will not be shown to your visitors' ) . " \" > " . _t ( 'ContentController.DRAFTSITE' , 'Draft Site' ) . " </div> " ;
2011-07-15 16:05:58 +02:00
}
2012-09-19 12:07:46 +02:00
public function getLink () {
2013-01-25 11:35:48 +01:00
$date = Versioned :: current_archived_date ();
return Controller :: join_links (
$this -> record -> PreviewLink (),
'?stage=Stage' ,
$date ? '?archiveDate=' . $date : null
);
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function canView ( $member = null ) {
2013-01-09 21:44:52 +01:00
return (
$this -> record -> hasExtension ( 'Versioned' )
&& $this -> getDraftPage ()
// Don't follow redirects in preview, they break the CMS editing form
&& ! ( $this -> record instanceof RedirectorPage )
);
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function isActive () {
2011-07-21 20:00:48 +02:00
return (
Versioned :: current_stage () == 'Stage'
&& ! ( ClassInfo :: exists ( 'SiteTreeFutureState' ) && SiteTreeFutureState :: get_future_datetime ())
2013-01-25 11:35:48 +01:00
&& ! $this -> isArchived ()
2011-07-21 20:00:48 +02:00
);
}
protected function getDraftPage () {
$baseTable = ClassInfo :: baseDataClass ( $this -> record -> class );
return Versioned :: get_one_by_stage (
$baseTable ,
'Stage' ,
sprintf ( '"%s"."ID" = %d' , $baseTable , $this -> record -> ID )
);
2011-07-15 16:05:58 +02:00
}
}
/**
* @ package cms
* @ subpackage content
*/
class SilverStripeNavigatorItem_LiveLink extends SilverStripeNavigatorItem {
2013-03-18 11:47:15 +01:00
/** @config */
private static $priority = 30 ;
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getHTML () {
2011-07-21 20:00:48 +02:00
$livePage = $this -> getLivePage ();
if ( $livePage ) {
$this -> recordLink = Controller :: join_links ( $livePage -> AbsoluteLink (), " ?stage=Live " );
2013-03-18 14:57:20 +01:00
return " <a " . ( $this -> isActive () ? 'class="current" ' : '' ) . " href= \" $this->recordLink\ " > " . _t('ContentController.PUBLISHEDSITE', 'Published Site') . " </ a > " ;
2011-07-15 16:05:58 +02:00
}
}
2012-05-04 01:26:40 +02:00
2012-11-15 02:05:04 +01:00
public function getTitle () {
2012-11-27 00:22:45 +01:00
return _t ( 'ContentController.PUBLISHED' , 'Published' , 'Used for the Switch between draft and published view mode. Needs to be a short label' );
2012-05-04 01:26:40 +02:00
}
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getMessage () {
2011-07-21 20:00:48 +02:00
return " <div id= \" SilverStripeNavigatorMessage \" title= \" " . _t ( 'ContentControl.NOTEWONTBESHOWN' , 'Note: this message will not be shown to your visitors' ) . " \" > " . _t ( 'ContentController.PUBLISHEDSITE' , 'Published Site' ) . " </div> " ;
2011-07-15 16:05:58 +02:00
}
2012-09-19 12:07:46 +02:00
public function getLink () {
2013-01-14 12:06:34 +01:00
return Controller :: join_links ( $this -> record -> PreviewLink (), '?stage=Live' );
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function canView ( $member = null ) {
2013-01-09 21:44:52 +01:00
return (
$this -> record -> hasExtension ( 'Versioned' )
&& $this -> getLivePage ()
// Don't follow redirects in preview, they break the CMS editing form
&& ! ( $this -> record instanceof RedirectorPage )
);
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function isActive () {
2013-01-25 11:35:48 +01:00
return (
( ! Versioned :: current_stage () || Versioned :: current_stage () == 'Live' )
&& ! $this -> isArchived ()
);
2011-07-21 20:00:48 +02:00
}
protected function getLivePage () {
$baseTable = ClassInfo :: baseDataClass ( $this -> record -> class );
return Versioned :: get_one_by_stage (
$baseTable ,
'Live' ,
sprintf ( '"%s"."ID" = %d' , $baseTable , $this -> record -> ID )
);
2011-07-15 16:05:58 +02:00
}
}
/**
* @ package cms
* @ subpackage content
*/
class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem {
2013-03-18 11:47:15 +01:00
/** @config */
private static $priority = 40 ;
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getHTML () {
2011-07-21 20:00:48 +02:00
$this -> recordLink = $this -> record -> AbsoluteLink ();
2013-03-18 14:57:20 +01:00
return " <a class= \" ss-ui-button " . ( $this -> isActive () ? ' current' : '' ) . " \" href= \" $this->recordLink ?archiveDate= { $this -> record -> LastEdited } \" target= \" _blank \" > " . _t ( 'ContentController.ARCHIVEDSITE' , 'Preview version' ) . " </a> " ;
2011-07-15 16:05:58 +02:00
}
2012-11-15 02:05:04 +01:00
public function getTitle () {
2013-01-25 11:35:48 +01:00
return _t ( 'SilverStripeNavigator.ARCHIVED' , 'Archived' );
2012-11-15 02:05:04 +01:00
}
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getMessage () {
2011-10-31 00:15:07 +01:00
if ( $date = Versioned :: current_archived_date ()) {
2013-03-18 14:57:20 +01:00
$dateObj = DBField :: create_field ( 'Datetime' , $date );
2011-10-31 00:15:07 +01:00
return " <div id= \" SilverStripeNavigatorMessage \" title= \" " . _t ( 'ContentControl.NOTEWONTBESHOWN' , 'Note: this message will not be shown to your visitors' ) . " \" > " . _t ( 'ContentController.ARCHIVEDSITEFROM' , 'Archived site from' ) . " <br> " . $dateObj -> Nice () . " </div> " ;
}
2011-07-15 16:05:58 +02:00
}
2012-09-19 12:07:46 +02:00
public function getLink () {
2013-01-25 11:35:48 +01:00
return $this -> record -> PreviewLink () . '?archiveDate=' . urlencode ( $this -> record -> LastEdited );
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function canView ( $member = null ) {
2013-01-09 21:44:52 +01:00
return (
$this -> record -> hasExtension ( 'Versioned' )
&& $this -> isArchived ()
// Don't follow redirects in preview, they break the CMS editing form
&& ! ( $this -> record instanceof RedirectorPage )
);
2011-07-21 20:00:48 +02:00
}
2012-09-19 12:07:46 +02:00
public function isActive () {
2013-01-25 11:35:48 +01:00
return $this -> isArchived ();
2011-07-15 16:05:58 +02:00
}
}