PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/frontend/modules/search/actions/index.php

http://github.com/forkcms/forkcms
PHP | 290 lines | 118 code | 49 blank | 123 comment | 25 complexity | 852774542f9a5615f7ca48f3e58e51b2 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, MIT, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of Fork CMS.
  4. *
  5. * For the full copyright and license information, please view the license
  6. * file that was distributed with this source code.
  7. */
  8. /**
  9. * This action will display a form to search
  10. *
  11. * @author Matthias Mullie <matthias@mullie.eu>
  12. */
  13. class FrontendSearchIndex extends FrontendBaseBlock
  14. {
  15. /**
  16. * Name of the cachefile
  17. *
  18. * @var string
  19. */
  20. private $cacheFile;
  21. /**
  22. * The items
  23. *
  24. * @var array
  25. */
  26. private $items;
  27. /**
  28. * Limit of data to fetch
  29. *
  30. * @var int
  31. */
  32. private $limit;
  33. /**
  34. * Offset of data to fetch
  35. *
  36. * @var int
  37. */
  38. private $offset;
  39. /**
  40. * The pagination array
  41. * It will hold all needed parameters, some of them need initialization.
  42. *
  43. * @var array
  44. */
  45. protected $pagination = array('limit' => 20, 'offset' => 0, 'requested_page' => 1, 'num_items' => null, 'num_pages' => null);
  46. /**
  47. * The requested page
  48. *
  49. * @var int
  50. */
  51. private $requestedPage;
  52. /**
  53. * The search term
  54. *
  55. * @var string
  56. */
  57. private $term = '';
  58. /**
  59. * Search statistics
  60. *
  61. * @var array
  62. */
  63. private $statistics;
  64. /**
  65. * Display
  66. */
  67. private function display()
  68. {
  69. // set variables
  70. $this->requestedPage = $this->URL->getParameter('page', 'int', 1);
  71. $this->limit = FrontendModel::getModuleSetting('search', 'overview_num_items', 20);
  72. $this->offset = ($this->requestedPage * $this->limit) - $this->limit;
  73. $this->cacheFile = FRONTEND_CACHE_PATH . '/' . $this->getModule() . '/' . FRONTEND_LANGUAGE . '_' . md5($this->term) . '_' . $this->offset . '_' . $this->limit . '.php';
  74. // load the cached data
  75. if(!$this->getCachedData())
  76. {
  77. // ... or load the real data
  78. $this->getRealData();
  79. }
  80. // parse
  81. $this->parse();
  82. }
  83. /**
  84. * Execute the extra
  85. */
  86. public function execute()
  87. {
  88. parent::execute();
  89. $this->loadTemplate();
  90. $this->loadForm();
  91. $this->validateForm();
  92. $this->display();
  93. $this->saveStatistics();
  94. }
  95. /**
  96. * Load the cached data
  97. *
  98. * @return bool
  99. */
  100. private function getCachedData()
  101. {
  102. // no search term = no search
  103. if(!$this->term) return false;
  104. // debug mode = no cache
  105. if(SPOON_DEBUG) return false;
  106. // check if cachefile exists
  107. if(!SpoonFile::exists($this->cacheFile)) return false;
  108. // get cachefile modification time
  109. $cacheInfo = @filemtime($this->cacheFile);
  110. // check if cache file is recent enough (1 hour)
  111. if(!$cacheInfo || $cacheInfo < strtotime('-1 hour')) return false;
  112. // include cache file
  113. require_once $this->cacheFile;
  114. // set info (received from cache)
  115. $this->pagination = $pagination;
  116. $this->items = $items;
  117. return true;
  118. }
  119. /**
  120. * Load the data
  121. */
  122. private function getRealData()
  123. {
  124. // no search term = no search
  125. if(!$this->term) return;
  126. // set url
  127. $this->pagination['url'] = FrontendNavigation::getURLForBlock('search') . '?form=search&q=' . $this->term;
  128. // populate calculated fields in pagination
  129. $this->pagination['limit'] = $this->limit;
  130. $this->pagination['offset'] = $this->offset;
  131. $this->pagination['requested_page'] = $this->requestedPage;
  132. // get items
  133. $this->items = FrontendSearchModel::search($this->term, $this->pagination['limit'], $this->pagination['offset']);
  134. // populate count fields in pagination
  135. // this is done after actual search because some items might be activated/deactivated (getTotal only does rough checking)
  136. $this->pagination['num_items'] = FrontendSearchModel::getTotal($this->term);
  137. $this->pagination['num_pages'] = (int) ceil($this->pagination['num_items'] / $this->pagination['limit']);
  138. // num pages is always equal to at least 1
  139. if($this->pagination['num_pages'] == 0) $this->pagination['num_pages'] = 1;
  140. // redirect if the request page doesn't exist
  141. if($this->requestedPage > $this->pagination['num_pages'] || $this->requestedPage < 1) $this->redirect(FrontendNavigation::getURL(404));
  142. // debug mode = no cache
  143. if(!SPOON_DEBUG)
  144. {
  145. // set cache content
  146. SpoonFile::setContent($this->cacheFile, "<?php\n" . '$pagination = ' . var_export($this->pagination, true) . ";\n" . '$items = ' . var_export($this->items, true) . ";\n?>");
  147. }
  148. }
  149. /**
  150. * Load the form
  151. */
  152. private function loadForm()
  153. {
  154. // create form
  155. $this->frm = new FrontendForm('search', null, 'get', null, false);
  156. // could also have been submitted by our widget
  157. if(!SpoonFilter::getGetValue('q', null, '')) $_GET['q'] = SpoonFilter::getGetValue('q_widget', null, '');
  158. // create elements
  159. $this->frm->addText('q', null, 255, 'inputText liveSuggest autoComplete', 'inputTextError liveSuggest autoComplete');
  160. // since we know the term just here we should set the canonical url here
  161. $canonicalUrl = SITE_URL . FrontendNavigation::getURLForBlock('search');
  162. if(isset($_GET['q']) && $_GET['q'] != '') $canonicalUrl .= '?q=' . $_GET['q'];
  163. $this->header->setCanonicalUrl($canonicalUrl);
  164. }
  165. /**
  166. * Parse the data into the template
  167. */
  168. private function parse()
  169. {
  170. // parse the form
  171. $this->frm->parse($this->tpl);
  172. // no search term = no search
  173. if(!$this->term) return;
  174. // loop items
  175. foreach($this->items as &$item)
  176. {
  177. // full url is set?
  178. if(!isset($item['full_url'])) continue;
  179. // build utm array
  180. $utm['utm_source'] = SpoonFilter::urlise(FrontendModel::getModuleSetting('core', 'site_title_' . FRONTEND_LANGUAGE, SITE_DEFAULT_TITLE));
  181. $utm['utm_medium'] = 'fork-search';
  182. $utm['utm_term'] = $this->term;
  183. // get parameters in url already
  184. if(strpos($item['full_url'], '?') !== false) $glue = '&amp;';
  185. else $glue = '?';
  186. // add utm to url
  187. $item['full_url'] .= $glue . http_build_query($utm, '', '&amp;');
  188. }
  189. // assign articles
  190. $this->tpl->assign('searchResults', $this->items);
  191. $this->tpl->assign('searchTerm', $this->term);
  192. // parse the pagination
  193. $this->parsePagination();
  194. }
  195. /**
  196. * Save statistics
  197. */
  198. private function saveStatistics()
  199. {
  200. // no search term = no search
  201. if(!$this->term) return;
  202. // previous search result
  203. $previousTerm = SpoonSession::exists('searchTerm') ? SpoonSession::get('searchTerm') : '';
  204. SpoonSession::set('searchTerm', '');
  205. // save this term?
  206. if($previousTerm != $this->term)
  207. {
  208. // format data
  209. $this->statistics = array();
  210. $this->statistics['term'] = $this->term;
  211. $this->statistics['language'] = FRONTEND_LANGUAGE;
  212. $this->statistics['time'] = FrontendModel::getUTCDate();
  213. $this->statistics['data'] = serialize(array('server' => $_SERVER));
  214. $this->statistics['num_results'] = $this->pagination['num_items'];
  215. // save data
  216. FrontendSearchModel::save($this->statistics);
  217. }
  218. // save current search term in cookie
  219. SpoonSession::set('searchTerm', $this->term);
  220. }
  221. /**
  222. * Validate the form
  223. */
  224. private function validateForm()
  225. {
  226. // is the form submitted
  227. if($this->frm->isSubmitted())
  228. {
  229. // cleanup the submitted fields, ignore fields that were added by hackers
  230. $this->frm->cleanupFields();
  231. // validate required fields
  232. $this->frm->getField('q')->isFilled(FL::err('TermIsRequired'));
  233. // no errors?
  234. if($this->frm->isCorrect())
  235. {
  236. // get search term
  237. $this->term = $this->frm->getField('q')->getValue();
  238. }
  239. }
  240. }
  241. }