PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/system/cms/modules/pages/controllers/pages.php

https://github.com/asalem/pyrocms
PHP | 362 lines | 213 code | 60 blank | 89 comment | 31 complexity | 51537aa32689e5c0920835f7401a5424 MD5 | raw file
Possible License(s): CC-BY-3.0, BSD-3-Clause, CC0-1.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, MIT
  1. <?php
  2. use Carbon\Carbon;
  3. use Pyro\Module\Pages\Model\Page;
  4. use Pyro\Module\Keywords\Model\Applied as AppliedKeywords;
  5. /**
  6. * The public controller for the Pages module.
  7. *
  8. * @author PyroCMS Dev Team
  9. * @package PyroCMS\Core\Modules\Pages\Controllers
  10. */
  11. class Pages extends Public_Controller
  12. {
  13. /**
  14. * Constructor method
  15. */
  16. public function __construct()
  17. {
  18. parent::__construct();
  19. // This basically keeps links to /home always pointing to
  20. // the actual homepage even when the default_controller is
  21. // changed
  22. // No page is mentioned and we are not using pages as default
  23. // (eg blog on homepage)
  24. if (!$this->uri->segment(1) and $this->router->default_controller != 'pages') {
  25. redirect('');
  26. }
  27. }
  28. /**
  29. * Catch all requests to this page in one mega-function.
  30. *
  31. * @param string $method The method to call.
  32. */
  33. public function _remap($method)
  34. {
  35. // This page has been routed to with pages/view/whatever
  36. if ($this->uri->rsegment(1, '') . '/' . $method === 'pages/view') {
  37. $url_segments = $this->uri->total_rsegments() > 0 ? array_slice($this->uri->rsegment_array(), 2) : null;
  38. } // not routed, so use the actual URI segments
  39. else {
  40. if (($url_segments = $this->uri->uri_string()) === 'favicon.ico') {
  41. $favicon = Asset::get_filepath_img('theme::favicon.ico');
  42. if (file_exists(FCPATH . $favicon) && is_file(FCPATH . $favicon)) {
  43. header('Content-type: image/x-icon');
  44. readfile(FCPATH . $favicon);
  45. } else {
  46. set_status_header(404);
  47. }
  48. }
  49. $url_segments = $this->uri->total_segments() > 0 ? $this->uri->segment_array() : null;
  50. }
  51. // If it has .rss on the end then parse the RSS feed
  52. $url_segments && preg_match('/.rss$/', end($url_segments))
  53. ? $this->_rss($url_segments)
  54. : $this->_page($url_segments);
  55. }
  56. /**
  57. * Page method
  58. *
  59. * @param array $url_segments The URL segments.
  60. */
  61. public function _page($url_segments)
  62. {
  63. // If we are on the development environment,
  64. // we should get rid of the cache. That ways we can just
  65. // make updates to the page type files and see the
  66. // results immediately.
  67. if (ENVIRONMENT === PYRO_DEVELOPMENT) {
  68. $this->cache->forget('Page');
  69. }
  70. // GET THE PAGE ALREADY. In the event of this being the home page $url_segments will be null
  71. // $page = $this->cache->method('Page::findByUri', array($url_segments, true));
  72. $page = Page::findByUri($url_segments, true);
  73. // If page is missing or not live (and the user does not have permission) show 404
  74. if (!$page or ($page->status === 'draft' and !ci()->current_user->hasAccess(array('put_live', 'edit_live')))) {
  75. // Load the '404' page. If the actual 404 page is missing (oh the irony) bitch and quit to prevent an infinite loop.
  76. // if ( ! ($page = $this->cache->method('page_m', 'get_by_uri', array('404'))))
  77. if (!($page = Page::findByUri(404))) {
  78. show_error(
  79. 'The page you are trying to view does not exist and it also appears as if the 404 page has been deleted.'
  80. );
  81. }
  82. }
  83. // the home page won't have a base uri
  84. isset($page->base_uri) OR $page->base_uri = $url_segments;
  85. // If this is a homepage, do not show the slug in the URL
  86. if ($page->is_home and $url_segments) {
  87. redirect('', 'location', 301);
  88. }
  89. // If the page is missing, set the 404 status header
  90. if ($page->slug == 404) {
  91. $this->output->set_status_header(404);
  92. } // Nope, it is a page, but do they have access?
  93. elseif ($restrictedIds = $page->entry->restricted_to->lists('id')) {
  94. $groupIds = isset($this->current_user->id) ? $this->current_user->groups->lists('id') : array();
  95. // Get the similarities between groups / restriced group IDs
  96. $matches = array_intersect(
  97. $restrictedIds,
  98. $groupIds
  99. );
  100. // Are they logged in and an admin or a member of the correct group?
  101. if (!$groupIds or (!in_array(1, $groupIds) and empty($matches))) {
  102. // send them to login but bring them back when they're done
  103. if ($url_segments) {
  104. $this->session->set_userdata('redirect_to', $redirect_to = implode('/', $url_segments));
  105. }
  106. redirect('users/login');
  107. }
  108. }
  109. // We want to use the valid uri from here on. Don't worry about segments passed by Streams or
  110. // similar. Also we don't worry about breadcrumbs for 404
  111. if ($url_segments = explode('/', $page->base_uri) and count($url_segments) > 1) {
  112. // we dont care about the last one
  113. array_pop($url_segments);
  114. $parents = $breadcrumb_segments = array();
  115. // TODO Cache me! Phil delete it
  116. foreach ($url_segments as $segment) {
  117. $breadcrumb_segments[] = $segment;
  118. $parents[] = Page::findByUri($breadcrumb_segments, true);
  119. }
  120. foreach ($parents as $parent_page) {
  121. $this->template->set_breadcrumb($parent_page->title, $parent_page->uri);
  122. }
  123. }
  124. // If this page has an RSS feed, show it
  125. if ($page->rss_enabled) {
  126. $this->template->append_metadata(
  127. '<link rel="alternate" type="application/rss+xml" title="' . $page->meta_title . '" href="' . site_url(
  128. uri_string() . '.rss'
  129. ) . '" />'
  130. );
  131. }
  132. // Set pages layout files in your theme folder
  133. if ($this->template->layout_exists($page->uri . '.html')) {
  134. $this->template->set_layout($page->uri . '.html');
  135. }
  136. // If a Page Type has a Theme Layout that exists, use it
  137. if (!empty($page->type->theme_layout) and $this->template->layout_exists($page->type->theme_layout)
  138. // But Allow that you use layout files of you theme folder without override the defined by you in your control panel
  139. and ($this->template->layout_is('default.html') or $page->type->theme_layout !== 'default.html')
  140. ) {
  141. $this->template->set_layout($page->type->theme_layout);
  142. }
  143. // ---------------------------------
  144. // Metadata
  145. // ---------------------------------
  146. $page->meta_title = $this->parser->parse_string(
  147. $page->meta_title,
  148. array('current_user' => ci()->current_user),
  149. true
  150. );
  151. $page->meta_description = $this->parser->parse_string(
  152. $page->meta_description,
  153. array('current_user' => ci()->current_user),
  154. true
  155. );
  156. // First we need to figure out our metadata. If we have meta for our page,
  157. // that overrides the meta from the page layout.
  158. $meta_title = ($page->meta_title ? : $page->type->meta_title);
  159. $meta_description = ($page->meta_description ? : $page->type->meta_description);
  160. $meta_keywords = '';
  161. $keyword_hash = $page->meta_keywords ? : $page->type->meta_keywords;
  162. if ($keyword_hash) {
  163. $meta_keywords = ''; //implode(', ', AppliedKeywords::getNamesByHash($page->meta_keywords)->lists('name'));
  164. $page->meta_keywords = $meta_keywords;
  165. }
  166. $meta_robots = $page->meta_robots_no_index ? 'noindex' : 'index';
  167. $meta_robots .= $page->meta_robots_no_follow ? ',nofollow' : ',follow';
  168. // They will be parsed later, when they are set for the template library.
  169. // Not got a meta title? Use slogan for homepage or the normal page title for other pages
  170. if (!$meta_title) {
  171. $meta_title = $page->is_home ? Settings::get('site_slogan') : $page->title;
  172. }
  173. // Set the title, keywords, description, and breadcrumbs.
  174. $this->template->title($this->parser->parse_string($meta_title, $page, true))
  175. ->set_metadata('keywords', $this->parser->parse_string($meta_keywords, $page, true))
  176. ->set_metadata('robots', $meta_robots)
  177. ->set_metadata('description', $this->parser->parse_string($meta_description, $page, true))
  178. ->set_breadcrumb($page->title);
  179. // Parse the CSS so we can use tags like {{ asset:inline_css }}
  180. // #foo {color: red} {{ /asset:inline_css }}
  181. // to output css via the {{ asset:render_inline_css }} tag. This is most useful for JS
  182. $css = $this->parser->parse_string($page->type->css . $page->css, $this, true);
  183. // there may not be any css (for sure after parsing Lex tags)
  184. if ($css) {
  185. $this->template->append_metadata(
  186. '
  187. <style type="text/css">
  188. ' . $css . '
  189. </style>',
  190. 'late_header'
  191. );
  192. }
  193. $js = $this->parser->parse_string($page->type->js . $page->js, $this, true);
  194. // Add our page and page layout JS
  195. if ($js) {
  196. $this->template->append_metadata(
  197. '
  198. <script type="text/javascript">
  199. ' . $js . '
  200. </script>'
  201. );
  202. }
  203. // If comments are enabled, go fetch them all
  204. if (Settings::get('enable_comments')) {
  205. // Load Comments so we can work out what to do with them
  206. $this->load->library(
  207. 'comments/comments',
  208. array(
  209. 'entry_id' => $page->id,
  210. 'entry_title' => $page->title,
  211. 'module' => 'pages',
  212. 'singular' => 'pages:page',
  213. 'plural' => 'pages:pages',
  214. )
  215. );
  216. }
  217. // Get our stream.
  218. //$this->load->driver('Streams');
  219. //$stream = $this->streams_m->get_stream($page->type->stream_id);
  220. // We are going to pre-build this data so we have the data
  221. // available to the template plugin (since we are pre-parsing our views).
  222. $template = $this->template->build_template_data();
  223. // Parse our view file. The view file is nothing
  224. // more than an echo of $page->layout->body and the
  225. // comments after it (if the page has comments).
  226. $attributes = $page->getAttributes();
  227. $attributes = array_merge(
  228. $attributes,
  229. ($page->entry and !$_POST) ? $page->entry->getPresenter('plugin')->toArray() : array()
  230. );
  231. $html = $this->template->load_view('pages/page', array_merge(array('page' => $page), $attributes), false);
  232. $view = $this->parser->parse_string(
  233. $html,
  234. $page,
  235. true,
  236. false,
  237. array(
  238. 'stream' => $page->entry ? $page->entry->getStreamSlug() : null,
  239. 'namespace' => $page->entry ? $page->entry->getStreamNamespace() : null,
  240. 'id_name' => 'entry_id'
  241. )
  242. );
  243. if ($page->slug == '404') {
  244. log_message('error', 'Page Missing: ' . $this->uri->uri_string());
  245. // things behave a little differently when called by MX from MY_Exceptions' show_404()
  246. exit($this->template->build($view, array('page' => $page), false, false, true, $template));
  247. }
  248. $this->template->build($view, array('page' => $page), false, false, true, $template);
  249. }
  250. /**
  251. * RSS method
  252. *
  253. * @param array $url_segments The URL segments.
  254. * @return null|void
  255. */
  256. public function _rss($url_segments)
  257. {
  258. // Remove the .rss suffix
  259. $url_segments += array(preg_replace('/.rss$/', '', array_pop($url_segments)));
  260. // Fetch this page from the database via cache
  261. // TODO Cache me, Phil delete it
  262. $page = Page::findByUri($url_segments, true);
  263. // We will need to know if we should include draft pages in the feed later on too, so save it.
  264. $include_draft = !empty($this->current_user) AND $this->current_user->group !== 'admin';
  265. // If page is missing or not live (and not an admin) show 404
  266. if (empty($page) or ($page->status == 'draft' and $include_draft) or !$page->rss_enabled) {
  267. // Will try the page then try 404 eventually
  268. $this->_page('404');
  269. return;
  270. }
  271. // If the feed should only show live pages
  272. $status = $include_draft ? null : 'live';
  273. // Hit the query through the cache.
  274. $children = $this->cache->method('Page', 'findByIdAndStatus', array($id, $status));
  275. $data = array(
  276. 'rss' => array(
  277. 'title' => ($page->meta_title ? : $page->title) . ' | ' . Settings::get('site_name'),
  278. 'description' => $page->meta_description,
  279. 'link' => site_url($url_segments),
  280. 'creator_email' => Settings::get('contact_email'),
  281. 'items' => array(),
  282. ),
  283. );
  284. if (!empty($children)) {
  285. $this->load->helper('xml');
  286. foreach ($children as &$row) {
  287. $row->link = $row->uri ? : $row->slug;
  288. $data['rss']['items'][] = array(
  289. //'author' => $row->author,
  290. 'title' => xml_convert($row->title),
  291. 'link' => $row->link,
  292. 'guid' => $row->link,
  293. 'description' => $row->meta_description,
  294. 'date' => Carbon::parse($row->created_at)->toRSSString(),
  295. );
  296. }
  297. }
  298. // We are outputing RSS/Atom here... let them know.
  299. $this->output->set_header('Content-Type: application/rss+xml');
  300. $this->load->view('rss', $data);
  301. }
  302. }