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 .
2016-08-05 06:46:35 +02:00
*
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 .
2016-08-05 06:46:35 +02:00
*
2011-07-15 16:05:58 +02:00
* @ package cms
* @ subpackage content
*/
2011-07-21 20:00:48 +02:00
class SilverStripeNavigator extends ViewableData {
2011-07-15 16:05:58 +02:00
/**
2016-07-25 15:34:45 +02:00
* @ var DataObject | CMSPreviewable
2011-07-15 16:05:58 +02:00
*/
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 ) {
2016-07-25 15:34:45 +02:00
parent :: __construct ();
if ( ! ( $record instanceof CMSPreviewable )) {
2014-11-03 02:09:27 +01:00
throw new InvalidArgumentException ( sprintf (
'SilverStripeNavigator: Record of type %s doesn\'t implement CMSPreviewable' ,
get_class ( $record )
));
2011-07-21 20:00:48 +02:00
}
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 ++ ;
2016-07-25 15:34:45 +02:00
/** @var SilverStripeNavigatorItem $item */
2011-07-15 16:05:58 +02:00
$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
2016-07-25 15:34:45 +02:00
* @ return array template data
2011-07-15 16:05:58 +02:00
*/
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 ()} .
2016-08-05 06:46:35 +02:00
*
2011-07-15 16:05:58 +02:00
* @ package cms
* @ subpackage content
*/
class SilverStripeNavigatorItem extends ViewableData {
/**
2016-07-25 15:34:45 +02:00
* @ var DataObject | CMSPreviewable
2011-07-15 16:05:58 +02:00
*/
protected $record ;
/**
2016-07-25 15:34:45 +02:00
* @ param DataObject $record
2011-07-15 16:05:58 +02:00
*/
2012-09-19 12:07:46 +02:00
public function __construct ( $record ) {
2016-07-25 15:34:45 +02:00
parent :: __construct ();
2011-07-15 16:05:58 +02:00
$this -> record = $record ;
}
/**
2015-09-28 11:31:31 +02:00
* @ return string HTML , mostly a link - but can be more complex as well .
2011-07-15 16:05:58 +02:00
* 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
/**
2015-09-28 11:31:31 +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 .
2016-08-05 06:46:35 +02:00
*
2015-09-28 11:31:31 +02:00
* @ return string
2011-07-21 20:00:48 +02:00
*/
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
/**
2015-09-28 11:31:31 +02:00
* @ return string
2011-07-15 16:05:58 +02:00
*/
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 ;
2016-08-05 06:46:35 +02:00
}
2011-07-15 16:05:58 +02:00
/**
2015-09-28 11:31:31 +02:00
* @ return int
2011-07-15 16:05:58 +02:00
*/
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 ) .
2016-08-05 06:46:35 +02:00
*
2011-07-21 20:00:48 +02:00
* @ 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 .
2016-08-05 06:46:35 +02:00
*
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 .
2016-08-05 06:46:35 +02:00
*
2013-01-25 11:35:48 +01:00
* @ return boolean
*/
public function isArchived () {
2017-05-04 05:05:25 +02:00
if ( ! Object :: has_extension ( $this -> record -> ClassName , 'Versioned' )) return false ;
2013-01-25 11:35:48 +01:00
if ( ! isset ( $this -> record -> _cached_isArchived )) {
$baseTable = ClassInfo :: baseDataClass ( $this -> record -> class );
2013-06-21 00:45:33 +02:00
$currentDraft = Versioned :: get_one_by_stage ( $baseTable , 'Stage' , array (
" \" $baseTable\ " . \ " ID \" " => $this -> record -> ID
));
$currentLive = Versioned :: get_one_by_stage ( $baseTable , 'Live' , array (
" \" $baseTable\ " . \ " ID \" " => $this -> record -> ID
));
2013-01-25 11:35:48 +01:00
$this -> record -> _cached_isArchived = (
2016-08-05 06:46:35 +02:00
( ! $currentDraft || ( $currentDraft && $this -> record -> Version != $currentDraft -> Version ))
2013-01-25 11:35:48 +01:00
&& ( ! $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 ();
2016-07-25 15:34:45 +02:00
if ( ! $draftPage ) {
return null ;
2011-07-15 16:05:58 +02:00
}
2016-07-25 15:34:45 +02:00
$linkClass = $this -> isActive () ? 'class="current" ' : '' ;
$linkTitle = _t ( 'ContentController.DRAFTSITE' , 'Draft Site' );
$recordLink = Convert :: raw2att ( Controller :: join_links ( $draftPage -> AbsoluteLink (), " ?stage=Stage " ));
return " <a { $linkClass } href= \" $recordLink\ " > $linkTitle </ 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 (
2016-08-05 06:46:35 +02:00
$this -> record -> PreviewLink (),
2013-01-25 11:35:48 +01:00
'?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 (
2017-05-04 05:05:25 +02:00
Object :: has_extension ( $this -> record -> ClassName , 'Versioned' )
2013-01-09 21:44:52 +01:00
&& $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 (
2016-08-05 06:46:35 +02:00
Versioned :: current_stage () == 'Stage'
2011-07-21 20:00:48 +02:00
&& ! ( 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 );
2013-06-21 00:45:33 +02:00
return Versioned :: get_one_by_stage ( $baseTable , 'Stage' , array (
" \" $baseTable\ " . \ " ID \" " => $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 ();
2016-07-25 15:34:45 +02:00
if ( ! $livePage ) {
return null ;
2011-07-15 16:05:58 +02:00
}
2016-07-25 15:34:45 +02:00
$linkClass = $this -> isActive () ? 'class="current" ' : '' ;
$linkTitle = _t ( 'ContentController.PUBLISHEDSITE' , 'Published Site' );
$recordLink = Convert :: raw2att ( Controller :: join_links ( $livePage -> AbsoluteLink (), " ?stage=Live " ));
return " <a { $linkClass } href= \" $recordLink\ " > $linkTitle </ 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 (
2017-05-04 05:05:25 +02:00
Object :: has_extension ( $this -> record -> ClassName , 'Versioned' )
2013-01-09 21:44:52 +01:00
&& $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 );
2013-06-21 00:45:33 +02:00
return Versioned :: get_one_by_stage ( $baseTable , 'Live' , array (
" \" $baseTable\ " . \ " ID \" " => $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 () {
2016-07-25 15:34:45 +02:00
$linkClass = $this -> isActive () ? 'ss-ui-button current' : 'ss-ui-button' ;
$linkTitle = _t ( 'ContentController.ARCHIVEDSITE' , 'Preview version' );
$recordLink = Convert :: raw2att ( Controller :: join_links (
$this -> record -> AbsoluteLink (),
'?archiveDate=' . urlencode ( $this -> record -> LastEdited )
));
return " <a class= \" { $linkClass } \" href= \" $recordLink\ " target = \ " _blank \" > $linkTitle </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
2016-08-05 06:46:35 +02:00
public function getMessage () {
2016-07-25 15:34:45 +02:00
$date = Versioned :: current_archived_date ();
if ( empty ( $date )) {
return null ;
2011-10-31 00:15:07 +01:00
}
2016-07-25 15:34:45 +02:00
/** @var SS_Datetime $dateObj */
2013-03-18 14:57:20 +01:00
$dateObj = DBField :: create_field ( 'Datetime' , $date );
2016-07-25 15:34:45 +02:00
$title = _t ( 'ContentControl.NOTEWONTBESHOWN' , 'Note: this message will not be shown to your visitors' );
return " <div id= \" SilverStripeNavigatorMessage \" title= \" { $title } \" > "
. _t ( 'ContentController.ARCHIVEDSITEFROM' , 'Archived site from' )
. " <br /> " . $dateObj -> Nice () . " </div> " ;
2011-10-31 00:15:07 +01:00
}
2011-07-15 16:05:58 +02:00
2012-09-19 12:07:46 +02:00
public function getLink () {
2016-07-25 15:34:45 +02:00
return Controller :: join_links (
$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 (
2017-05-04 05:05:25 +02:00
Object :: has_extension ( $this -> record -> ClassName , 'Versioned' )
2013-01-09 21:44:52 +01:00
&& $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
}
}