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

/lib/core/lhgallery/lhgallery.php

http://hppg.googlecode.com/
PHP | 829 lines | 633 code | 165 blank | 31 comment | 184 complexity | 632b847939dc31b82afa8e716e7baa9f MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. <?php
  2. class erLhcoreClassGallery{
  3. static private $sphinxClient = NULL;
  4. function __construct()
  5. {
  6. }
  7. public static function getSession($type = false)
  8. {
  9. if ($type === false && !isset( self::$persistentSession ) )
  10. {
  11. self::$persistentSession = new ezcPersistentSession(
  12. ezcDbInstance::get(),
  13. new ezcPersistentCodeManager( './pos/lhgallery' )
  14. );
  15. } elseif ($type !== false && !isset( self::$persistentSessionSlave ) ) {
  16. self::$persistentSessionSlave = new ezcPersistentSession(
  17. ezcDbInstance::get($type),
  18. new ezcPersistentCodeManager( './pos/lhgallery' )
  19. );
  20. }
  21. return $type === false ? self::$persistentSession : self::$persistentSessionSlave;
  22. }
  23. public static function multi_implode($glue, $pieces, $key = null)
  24. {
  25. $string='';
  26. if(is_array($pieces))
  27. {
  28. reset($pieces);
  29. while(list($key,$value)=each($pieces))
  30. {
  31. $string.=$glue.erLhcoreClassGallery::multi_implode($glue, $value, $key);
  32. }
  33. }
  34. else
  35. {
  36. return "{$key}_{$pieces}";
  37. }
  38. return trim($string, $glue);
  39. }
  40. /**
  41. * Does all the nasty job regarding spliting indexes. Currently only last uploads uses it.
  42. *
  43. * */
  44. public static function getShardFilter($params)
  45. {
  46. $shardPartSplit = 5000;
  47. $safeAheadOffset = 100;
  48. if (($params['offset'] / $shardPartSplit) > 1)
  49. {
  50. $db = ezcDbInstance::get();
  51. $sortKey = md5($params['sort']);
  52. $filterKey = md5( erLhcoreClassGallery::multi_implode(',',$params['filter']) );
  53. $offsetKey = floor($params['offset'] / $shardPartSplit);
  54. // Left offset filter
  55. $q = $db->createSelectQuery();
  56. $q->select( 'pid,offset' )
  57. ->from( 'lh_gallery_shard_limit' )
  58. ->where(
  59. $q->expr->land(
  60. $q->expr->lte( 'offset', $q->bindValue($params['offset']) ),
  61. $q->expr->eq( 'identifier', $q->bindValue($params['identifier']) ),
  62. $q->expr->eq( 'filter', $q->bindValue($filterKey )),
  63. $q->expr->eq( 'sort', $q->bindValue($sortKey) )
  64. ))
  65. ->limit(1,0)
  66. ->orderBy('offset DESC');
  67. $stmt = $q->prepare();
  68. $stmt->execute();
  69. $data = $stmt->fetch(PDO::FETCH_ASSOC);
  70. $appendShardData = array('filter_key' => $filterKey, 'offset' => $params['offset'], 'identifier' => $params['identifier'],'sort_key' => $sortKey );
  71. $returnShardFilter = array('filter' => false,'append_shard' => false );
  72. $leftFilter = 'filterlte';
  73. $rightFilter = 'filtergte';
  74. if (isset($params['reverse']) && $params['reverse'] === true) {
  75. $leftFilter = 'filtergte';
  76. $rightFilter = 'filterlte';
  77. }
  78. if ($data !== false && $data['pid'] !== false ) {
  79. $returnShardFilter['filter'][$leftFilter] = array('pid' => $data['pid']);
  80. $returnShardFilter['filter']['shard_deduct_limit'] = $data['offset'];
  81. }
  82. // Right offset filter
  83. $q2 = $db->createSelectQuery();
  84. $q2->select( 'pid,offset' )
  85. ->from( 'lh_gallery_shard_limit' )
  86. ->where(
  87. $q2->expr->land (
  88. $q2->expr->gte( 'offset', $q2->bindValue($params['offset']) ),
  89. $q2->expr->eq( 'identifier', $q2->bindValue($params['identifier']) ),
  90. $q2->expr->eq( 'filter', $q2->bindValue($filterKey )),
  91. $q2->expr->eq( 'sort', $q2->bindValue($sortKey) )
  92. ))
  93. ->limit(1,0)
  94. ->orderBy('offset ASC');
  95. $stmt = $q2->prepare();
  96. $stmt->execute();
  97. $dataMin = $stmt->fetch(PDO::FETCH_ASSOC);
  98. if ($dataMin !== false && $dataMin['pid'] !== false && ($dataMin['offset'] > $params['offset'] + ($shardPartSplit/10))) {
  99. $returnShardFilter['filter'][$rightFilter] = array('pid' => $dataMin['pid']);
  100. }
  101. if (isset($data['offset']) && !isset($dataMin['pid']) && ($params['offset'] - $data['offset']) > $shardPartSplit) {
  102. $returnShardFilter['append_shard'] = $appendShardData;
  103. } elseif (isset($data['offset']) && isset($dataMin['offset']) && ($params['offset'] - $data['offset']) > $shardPartSplit && ($dataMin['offset'] - $params['offset']) > $shardPartSplit) {
  104. $returnShardFilter['append_shard'] = $appendShardData;
  105. } elseif (!isset($data['offset']) && isset($dataMin['offset']) && ($dataMin['offset']-$params['offset']) > $shardPartSplit) {
  106. $returnShardFilter['append_shard'] = $appendShardData;
  107. } elseif (!isset($data['offset']) && !isset($dataMin['offset'])) {
  108. $returnShardFilter['append_shard'] = $appendShardData;
  109. }
  110. return $returnShardFilter;
  111. } else {
  112. // Offset is less than shard split part, no need any special actions
  113. return array('filter' => false,'append_shard' => false);
  114. }
  115. }
  116. public static function addShardFilter($params) {
  117. //echo "<pre>";
  118. //print_r($params);
  119. //echo "</pre>";
  120. $db = ezcDbInstance::get();
  121. $stmt = $db->prepare("REPLACE INTO lh_gallery_shard_limit (pid,offset,sort,filter,identifier) VALUES (:pid,:offset,:sort,:filter,:identifier)");
  122. $stmt->bindValue( ':pid',$params['pid']);
  123. $stmt->bindValue( ':offset',$params['offset']);
  124. $stmt->bindValue( ':sort',$params['sort_key']);
  125. $stmt->bindValue( ':filter',$params['filter_key']);
  126. $stmt->bindValue( ':identifier',$params['identifier']);
  127. $stmt->execute();
  128. }
  129. public static function expireShardIndexByIdentifier(array $identifiers,$sorts = array())
  130. {
  131. $db = ezcDbInstance::get();
  132. foreach ($identifiers as $identifier) {
  133. $sortFilter = '';
  134. if (count($sorts) > 0) {
  135. $sortFilter = ' AND (';
  136. $parts = array();
  137. foreach ($sorts as $sort){
  138. $parts[] = "sort = '".md5($sort)."'";
  139. }
  140. $sortFilter .= implode(' OR ',$parts).')';
  141. }
  142. $stmt = $db->prepare("DELETE FROM lh_gallery_shard_limit WHERE identifier = :identifier {$sortFilter}");
  143. $stmt->bindValue( ':identifier',$identifier);
  144. $stmt->execute();
  145. }
  146. }
  147. public static function searchSphinxMulti($queryesBatch,$cacheEnabled = true,$asSingle = false)
  148. {
  149. if ($cacheEnabled == true) {
  150. $cache = CSCacheAPC::getMem();
  151. $sphinxCacheVersion = $cache->getCacheVersion('sphinx_cache_version');
  152. $cacheKey = md5('SphinxSearchMulti_VersionCache'.$sphinxCacheVersion.erLhcoreClassGallery::multi_implode(',',$queryesBatch));
  153. }
  154. if ($cacheEnabled == false || ($resultReturn = $cache->restore($cacheKey)) === false)
  155. {
  156. $cl = self::getSphinxInstance();
  157. $cfg = erConfigClassLhConfig::getInstance();
  158. $maxReturn = $cfg->getSetting( 'sphinx', 'max_matches' );
  159. $wildCardEnabled = $cfg->getSetting( 'sphinx', 'enabled_wildcard');
  160. $sphinxIndex = $cfg->getSetting( 'sphinx', 'index' );
  161. $extendedSearch = $cfg->getSetting( 'color_search', 'extended_search');
  162. $faceSearch = $cfg->getSetting( 'face_search', 'enabled');
  163. $resultItems = array();
  164. $hasGroupFilter = false;
  165. $fetchedGroupFromCache = false;
  166. foreach ($queryesBatch as $params) {
  167. $executeSearch = true;
  168. $cl->ResetFilters();
  169. $cl->SetSelect('');
  170. $cl->ResetGroupBy('');
  171. $cl->SetLimits(isset($params['SearchOffset']) ? (int)$params['SearchOffset'] : 0, isset($params['SearchLimit']) ? (int)$params['SearchLimit'] : 20,$maxReturn);
  172. $filter = isset($params['Filter']) ? $params['Filter'] : array();
  173. if (isset($params['keyword'])) {
  174. $params['keyword'] = str_replace(array('.',':'),' ',$cl->EscapeString($params['keyword']));
  175. }
  176. foreach ($filter as $field => $value)
  177. {
  178. if ( is_numeric( $value ) and $value > 0 )
  179. {
  180. $cl->SetFilter( $field, array((int)$value));
  181. }
  182. else if ( is_array( $value ) and count( $value ) )
  183. {
  184. $cl->SetFilter( $field, $value);
  185. }
  186. }
  187. if (isset($params['filtergt'])) {
  188. foreach ($params['filtergt'] as $attribute => $fieldValue) {
  189. $cl->SetFilterRange( $attribute, (int)0, (int)$fieldValue, true );
  190. }
  191. }
  192. if (isset($params['filterlt'])) {
  193. foreach ($params['filterlt'] as $attribute => $fieldValue) {
  194. $cl->SetFilterRange( $attribute, (int)0, (int)$fieldValue, false );
  195. }
  196. }
  197. if (isset($params['filterfloatgt'])) {
  198. foreach ($params['filterfloatgt'] as $attribute => $fieldValue) {
  199. $cl->SetFilterFloatRange( $attribute, (float)0, (float)$fieldValue, true );
  200. }
  201. }
  202. if (isset($params['filterfloatlt'])) {
  203. foreach ($params['filterfloatlt'] as $attribute => $fieldValue) {
  204. $cl->SetFilterFloatRange( $attribute, (float)0, (float)$fieldValue, false );
  205. }
  206. }
  207. if (isset($params['FilterFloat'])) {
  208. foreach ($params['FilterFloat'] as $attribute => $fieldValue) {
  209. $cl->SetFilterFloatRange( $attribute, (float)$fieldValue, (float)$fieldValue, false );
  210. }
  211. }
  212. if (isset($params['custom_filter'])){
  213. $cl->SetSelect ( $params['custom_filter']['filter'] );
  214. $cl->SetFilter ( $params['custom_filter']['filter_name'], array(1) );
  215. }
  216. // Currently we only support all and any match modes
  217. $matchModeAll = false;
  218. if (isset($params['MatchMode'])) {
  219. switch ($params['MatchMode']) {
  220. case 'all':
  221. $cl->SetMatchMode(SPH_MATCH_ALL);
  222. $matchModeAll = true;
  223. break;
  224. default:
  225. break;
  226. }
  227. }
  228. $cl->SetSortMode(SPH_SORT_EXTENDED, isset($params['sort']) ? $params['sort'] : '@id DESC');
  229. $startAppend = $wildCardEnabled == true ? '*' : '';
  230. $colorSearchText = '';
  231. if ((isset($params['color_filter']) && count($params['color_filter']) > 0) || (isset($params['ncolor_filter']) && count($params['ncolor_filter']) > 0)){
  232. $colorSearchText = '';
  233. $selectPart = array();
  234. foreach ($params['color_filter'] as $color_id)
  235. {
  236. $colorSearchText .= ' pld'.$color_id;
  237. $selectPart[] = "ln(pld{$color_id}+1)"; // +1 to avoid infinity
  238. }
  239. // Must not be present
  240. foreach ($params['ncolor_filter'] as $color_id)
  241. {
  242. $colorSearchText .= ' -pld'.$color_id;
  243. }
  244. // Works best for search by color, like we are repeating color multiple times,
  245. // that way we get almoust the same result as using database
  246. // Reference:
  247. // http://sphinxsearch.com/docs/current.html#api-func-setrankingmode
  248. if (isset($params['color_search_mode'])) {
  249. $cl->SetMatchMode( SPH_MATCH_EXTENDED2);
  250. if (count($params['color_filter']) == 1 || erConfigClassLhConfig::getInstance()->getSetting( 'color_search', 'extended_search') == false) { // If one color we use internal wordcount algorithm
  251. if (!empty($params['color_filter'])){
  252. $cl->SetRankingMode(SPH_RANK_WORDCOUNT);
  253. } else {
  254. // Just make sure that atleast one color is set
  255. $colorSearchText = implode(' ',array_unique(explode(' ',trim($colorSearchText)))).' imgan';
  256. }
  257. } else {
  258. $colorSearchText = implode(' ',array_unique(explode(' ',trim($colorSearchText))));
  259. if (isset($params['color_filter']) && count($params['color_filter']) > 0 ) {
  260. $cl->SetRankingMode(SPH_RANK_NONE);
  261. $cl->SetSelect('FLOOR(('.implode('+',$selectPart).')*10000) as custom_match');
  262. } else {
  263. $colorSearchText .= ' imgan';
  264. }
  265. }
  266. } else { // Works best then keyword and color is used
  267. $cl->SetMatchMode( SPH_MATCH_EXTENDED2);
  268. $params['keyword'] = '('.implode($matchModeAll == true ? ' & ' : ' | ',explode(' ',trim($params['keyword']).$startAppend)).') & ';
  269. $startAppend = '';
  270. $cl->SetRankingMode(SPH_RANK_BM25);
  271. }
  272. }
  273. $weights = array (
  274. 'colors' => 9,
  275. 'title' => 10,
  276. 'caption' => 8,
  277. 'filename' => 9,
  278. 'file_path' => 7
  279. );
  280. if ($faceSearch == true) {
  281. $weights['face_data'] = 9;
  282. if (isset($params['keyword'])) {
  283. $params['keyword'] = preg_replace('/^(females|womens|women|woman)/','female',$params['keyword']);
  284. $params['keyword'] = preg_replace('/^(males|mens|man|men)/','male',$params['keyword']);
  285. $params['keyword'] = preg_replace('/^(smile)/','smiling',$params['keyword']);
  286. }
  287. }
  288. // Make some weightning
  289. $cl->SetFieldWeights($weights);
  290. if (isset($params['group_by_album']) && $params['group_by_album'] == true) {
  291. if (!isset($sphinxCacheVersion)){
  292. $cache = CSCacheAPC::getMem();
  293. $sphinxCacheVersion = $cache->getCacheVersion('sphinx_cache_version');
  294. }
  295. $paramsCache = $params;
  296. if ( isset($paramsCache['Filter']['album_id']) ) {
  297. unset($paramsCache['Filter']['album_id']);
  298. }
  299. if ( isset($paramsCache['sort']) ) {
  300. unset($paramsCache['sort']);
  301. }
  302. if ( isset($paramsCache['SearchOffset']) ) {
  303. unset($paramsCache['SearchOffset']);
  304. }
  305. if ( isset($paramsCache['SearchLimit']) ) {
  306. unset($paramsCache['SearchLimit']);
  307. }
  308. $paramsCache = array_filter($paramsCache);
  309. ksort($paramsCache);
  310. $cacheKeyGroup = md5('SphinxSearch_VersionCacheFacet'.$sphinxCacheVersion.erLhcoreClassGallery::multi_implode(',',$paramsCache));
  311. $hasGroupFilter = true;
  312. if ( ($cacheGroupResult = $cache->restore($cacheKeyGroup)) !== false ) {
  313. $fetchedGroupFromCache = true;
  314. } else {
  315. $cl->SetGroupBy( 'album_id', SPH_GROUPBY_ATTR, '@count desc' );
  316. $cl->ResetFilterByAttribute('album_id');
  317. $cl->SetLimits(0,(int)50,$maxReturn);
  318. }
  319. } elseif ( isset($params['group_by_album']) ) {
  320. $executeSearch = false; // Means filter is set, but not need to execute, because facet search is disabled
  321. }
  322. if ( $fetchedGroupFromCache == false && $executeSearch == true) {
  323. if ($asSingle == false){
  324. $cl->AddQuery( (isset($params['keyword']) && trim($params['keyword']) != '') ? trim($params['keyword']).$startAppend.$colorSearchText : trim($colorSearchText), $sphinxIndex );
  325. } else {
  326. $resultItems[] = $cl->Query( (isset($params['keyword']) && trim($params['keyword']) != '') ? trim($params['keyword']).$startAppend.$colorSearchText : trim($colorSearchText), $sphinxIndex );
  327. }
  328. }
  329. }
  330. if ($asSingle == false) {
  331. $resultItems = $cl->RunQueries();
  332. }
  333. $resultReturn = array();
  334. $idMatchGroup = array();
  335. $idMatchGroupData = array();
  336. if ($hasGroupFilter == true)
  337. {
  338. if ( $fetchedGroupFromCache == true ) {
  339. $idMatchGroup = $cacheGroupResult['id_match_group'];
  340. $idMatchGroupData = $cacheGroupResult['id_match_group_data'];
  341. } else {
  342. $resultGroup = array_pop($resultItems); // Last return is always group if it's enabled
  343. foreach ($resultGroup['matches'] as $item)
  344. {
  345. $idMatchGroup[$item['attrs']['album_id']] = null;
  346. $idMatchGroupData[$item['attrs']['album_id']] = $item['attrs']['@count'];
  347. }
  348. $listObjects = erLhcoreClassModelGalleryAlbum::getAlbumsByCategory(array('limit' => 50,'filterin'=> array('aid' => array_keys($idMatchGroup))));
  349. foreach ($listObjects as $object)
  350. {
  351. $idMatchGroup[$object->aid] = $object;
  352. }
  353. $cache->store($cacheKeyGroup,array('id_match_group' => $idMatchGroup,'id_match_group_data' => $idMatchGroupData),12000);
  354. }
  355. }
  356. // Get ID's witch we need to fetch first
  357. $imagesIDToFetch = array();
  358. foreach ($resultItems as $result)
  359. {
  360. if ($result['total_found'] != 0 && isset($result['matches'])) {
  361. $imagesIDToFetch = array_merge($imagesIDToFetch,array_keys($result['matches']));
  362. }
  363. }
  364. // We fetch only unique images
  365. $imagesIDToFetch = array_unique($imagesIDToFetch);
  366. if (count($imagesIDToFetch) > 0){
  367. $listObjects = erLhcoreClassModelGalleryImage::getImages(array('ignore_fields' => (isset($params['ignore_fields']) ? $params['ignore_fields'] : array()),'filterin'=> array('pid' => $imagesIDToFetch)));
  368. } else {
  369. foreach ($resultItems as $keyQuery => $result)
  370. {
  371. $resultReturn[$keyQuery] = array('total_found' => 0,'list' => array());
  372. }
  373. $resultReturn[] = array('facet_list' => $idMatchGroup, 'facet_data' => $idMatchGroupData);
  374. return $resultReturn;
  375. }
  376. foreach ($resultItems as $keyQuery => $result)
  377. {
  378. if ($result['total_found'] == 0 || !isset($result['matches'])) {
  379. $resultReturn[$keyQuery] = array('total_found' => 0,'list' => null);
  380. continue;
  381. }
  382. $idMatch = array();
  383. foreach ($result['matches'] as $key => $match)
  384. {
  385. $idMatch[$key] = null;
  386. }
  387. if (count($idMatch) == 0){
  388. $resultReturn[$keyQuery] = array('total_found' => 0,'list' => null);
  389. continue;
  390. }
  391. foreach ($idMatch as $key => $value)
  392. {
  393. if ( isset($listObjects[$key]) ) {
  394. $idMatch[$key] = $listObjects[$key];
  395. } else {
  396. unset($idMatch[$key]);
  397. }
  398. }
  399. if ($result['total_found'] > $maxReturn) {
  400. $result['total_found'] = $maxReturn;
  401. }
  402. $resultReturn[$keyQuery] = array('total_found' => $result['total_found'],'list' => $idMatch );
  403. }
  404. $resultReturn[] = array('facet_list' => $idMatchGroup, 'facet_data' => $idMatchGroupData);
  405. if ($cacheEnabled == true)
  406. $cache->store($cacheKey,$resultReturn,12000);
  407. }
  408. return $resultReturn;
  409. }
  410. static function getSphinxInstance() {
  411. if (self::$sphinxClient == NULL) {
  412. self::$sphinxClient = new SphinxClient();
  413. self::$sphinxClient->SetServer( erConfigClassLhConfig::getInstance()->getSetting( 'sphinx', 'host' ), erConfigClassLhConfig::getInstance()->getSetting( 'sphinx', 'port' ) );
  414. self::$sphinxClient->SetMatchMode( SPH_MATCH_ANY );
  415. }
  416. return self::$sphinxClient;
  417. }
  418. public static function searchSphinx($params = array('SearchLimit' => 20),$cacheEnabled = true)
  419. {
  420. if ($cacheEnabled == true ) {
  421. $cache = CSCacheAPC::getMem();
  422. $sphinxCacheVersion = $cache->getCacheVersion('sphinx_cache_version');
  423. $cacheKey = md5('SphinxSearch_VersionCache'.$sphinxCacheVersion.erLhcoreClassGallery::multi_implode(',',$params));
  424. }
  425. if ($cacheEnabled == false || ($resultReturn = $cache->restore($cacheKey)) === false)
  426. {
  427. $cl = self::getSphinxInstance();
  428. $cl->ResetFilters();
  429. $cl->SetSelect('');
  430. $maxMatches = erConfigClassLhConfig::getInstance()->getSetting( 'sphinx', 'max_matches' );
  431. $extendedColorSearch = erConfigClassLhConfig::getInstance()->getSetting( 'color_search', 'extended_search');
  432. $faceSearch = erConfigClassLhConfig::getInstance()->getSetting( 'face_search', 'enabled');
  433. $cl->SetLimits(isset($params['SearchOffset']) ? (int)$params['SearchOffset'] : 0,(int)$params['SearchLimit'],$maxMatches);
  434. $filter = isset($params['Filter']) ? $params['Filter'] : array();
  435. if (isset($params['keyword'])) {
  436. $params['keyword'] = str_replace(array('.',':'),' ',$cl->EscapeString($params['keyword']));
  437. }
  438. foreach ($filter as $field => $value)
  439. {
  440. if ( is_numeric( $value ) and $value > 0 )
  441. {
  442. $cl->SetFilter( $field, array((int)$value));
  443. }
  444. else if ( is_array( $value ) and count( $value ) )
  445. {
  446. $cl->SetFilter( $field, $value);
  447. }
  448. }
  449. if (isset($params['filtergt'])) {
  450. foreach ($params['filtergt'] as $attribute => $fieldValue) {
  451. $cl->SetFilterRange( $attribute, (int)0, (int)$fieldValue, true );
  452. }
  453. }
  454. if (isset($params['filterlt'])) {
  455. foreach ($params['filterlt'] as $attribute => $fieldValue) {
  456. $cl->SetFilterRange( $attribute, (int)0, (int)$fieldValue, false );
  457. }
  458. }
  459. if (isset($params['filterfloatgt'])) {
  460. foreach ($params['filterfloatgt'] as $attribute => $fieldValue) {
  461. $cl->SetFilterFloatRange( $attribute, (float)0, (float)$fieldValue, true );
  462. }
  463. }
  464. if (isset($params['filterfloatlt'])) {
  465. foreach ($params['filterfloatlt'] as $attribute => $fieldValue) {
  466. $cl->SetFilterFloatRange( $attribute, (float)0, (float)$fieldValue, false );
  467. }
  468. }
  469. if (isset($params['FilterFloat'])) {
  470. foreach ($params['FilterFloat'] as $attribute => $fieldValue) {
  471. $cl->SetFilterFloatRange( $attribute, (float)$fieldValue, (float)$fieldValue, false );
  472. }
  473. }
  474. if (isset($params['custom_filter'])){
  475. $cl->SetSelect ( $params['custom_filter']['filter'] );
  476. $cl->SetFilter ( $params['custom_filter']['filter_name'], array(1) );
  477. }
  478. // Currently we only support all and any match modes
  479. $matchModeAll = false;
  480. if (isset($params['MatchMode'])) {
  481. switch ($params['MatchMode']) {
  482. case 'all':
  483. $cl->SetMatchMode(SPH_MATCH_ALL);
  484. $matchModeAll = true;
  485. break;
  486. default:
  487. break;
  488. }
  489. }
  490. $cl->SetSortMode(SPH_SORT_EXTENDED, isset($params['sort']) ? $params['sort'] : '@id DESC');
  491. $startAppend = erConfigClassLhConfig::getInstance()->getSetting( 'sphinx', 'enabled_wildcard') == true ? '*' : '';
  492. $weights = array (
  493. 'colors' => 9,
  494. 'title' => 10,
  495. 'caption' => 8,
  496. 'filename' => 9,
  497. 'file_path' => 7
  498. );
  499. if ($faceSearch == true) {
  500. $weights['face_data'] = 9;
  501. if (isset($params['keyword'])) {
  502. $params['keyword'] = preg_replace('/^(females|womans|woman)/','female',$params['keyword']);
  503. $params['keyword'] = preg_replace('/^(males|mans|man)/','male',$params['keyword']);
  504. $params['keyword'] = preg_replace('/^(smile)/','smiling',$params['keyword']);
  505. }
  506. }
  507. // Make some weightning
  508. $cl->SetFieldWeights($weights);
  509. $colorSearchText = '';
  510. if ( (isset($params['color_filter']) && count($params['color_filter']) > 0) || (isset($params['ncolor_filter']) && count($params['ncolor_filter']) > 0) ){
  511. $colorSearchText = '';
  512. $selectPart = array();
  513. if (isset($params['color_filter'])){
  514. foreach ($params['color_filter'] as $color_id)
  515. {
  516. $colorSearchText .= ' pld'.$color_id;
  517. $selectPart[] = "ln(pld{$color_id}+1)"; // +1 to avoid infinity
  518. }
  519. }
  520. if (isset($params['ncolor_filter'])){
  521. // Must not be present
  522. foreach ($params['ncolor_filter'] as $color_id)
  523. {
  524. $colorSearchText .= ' -pld'.$color_id;
  525. }
  526. }
  527. // Works best for search by color, like we are repeating color multiple times,
  528. // that way we get almoust the same result as using database
  529. // Reference:
  530. // http://sphinxsearch.com/docs/current.html#api-func-setrankingmode
  531. if (isset($params['color_search_mode'])) {
  532. $cl->SetMatchMode( SPH_MATCH_EXTENDED2);
  533. if (count($params['color_filter']) == 1 || $extendedColorSearch == false) { // If one color we use internal wordcount algorithm
  534. if (!empty($params['color_filter'])){
  535. $cl->SetRankingMode(SPH_RANK_WORDCOUNT);
  536. } else {
  537. // Just make sure that atleast one color is set
  538. $colorSearchText = implode(' ',array_unique(explode(' ',trim($colorSearchText)))).' imgan';
  539. }
  540. } else {
  541. // Just make sure that atleast one color is set
  542. $colorSearchText = implode(' ',array_unique(explode(' ',trim($colorSearchText))));
  543. if (isset($params['color_filter']) && count($params['color_filter']) > 0 ) {
  544. $cl->SetRankingMode(SPH_RANK_NONE);
  545. $cl->SetSelect('FLOOR(('.implode('+',$selectPart).')*10000) as custom_match');
  546. } else {
  547. $colorSearchText .= ' imgan';
  548. }
  549. }
  550. } else { // Works best then keyword and color is used
  551. $cl->SetMatchMode( SPH_MATCH_EXTENDED2);
  552. $params['keyword'] = '('.implode($matchModeAll == true ? ' & ' : ' | ',explode(' ',trim($params['keyword']).$startAppend)).') & ';
  553. $startAppend = '';
  554. $cl->SetRankingMode(SPH_RANK_BM25);
  555. }
  556. }
  557. $result = $cl->AddQuery( (isset($params['keyword']) && trim($params['keyword']) != '') ? trim($params['keyword']).$startAppend.$colorSearchText : trim($colorSearchText), erConfigClassLhConfig::getInstance()->getSetting( 'sphinx', 'index' ) );
  558. $idMatchGroup = array();
  559. $idMatchGroupData = array();
  560. $fetchedGroupFromCache = false;
  561. if (isset($params['group_by_album'])) {
  562. if (!isset($sphinxCacheVersion)){
  563. $cache = CSCacheAPC::getMem();
  564. $sphinxCacheVersion = $cache->getCacheVersion('sphinx_cache_version');
  565. }
  566. $paramsCache = $params;
  567. if ( isset($paramsCache['Filter']['album_id']) ) {
  568. unset($paramsCache['Filter']['album_id']);
  569. }
  570. if ( isset($paramsCache['sort']) ) {
  571. unset($paramsCache['sort']);
  572. }
  573. if ( isset($paramsCache['SearchOffset']) ) {
  574. unset($paramsCache['SearchOffset']);
  575. }
  576. if ( isset($paramsCache['SearchLimit']) ) {
  577. unset($paramsCache['SearchLimit']);
  578. }
  579. $paramsCache = array_filter($paramsCache);
  580. ksort($paramsCache);
  581. $cacheKeyGroup = md5('SphinxSearch_VersionCacheFacet'.$sphinxCacheVersion.erLhcoreClassGallery::multi_implode(',',$paramsCache));
  582. if ( ($cacheGroupResult = $cache->restore($cacheKeyGroup)) !== false ) {
  583. $fetchedGroupFromCache = true;
  584. } else {
  585. $cl->SetGroupBy( 'album_id', SPH_GROUPBY_ATTR, '@count desc' );
  586. $cl->ResetFilterByAttribute('album_id');
  587. $cl->SetLimits(0,(int)50,$maxMatches);
  588. $cl->AddQuery( (isset($params['keyword']) && trim($params['keyword']) != '') ? trim($params['keyword']).$startAppend.$colorSearchText : trim($colorSearchText), erConfigClassLhConfig::getInstance()->getSetting( 'sphinx', 'index' ) );
  589. }
  590. }
  591. $resultArray = $cl->RunQueries();
  592. $result = array_shift($resultArray);
  593. if ($result['total_found'] == 0 || !isset($result['matches'])){
  594. if (isset($params['relevance'])) {
  595. return 1;
  596. } else {
  597. return array('total_found' => 0,'list' => null, 'facet_list' => $idMatchGroup, 'facet_data' => $idMatchGroupData);
  598. }
  599. }
  600. if ( isset($params['group_by_album']) ) {
  601. if ( $fetchedGroupFromCache == true ) {
  602. $idMatchGroup = $cacheGroupResult['id_match_group'];
  603. $idMatchGroupData = $cacheGroupResult['id_match_group_data'];
  604. } else {
  605. $resultGroup = array_shift($resultArray);
  606. $idMatchGroup = array();
  607. $idMatchGroupData = array();
  608. foreach ($resultGroup['matches'] as $item)
  609. {
  610. $idMatchGroup[$item['attrs']['album_id']] = null;
  611. $idMatchGroupData[$item['attrs']['album_id']] = $item['attrs']['@count'];
  612. }
  613. $listObjects = erLhcoreClassModelGalleryAlbum::getAlbumsByCategory(array('limit' => 50,'filterin'=> array('aid' => array_keys($idMatchGroup))));
  614. foreach ($listObjects as $object)
  615. {
  616. $idMatchGroup[$object->aid] = $object;
  617. }
  618. $cache->store($cacheKeyGroup,array('id_match_group' => $idMatchGroup,'id_match_group_data' => $idMatchGroupData),12000);
  619. }
  620. }
  621. $idMatch = array();
  622. if (isset($params['relevance'])) {
  623. $itemCurrent = array_shift($result['matches']);
  624. if (!isset($params['color_search_mode']) || count($params['color_filter']) == 1 || empty($params['color_filter']) || $extendedColorSearch == false) {
  625. $relevanceValue = $itemCurrent['weight'];
  626. } else {
  627. if (isset($itemCurrent['attrs']['custom_match'])){
  628. $relevanceValue = $itemCurrent['attrs']['custom_match'];
  629. } else {
  630. $relevanceValue = $itemCurrent['weight'];
  631. }
  632. }
  633. if ($cacheEnabled == true ) {
  634. $cache->store($cacheKey,$relevanceValue,12000);
  635. }
  636. return $relevanceValue;
  637. }
  638. foreach ($result['matches'] as $key => $match)
  639. {
  640. $idMatch[$key] = null;
  641. }
  642. if (count($idMatch) == 0)
  643. return array('total_found' => 0,'list' => null, 'facet_list' => $idMatchGroup, 'facet_data' => $idMatchGroupData);
  644. $listObjects = erLhcoreClassModelGalleryImage::getImages(array('ignore_fields' => (isset($params['ignore_fields']) ? $params['ignore_fields'] : array()), 'filterin'=> array('pid' => array_keys($idMatch))));
  645. foreach ($listObjects as $object)
  646. {
  647. $idMatch[$object->pid] = $object;
  648. }
  649. if ($result['total_found'] > $maxMatches) {
  650. $result['total_found'] = $maxMatches;
  651. }
  652. $resultReturn = array('total_found' => $result['total_found'],'list' => $idMatch, 'facet_list' => $idMatchGroup, 'facet_data' => $idMatchGroupData);
  653. if ($cacheEnabled == true) {
  654. $cache->store($cacheKey,$resultReturn,12000);
  655. }
  656. }
  657. return $resultReturn;
  658. }
  659. // For all others
  660. private static $persistentSession;
  661. // For selects
  662. private static $persistentSessionSlave;
  663. }
  664. ?>