PageRenderTime 141ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/code/controller/SilverStripeNavigator.php

https://github.com/icecaster/silverstripe-cms
PHP | 344 lines | 189 code | 53 blank | 102 comment | 24 complexity | c8340ae68d9b4fe2fb9775bc902743d7 MD5 | raw file
  1. <?php
  2. /**
  3. * Utility class representing links to different views of a record
  4. * for CMS authors, usually for {@link SiteTree} objects with "stage" and "live" links.
  5. * Useful both in the CMS and alongside the page template (for logged in authors).
  6. * The class can be used for any {@link DataObject} subclass implementing the {@link CMSPreviewable} interface.
  7. *
  8. * New item types can be defined by extending the {@link SilverStripeNavigatorItem} class,
  9. * for example the "cmsworkflow" module defines a new "future state" item with a date selector
  10. * to view embargoed data at a future point in time. So the item doesn't always have to be a simple link.
  11. *
  12. * @package cms
  13. * @subpackage content
  14. */
  15. class SilverStripeNavigator extends ViewableData {
  16. /**
  17. * @var DataObject
  18. */
  19. protected $record;
  20. /**
  21. * @param DataObject
  22. */
  23. function __construct($record) {
  24. if(!in_array('CMSPreviewable', class_implements($record))) {
  25. throw new InvalidArgumentException('SilverStripeNavigator: Record of type %s doesn\'t implement CMSPreviewable', get_class($record));
  26. }
  27. $this->record = $record;
  28. }
  29. /**
  30. * @return DataObjectSet of SilverStripeNavigatorItem
  31. */
  32. function getItems() {
  33. $items = array();
  34. $classes = ClassInfo::subclassesFor('SilverStripeNavigatorItem');
  35. array_shift($classes);
  36. // Sort menu items according to priority
  37. $i = 0;
  38. foreach($classes as $class) {
  39. // Skip base class
  40. if($class == 'SilverStripeNavigatorItem') continue;
  41. $i++;
  42. $item = new $class($this->record);
  43. if(!$item->canView()) continue;
  44. // This funny litle formula ensures that the first item added with the same priority will be left-most.
  45. $priority = $item->getPriority() * 100 - 1;
  46. // Ensure that we can have duplicates with the same (default) priority
  47. while(isset($items[$priority])) $priority++;
  48. $items[$priority] = $item;
  49. }
  50. ksort($items);
  51. return new DataObjectSet($items);
  52. }
  53. /**
  54. * @return DataObject
  55. */
  56. function getRecord() {
  57. return $this->record;
  58. }
  59. /**
  60. * @param DataObject $record
  61. * @return Array template data
  62. */
  63. static function get_for_record($record) {
  64. $html = '';
  65. $message = '';
  66. $navigator = new SilverStripeNavigator($record);
  67. $items = $navigator->getItems();
  68. foreach($items as $item) {
  69. $text = $item->getHTML();
  70. if($text) $html .= $text;
  71. $newMessage = $item->getMessage();
  72. if($newMessage) $message = $newMessage;
  73. }
  74. return array(
  75. 'items' => $html,
  76. 'message' => $message
  77. );
  78. }
  79. }
  80. /**
  81. * Navigator items are links that appear in the $SilverStripeNavigator bar.
  82. * To add an item, extend this class - it will be automatically picked up.
  83. * When instanciating items manually, please ensure to call {@link canView()}.
  84. *
  85. * @package cms
  86. * @subpackage content
  87. */
  88. class SilverStripeNavigatorItem extends ViewableData {
  89. /**
  90. * @param DataObject
  91. */
  92. protected $record;
  93. /**
  94. * @param DataObject
  95. */
  96. function __construct($record) {
  97. $this->record = $record;
  98. }
  99. /**
  100. * @return String HTML, mostly a link - but can be more complex as well.
  101. * For example, a "future state" item might show a date selector.
  102. */
  103. function getHTML() {}
  104. /**
  105. * Optional link to a specific view of this record.
  106. * Not all items are simple links, please use {@link getHTML()}
  107. * to represent an item in markup unless you know what you're doing.
  108. *
  109. * @return String
  110. */
  111. function getLink() {}
  112. /**
  113. * @return String
  114. */
  115. function getMessage() {}
  116. /**
  117. * @return DataObject
  118. */
  119. function getRecord() {
  120. return $this->record;
  121. }
  122. /**
  123. * @return Int
  124. */
  125. function getPriority() {
  126. return $this->stat('priority');
  127. }
  128. /**
  129. * As items might convey different record states like a "stage" or "live" table,
  130. * an item can be active (showing the record in this state).
  131. *
  132. * @return boolean
  133. */
  134. function isActive() {
  135. return false;
  136. }
  137. /**
  138. * Filters items based on member permissions or other criteria,
  139. * such as if a state is generally available for the current record.
  140. *
  141. * @param Member
  142. * @return Boolean
  143. */
  144. function canView($member = null) {
  145. return true;
  146. }
  147. }
  148. /**
  149. * @package cms
  150. * @subpackage content
  151. */
  152. class SilverStripeNavigatorItem_CMSLink extends SilverStripeNavigatorItem {
  153. static $priority = 10;
  154. function getHTML() {
  155. return sprintf(
  156. '<a href="%s">%s</a>',
  157. $this->record->CMSEditLink(),
  158. _t('ContentController.CMS', 'CMS')
  159. );
  160. }
  161. function getLink() {
  162. return $this->record->CMSEditLink();
  163. }
  164. function isActive() {
  165. return (Controller::curr() instanceof CMSMain);
  166. }
  167. function canView() {
  168. // Don't show in CMS
  169. return !(Controller::curr() instanceof CMSMain);
  170. }
  171. }
  172. /**
  173. * @package cms
  174. * @subpackage content
  175. */
  176. class SilverStripeNavigatorItem_StageLink extends SilverStripeNavigatorItem {
  177. static $priority = 20;
  178. function getHTML() {
  179. $draftPage = $this->getDraftPage();
  180. if($draftPage) {
  181. $this->recordLink = Controller::join_links($draftPage->AbsoluteLink(), "?stage=Stage");
  182. return "<a href=\"$this->recordLink\">". _t('ContentController.DRAFTSITE', 'Draft Site') ."</a>";
  183. }
  184. }
  185. function getMessage() {
  186. return "<div id=\"SilverStripeNavigatorMessage\" title=\"". _t('ContentControl.NOTEWONTBESHOWN', 'Note: this message will not be shown to your visitors') ."\">". _t('ContentController.DRAFTSITE', 'Draft Site') ."</div>";
  187. }
  188. function getLink() {
  189. return Controller::join_links($this->record->AbsoluteLink(), '?stage=Stage');
  190. }
  191. function canView() {
  192. return ($this->record->hasExtension('Versioned') && $this->getDraftPage());
  193. }
  194. function isActive() {
  195. return (
  196. Versioned::current_stage() == 'Stage'
  197. && !(ClassInfo::exists('SiteTreeFutureState') && SiteTreeFutureState::get_future_datetime())
  198. );
  199. }
  200. protected function getDraftPage() {
  201. $baseTable = ClassInfo::baseDataClass($this->record->class);
  202. return Versioned::get_one_by_stage(
  203. $baseTable,
  204. 'Stage',
  205. sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID)
  206. );
  207. }
  208. }
  209. /**
  210. * @package cms
  211. * @subpackage content
  212. */
  213. class SilverStripeNavigatorItem_LiveLink extends SilverStripeNavigatorItem {
  214. static $priority = 30;
  215. function getHTML() {
  216. $livePage = $this->getLivePage();
  217. if($livePage) {
  218. $this->recordLink = Controller::join_links($livePage->AbsoluteLink(), "?stage=Live");
  219. return "<a href=\"$this->recordLink\">". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."</a>";
  220. }
  221. }
  222. function getMessage() {
  223. return "<div id=\"SilverStripeNavigatorMessage\" title=\"". _t('ContentControl.NOTEWONTBESHOWN', 'Note: this message will not be shown to your visitors') ."\">". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."</div>";
  224. }
  225. function getLink() {
  226. return Controller::join_links($this->record->AbsoluteLink(), '?stage=Live');
  227. }
  228. function canView() {
  229. return ($this->record->hasExtension('Versioned') && $this->getLivePage());
  230. }
  231. function isActive() {
  232. return (!Versioned::current_stage() || Versioned::current_stage() == 'Live');
  233. }
  234. protected function getLivePage() {
  235. $baseTable = ClassInfo::baseDataClass($this->record->class);
  236. return Versioned::get_one_by_stage(
  237. $baseTable,
  238. 'Live',
  239. sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID)
  240. );
  241. }
  242. }
  243. /**
  244. * @package cms
  245. * @subpackage content
  246. */
  247. class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem {
  248. static $priority = 40;
  249. function getHTML() {
  250. $this->recordLink = $this->record->AbsoluteLink();
  251. return "<a href=\"$this->recordLink?archiveDate={$this->record->LastEdited}\" target=\"_blank\">". _t('ContentController.ARCHIVEDSITE', 'Archived Site') ."</a>";
  252. }
  253. function getMessage() {
  254. $dateObj = Object::create('Datetime');
  255. $dateObj->setValue($date);
  256. 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>";
  257. }
  258. function getLink() {
  259. return $this->record->AbsoluteLink() . '?archiveDate=' . $date;
  260. }
  261. function canView() {
  262. return ($this->record->hasExtension('Versioned') && $this->isArchived());
  263. }
  264. function isActive() {
  265. return (Versioned::current_archived_date());
  266. }
  267. /**
  268. * Counts as "archived" if the current record is a different version from both live and draft.
  269. *
  270. * @return boolean
  271. */
  272. function isArchived() {
  273. if(!$this->record->hasExtension('Versioned')) return false;
  274. $baseTable = ClassInfo::baseDataClass($this->record->class);
  275. $currentDraft = Versioned::get_one_by_stage(
  276. $baseTable,
  277. 'Stage',
  278. sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID)
  279. );
  280. $currentLive = Versioned::get_one_by_stage(
  281. $baseTable,
  282. 'Live',
  283. sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID)
  284. );
  285. return (
  286. (!$currentDraft || ($currentDraft && $this->record->Version != $currentDraft->Version))
  287. && (!$currentLive || ($currentLive && $this->record->Version != $currentLive->Version))
  288. );
  289. }
  290. }
  291. ?>