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

/plugins/search/flexisearch.php

http://flexicontent.googlecode.com/
PHP | 394 lines | 273 code | 54 blank | 67 comment | 53 complexity | cbed09a1f64c08630bdc01cb7ba806ca MD5 | raw file
Possible License(s): MIT, GPL-2.0, Apache-2.0
  1. <?php
  2. /**
  3. * @version 1.0 $Id: flexisearch.php 1781 2013-10-03 02:29:51Z ggppdk $
  4. * @package Joomla
  5. * @subpackage FLEXIcontent
  6. * @copyright (C) 2009 Emmanuel Danan - www.vistamedia.fr
  7. * @license GNU/GPL v2
  8. *
  9. * FLEXIcontent is a derivative work of the excellent QuickFAQ component
  10. * @copyright (C) 2008 Christoph Lukes
  11. * see www.schlu.net for more information
  12. *
  13. * FLEXIcontent is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. */
  18. // no direct access
  19. defined( '_JEXEC' ) or die( 'Restricted access' );
  20. jimport('joomla.plugin.plugin');
  21. require_once(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_flexicontent'.DS.'defineconstants.php');
  22. require_once(JPATH_SITE.DS.'components'.DS.'com_content'.DS.'helpers'.DS.'route.php');
  23. require_once(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'helpers'.DS.'route.php');
  24. require_once(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_search'.DS.'helpers'.DS.'search.php');
  25. require_once(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'classes'.DS.'flexicontent.fields.php');
  26. require_once(JPATH_SITE.DS.'components'.DS.'com_flexicontent'.DS.'classes'.DS.'flexicontent.helper.php');
  27. /**
  28. * Content Search plugin
  29. *
  30. * @package FLEXIcontent.Plugin
  31. * @subpackage Search.flexisearch
  32. * @since 1.6
  33. */
  34. class plgSearchFlexisearch extends JPlugin
  35. {
  36. public function __construct(& $subject, $config)
  37. {
  38. parent::__construct($subject, $config);
  39. $extension_name = 'plg_search_flexisearch';
  40. //$this->loadLanguage();
  41. //$this->loadLanguage( '$extension_name, JPATH_ADMINISTRATOR);
  42. JFactory::getLanguage()->load($extension_name, JPATH_ADMINISTRATOR, 'en-GB' , true);
  43. JFactory::getLanguage()->load($extension_name, JPATH_ADMINISTRATOR, null , true);
  44. }
  45. function _getAreas()
  46. {
  47. $areas = array();
  48. if ($this->params->get('search_title', 1)) {$areas['FlexisearchTitle'] = JText::_('FLEXI_STDSEARCH_TITLE');}
  49. if ($this->params->get('search_desc', 1)) {$areas['FlexisearchDesc'] = JText::_('FLEXI_STDSEARCH_DESC');}
  50. if ($this->params->get('search_fields', 1)) {$areas['FlexisearchFields'] = JText::_('FLEXI_STDSEARCH_FIELDS');}
  51. if ($this->params->get('search_meta', 1)) {$areas['FlexisearchMeta'] = JText::_('FLEXI_STDSEARCH_META');}
  52. if ($this->params->get('search_tags', 1)) {$areas['FlexisearchTags'] = JText::_('FLEXI_STDSEARCH_TAGS');}
  53. // Goto last element of array and add to it 2 line breaks, this layout hack is not appropriate e.g. the areas maybe inside a list ...
  54. //end($areas);
  55. //$areas[key($areas)]=current($areas).'<br><br>';
  56. return $areas;
  57. }
  58. function _getContentTypes()
  59. {
  60. // Get allowed search types
  61. $typeIds = $this->params->get('search_types', '');
  62. $typesarray = array();
  63. preg_match_all('/\b\d+\b/', $typeIds, $typesarray);
  64. $wheres=array();
  65. foreach ($typesarray[0] as $key=>$typeID)
  66. {
  67. $wheres[]='t.id = '.$typeID;
  68. }
  69. $whereTypes = $wheres ? '(' . implode(') OR (', $wheres) . ')' : '';
  70. $db = JFactory::getDbo();
  71. $query = ' SELECT t.id, t.name'
  72. .' FROM #__flexicontent_types AS t '
  73. .' WHERE t.published = 1'.($whereTypes ? ' AND ('.$whereTypes.')' : '')
  74. .' ORDER BY t.id ASC';
  75. $db->setQuery($query);
  76. $list = $db->loadObjectList();
  77. $ContentType = array();
  78. if (isset($list)){
  79. foreach($list as $item){
  80. $ContentType['FlexisearchType'.$item->id]=$item->name.'<br>'; // add a line break too
  81. }
  82. }
  83. // Goto last element of array and add to it one more line breaks, this layout hack is not appropriate e.g. the areas maybe inside a list ...
  84. //end($ContentType);
  85. //$ContentType[key($ContentType)]=current($ContentType).'<br>';
  86. return $ContentType;
  87. }
  88. /*
  89. * @return array of search areas
  90. */
  91. function onContentSearchAreas()
  92. {
  93. static $areas = array();
  94. $areas = $this->params->get('search_select_types', 1) ? $this->_getAreas() + $this->_getContentTypes() : $this->_getAreas();
  95. return $areas;
  96. }
  97. // Also add J1.5 function signature
  98. function onSearchAreas() { return $this->onContentSearchAreas(); }
  99. /**
  100. * Content Search method
  101. * The sql must return the following fields that are used in a common display
  102. * routine: href, title, section, created, text, browsernav
  103. * @param string Target search string
  104. * @param string mathcing option, exact|any|all
  105. * @param string ordering option, newest|oldest|popular|alpha|category
  106. * @param mixed An array if restricted to areas, null if search all
  107. */
  108. function onContentSearch( $text, $phrase='', $ordering='', $areas=null )
  109. {
  110. $db = JFactory::getDbo();
  111. $app = JFactory::getApplication();
  112. $user = JFactory::getUser();
  113. // Get language
  114. $cntLang = substr(JFactory::getLanguage()->getTag(), 0,2); // Current Content language (Can be natively switched in J2.5)
  115. $urlLang = JRequest::getWord('lang', '' ); // Language from URL (Can be switched via Joomfish in J1.5)
  116. $lang = (FLEXI_J16GE || empty($urlLang)) ? $cntLang : $urlLang;
  117. // COMPONENT PARAMETERS
  118. $cparams = $app->isSite() ? $app->getParams('com_flexicontent') : JComponentHelper::getParams('com_flexicontent');
  119. if (!defined('FLEXI_SECTION'))
  120. define('FLEXI_SECTION', $cparams->get('flexi_section')); // define section
  121. $show_noauth = $cparams->get('show_noauth', 0); // items the user cannot see ...
  122. $searchText = $text;
  123. $AllAreas = array_keys( $this->_getAreas() );
  124. $AllTypes = array_keys( $this->_getContentTypes() );
  125. if (is_array($areas)) {
  126. // search in selected areas
  127. $searchAreas = array_intersect( $areas, $AllAreas );
  128. $searchTypes = array_intersect( $areas, $AllTypes );
  129. if (!$searchAreas && !$searchTypes) return array();
  130. if (!$searchAreas) {$searchAreas = $AllAreas;}
  131. if (!$searchTypes) {$searchTypes = $AllTypes;}
  132. } else {
  133. // search in all avaliable areas if no selected ones
  134. $searchAreas = $AllAreas;
  135. $searchTypes = $AllTypes;
  136. }
  137. foreach ($searchTypes as $id=>$tipe){
  138. $searchTypes[$id]=preg_replace('/\D/','',$tipe);
  139. }
  140. $types= implode(', ',$searchTypes);
  141. $filter_lang = $this->params->def('filter_lang', 1);
  142. $limit = $this->params->def('search_limit', 50);
  143. // Dates for publish up & down items
  144. $date = JFactory::getDate();
  145. $nowDate = FLEXI_J16GE ? $date->toSql() : $date->toMySQL();
  146. $nullDate = $db->getNullDate();
  147. $text = trim($text);
  148. if ($text == '') {
  149. return array();
  150. }
  151. $wheres = array();
  152. switch ($phrase) {
  153. case 'exact':
  154. $text = FLEXI_J16GE ? $db->escape($text, true) : $db->getEscaped($text, true);
  155. $text = $db->Quote('%'.$text.'%', false);
  156. $wheres2 = array();
  157. if (in_array('FlexisearchTitle', $searchAreas)) {$wheres2[] = 'i.title LIKE '.$text;}
  158. if (in_array('FlexisearchDesc', $searchAreas)) {$wheres2[] = 'i.introtext LIKE '.$text; $wheres2[] = 'i.fulltext LIKE '.$text;}
  159. if (in_array('FlexisearchMeta', $searchAreas)) {$wheres2[] = 'i.metakey LIKE '.$text; $wheres2[] = 'i.metadesc LIKE '.$text;}
  160. if (in_array('FlexisearchFields', $searchAreas)) {$wheres2[] = "f.field_type IN ('text','textselect') AND f.issearch=1 AND fir.value LIKE ".$text;}
  161. if (in_array('FlexisearchTags', $searchAreas)) {$wheres2[] = 't.name LIKE '.$text;}
  162. if (count($wheres2)) $where = '(' . implode(') OR (', $wheres2) . ')';
  163. break;
  164. case 'all':
  165. case 'any':
  166. default:
  167. $words = explode(' ', $text);
  168. $wheres = array();
  169. foreach ($words as $word) {
  170. $word = FLEXI_J16GE ? $db->escape($word, true) : $db->getEscaped($word, true);
  171. $word = $db->Quote('%'.$word.'%', false);
  172. $wheres2 = array();
  173. if (in_array('FlexisearchTitle', $searchAreas)) {$wheres2[] = 'i.title LIKE '.$word;}
  174. if (in_array('FlexisearchDesc', $searchAreas)) {$wheres2[] = 'i.introtext LIKE '.$word; $wheres2[] = 'i.fulltext LIKE '.$word;}
  175. if (in_array('FlexisearchMeta', $searchAreas)) {$wheres2[] = 'i.metakey LIKE '.$word; $wheres2[] = 'i.metadesc LIKE '.$word;}
  176. if (in_array('FlexisearchFields', $searchAreas)) {$wheres2[] = "f.field_type IN ('text','textselect') AND f.issearch=1 AND fir.value LIKE ".$word;}
  177. if (in_array('FlexisearchTags', $searchAreas)) {$wheres2[] = 't.name LIKE '.$word;}
  178. if (count($wheres2)) $wheres[] = '(' . implode(') OR (', $wheres2) . ')';
  179. }
  180. if (count($wheres)) {
  181. $where = '(' . implode(($phrase == 'all' ? ') AND (' : ') OR ('), $wheres) . ')';
  182. }
  183. break;
  184. }
  185. if (!@$where) {return array();}
  186. //if ( empty($where) ) $where = '1';
  187. switch ($ordering)
  188. {
  189. //case 'relevance': $order = ' ORDER BY score DESC, i.title ASC'; break;
  190. case 'oldest': $order = 'i.created ASC'; break;
  191. case 'popular': $order = 'i.hits DESC'; break;
  192. case 'alpha': $order = 'i.title ASC'; break;
  193. case 'category': $order = 'c.title ASC, i.title ASC'; break;
  194. case 'newest': $order = 'i.created DESC'; break;
  195. default: $order = 'i.created DESC'; break;
  196. }
  197. // ****************************************************************************************
  198. // Create JOIN clause and WHERE clause part for filtering by current (viewing) access level
  199. // ****************************************************************************************
  200. $joinaccess = '';
  201. $andaccess = '';
  202. $select_access = '';
  203. // Extra access columns for main category and content type (item access will be added as 'access')
  204. $select_access .= ', c.access as category_access, ty.access as type_access';
  205. if ( !$show_noauth ) { // User not allowed to LIST unauthorized items
  206. if (FLEXI_J16GE) {
  207. $aid_arr = $user->getAuthorisedViewLevels();
  208. $aid_list = implode(",", $aid_arr);
  209. $andaccess .= ' AND ty.access IN (0,'.$aid_list.')';
  210. $andaccess .= ' AND c.access IN (0,'.$aid_list.')';
  211. $andaccess .= ' AND i.access IN (0,'.$aid_list.')';
  212. } else {
  213. $aid = (int) $user->get('aid');
  214. if (FLEXI_ACCESS) {
  215. $joinaccess .= ' LEFT JOIN #__flexiaccess_acl AS gt ON ty.id = gt.axo AND gt.aco = "read" AND gt.axosection = "type"';
  216. $joinaccess .= ' LEFT JOIN #__flexiaccess_acl AS gc ON c.id = gc.axo AND gc.aco = "read" AND gc.axosection = "category"';
  217. $joinaccess .= ' LEFT JOIN #__flexiaccess_acl AS gi ON i.id = gi.axo AND gi.aco = "read" AND gi.axosection = "item"';
  218. $andaccess .= ' AND (gt.aro IN ( '.$user->gmid.' ) OR ty.access <= '. $aid . ')';
  219. $andaccess .= ' AND (gc.aro IN ( '.$user->gmid.' ) OR c.access <= '. $aid . ')';
  220. $andaccess .= ' AND (gi.aro IN ( '.$user->gmid.' ) OR i.access <= '. $aid . ')';
  221. } else {
  222. $andaccess .= ' AND ty.access <= '.$aid;
  223. $andaccess .= ' AND c.access <= '.$aid;
  224. $andaccess .= ' AND i.access <= '.$aid;
  225. }
  226. }
  227. $select_access .= ', 1 AS has_access';
  228. }
  229. else {
  230. // Access Flags for: content type, main category, item
  231. if (FLEXI_J16GE) {
  232. $aid_arr = $user->getAuthorisedViewLevels();
  233. $aid_list = implode(",", $aid_arr);
  234. $select_access .= ', '
  235. .' CASE WHEN '
  236. .' ty.access IN ('.$aid_list.') AND '
  237. .' c.access IN ('.$aid_list.') AND '
  238. .' i.access IN ('.$aid_list.') '
  239. .' THEN 1 ELSE 0 END AS has_access';
  240. } else {
  241. $aid = (int) $user->get('aid');
  242. if (FLEXI_ACCESS) {
  243. $joinaccess .= ' LEFT JOIN #__flexiaccess_acl AS gt ON ty.id = gt.axo AND gt.aco = "read" AND gt.axosection = "type"';
  244. $joinaccess .= ' LEFT JOIN #__flexiaccess_acl AS gc ON c.id = gc.axo AND gc.aco = "read" AND gc.axosection = "category"';
  245. $joinaccess .= ' LEFT JOIN #__flexiaccess_acl AS gi ON i.id = gi.axo AND gi.aco = "read" AND gi.axosection = "item"';
  246. $select_access .= ', '
  247. .' CASE WHEN '
  248. .' (gt.aro IN ( '.$user->gmid.' ) OR ty.access <= '. (int) $aid . ') AND '
  249. .' (gc.aro IN ( '.$user->gmid.' ) OR c.access <= '. (int) $aid . ') AND '
  250. .' (gi.aro IN ( '.$user->gmid.' ) OR i.access <= '. (int) $aid . ') '
  251. .' THEN 1 ELSE 0 END AS has_access';
  252. } else {
  253. $select_access .= ', '
  254. .' CASE WHEN '
  255. .' (ty.access <= '. (int) $aid . ') AND '
  256. .' ( c.access <= '. (int) $aid . ') AND '
  257. .' ( i.access <= '. (int) $aid . ') '
  258. .' THEN 1 ELSE 0 END AS has_access';
  259. }
  260. }
  261. }
  262. // **********************************************************************************************************************************************************
  263. // Create WHERE clause part for filtering by current active language, and current selected contend types ( !! although this is possible via a filter too ...)
  264. // **********************************************************************************************************************************************************
  265. $andlang = '';
  266. if ( $app->isSite() &&
  267. ( FLEXI_FISH || (FLEXI_J16GE && $app->getLanguageFilter()) ) &&
  268. $filter_lang // Language filtering enabled
  269. ) {
  270. $andlang .= ' AND ie.language LIKE ' . $db->Quote( $lang .'%' );
  271. }
  272. // search articles
  273. $results = array();
  274. if ( $limit > 0)
  275. {
  276. $query = 'SELECT i.sectionid,'
  277. .' i.id as id,'
  278. .' i.title AS title,'
  279. .' i.metakey AS metakey,'
  280. .' i.metadesc AS metadesc,'
  281. .' i.modified AS created,' // TODO ADD a PARAMETER FOR CONTROLING the use of modified by or created by date as "created"
  282. .' t.name AS tagname,'
  283. .' fir.value as field,'
  284. .' CONCAT(i.introtext, i.fulltext) AS text,'
  285. .' CONCAT_WS( " / ", '. $db->Quote( JText::_( 'FLEXICONTENT' ) ) .', c.title, i.title ) AS section,'
  286. .' CASE WHEN CHAR_LENGTH(i.alias) THEN CONCAT_WS(\':\', i.id, i.alias) ELSE i.id END AS slug,'
  287. .' CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(\':\', c.id, c.alias) ELSE c.id END AS catslug,'
  288. .' "2" AS browsernav'
  289. . $select_access
  290. .' FROM #__content AS i'
  291. .' JOIN #__categories AS c ON i.catid = c.id'
  292. .' JOIN #__flexicontent_items_ext AS ie ON i.id = ie.item_id'
  293. .' JOIN #__flexicontent_types AS ty ON ie.type_id = ty.id'
  294. // searching into text-like fields
  295. .' LEFT JOIN #__flexicontent_fields_item_relations AS fir ON i.id = fir.item_id'
  296. .' LEFT JOIN #__flexicontent_fields AS f ON fir.field_id = f.id'
  297. // searching into 'tags' field
  298. .' LEFT JOIN #__flexicontent_tags_item_relations AS tir ON i.id = tir.itemid'
  299. .' LEFT JOIN #__flexicontent_tags AS t ON tir.tid = t.id '
  300. . $joinaccess
  301. .' WHERE ( '.$where.' ) '
  302. .' AND ie.type_id IN('.$types.') '
  303. .' AND i.state IN (1, -5) AND c.published = 1 '
  304. .' AND (i.publish_up = '.$db->Quote($nullDate).' OR i.publish_up <= '.$db->Quote($nowDate).') '
  305. .' AND (i.publish_down = '.$db->Quote($nullDate).' OR i.publish_down >= '.$db->Quote($nowDate).') '
  306. . $andaccess // Filter by user access
  307. . $andlang // Filter by current language
  308. . ' GROUP BY i.id '
  309. . ' ORDER BY '. $order
  310. ;
  311. //echo "<pre style='white-space:normal!important;'>".$query."</pre>";
  312. $db->setQuery($query, 0, $limit);
  313. $list = $db->loadObjectList();
  314. if ($db->getErrorNum()) { echo $db->getErrorMsg(); }
  315. if ( $list )
  316. {
  317. $item_cats = FlexicontentFields::_getCategories($list);
  318. foreach($list as $key => $item)
  319. {
  320. // echo $item->title." ".$item->tagname."<br/>"; // Before checking for noHTML
  321. if( FLEXI_J16GE || $item->sectionid==FLEXI_SECTION ) {
  322. $item->categories = isset($item_cats[$item->id]) ? $item_cats[$item->id] : array(); // in case of item categories missing
  323. $item->href = JRoute::_(FlexicontentHelperRoute::getItemRoute($item->slug, $item->catslug));
  324. } else {
  325. $item->href = JRoute::_(ContentHelperRoute::getArticleRoute($item->slug, $item->catslug, $item->sectionid));
  326. }
  327. if (searchHelper::checkNoHTML($item, $searchText, array('title', 'metadesc', 'metakey', 'tagname', 'field', 'text' ))) {
  328. $results[$item->id] = $item;
  329. }
  330. }
  331. }
  332. }
  333. return $results;
  334. }
  335. // Also add J1.5 function signature
  336. function onSearch( $text, $phrase='', $ordering='', $areas=null )
  337. {
  338. return $this->onContentSearch( $text, $phrase, $ordering, $areas );
  339. }
  340. }