mirror of
https://github.com/Oreolek/ifhub.club.git
synced 2024-07-02 22:45:02 +03:00
228 lines
6.8 KiB
PHP
228 lines
6.8 KiB
PHP
<?php
|
||
/**
|
||
* LiveStreet CMS
|
||
* Copyright © 2013 OOO "ЛС-СОФТ"
|
||
*
|
||
* ------------------------------------------------------
|
||
*
|
||
* Official site: www.livestreetcms.com
|
||
* Contact e-mail: office@livestreetcms.com
|
||
*
|
||
* GNU General Public License, version 2:
|
||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||
*
|
||
* ------------------------------------------------------
|
||
*
|
||
* @link http://www.livestreetcms.com
|
||
* @copyright 2014 OOO "ЛС-СОФТ"
|
||
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* Модуль поиска
|
||
*
|
||
* @package modules.search
|
||
* @since 2.0
|
||
*/
|
||
class ModuleSearch extends Module {
|
||
|
||
protected $oMapper;
|
||
|
||
/**
|
||
* Инициализация модуля
|
||
*/
|
||
public function Init() {
|
||
$this->oMapper=Engine::GetMapper(__CLASS__);
|
||
}
|
||
|
||
/**
|
||
* Выполняет поиск топиков по регулярному выражению
|
||
*
|
||
* @param $sRegexp
|
||
* @param $iCurrPage
|
||
* @param $iPerPage
|
||
*
|
||
* @return array
|
||
*/
|
||
public function SearchTopics($sRegexp,$iCurrPage,$iPerPage) {
|
||
$sCacheKey="search_topics_{$sRegexp}_{$iCurrPage}_{$iPerPage}";
|
||
if (false===($data=$this->Cache_Get($sCacheKey))) {
|
||
$data=array(
|
||
'collection'=> $this->oMapper->SearchTopics($sRegexp,$iCount,$iCurrPage,$iPerPage),
|
||
'count'=> $iCount
|
||
);
|
||
$this->Cache_Set($data,$sCacheKey,array('topic_update','topic_new'),60*60*24*1);
|
||
}
|
||
if ($data['collection']) {
|
||
$data['collection']=$this->Topic_GetTopicsAdditionalData($data['collection']);
|
||
}
|
||
return $data;
|
||
}
|
||
/**
|
||
* Выполняет поиск комментариев по регулярному выражению
|
||
*
|
||
* @param $sRegexp
|
||
* @param $iCurrPage
|
||
* @param $iPerPage
|
||
* @param $sTargetType
|
||
*
|
||
* @return array
|
||
*/
|
||
public function SearchComments($sRegexp,$iCurrPage,$iPerPage,$sTargetType) {
|
||
$sCacheKey="search_comments_{$sRegexp}_{$iCurrPage}_{$iPerPage}_".serialize($sTargetType);
|
||
if (false===($data=$this->Cache_Get($sCacheKey))) {
|
||
$data=array(
|
||
'collection'=> $this->oMapper->SearchComments($sRegexp,$iCount,$iCurrPage,$iPerPage,$sTargetType),
|
||
'count'=> $iCount
|
||
);
|
||
$this->Cache_Set($data,$sCacheKey,array('comment_new'),60*60*24*1);
|
||
}
|
||
if ($data['collection']) {
|
||
$data['collection']=$this->Comment_GetCommentsAdditionalData($data['collection']);
|
||
}
|
||
return $data;
|
||
}
|
||
/**
|
||
* Выделяет отрывки из текста с необходимыми словами (делает сниппеты)
|
||
*
|
||
* @param string $sText Исходный текст
|
||
* @param array|string $aWords Список слов
|
||
* @param array $aParams Список параметром
|
||
*
|
||
* @return string
|
||
*/
|
||
public function BuildExcerpts($sText,$aWords,$aParams=array()) {
|
||
$iMaxLengthBetweenWords=isset($aParams['iMaxLengthBetweenWords']) ? $aParams['iMaxLengthBetweenWords'] : 200;
|
||
$iLengthIndentSection=isset($aParams['iLengthIndentSection']) ? $aParams['iLengthIndentSection'] : 100;
|
||
$iMaxCountSections=isset($aParams['iMaxCountSections']) ? $aParams['iMaxCountSections'] : 3;
|
||
$sWordWrapBegin=isset($aParams['sWordWrapBegin']) ? $aParams['sWordWrapBegin'] : '<span class="searched-item">';
|
||
$sWordWrapEnd=isset($aParams['sWordWrapEnd']) ? $aParams['sWordWrapEnd'] : '</span>';
|
||
$sGlueSections=isset($aParams['sGlueSections']) ? $aParams['sGlueSections'] : "\r\n";
|
||
|
||
$sText=strip_tags($sText);
|
||
$sText=trim($sText);
|
||
if (is_string($aWords)) {
|
||
$aWords=preg_split('#[\W]+#u',$aWords);
|
||
}
|
||
$sPregWords=join('|',array_filter($aWords,'preg_quote'));
|
||
$aSections=array();
|
||
if (preg_match_all("#{$sPregWords}#i",$sText,$aMatchAll,PREG_OFFSET_CAPTURE)) {
|
||
$aSectionItems=array();
|
||
$iCountDiff=-1;
|
||
foreach($aMatchAll[0] as $aMatch) {
|
||
if ($iCountDiff==-1 or $aMatch[1]-$iCountDiff<=$iMaxLengthBetweenWords) {
|
||
$aSectionItems[]=$aMatch;
|
||
$iCountDiff=$aMatch[1];
|
||
} else {
|
||
$aSections[]=array('items'=>$aSectionItems);
|
||
$aSectionItems=array();
|
||
$aSectionItems[]=$aMatch;
|
||
$iCountDiff=$aMatch[1];
|
||
}
|
||
}
|
||
if (count($aSectionItems)) {
|
||
$aSections[]=array('items'=>$aSectionItems);
|
||
}
|
||
}
|
||
|
||
$aSections=array_slice($aSections,0,$iMaxCountSections);
|
||
|
||
$sTextResult='';
|
||
if ($aSections) {
|
||
foreach($aSections as $aSection) {
|
||
/**
|
||
* Расчитываем дополнительные данные: начало и конец фрагмента, уникальный список слов
|
||
*/
|
||
$aItem=reset($aSection['items']);
|
||
$aSection['begin']=$aItem[1];
|
||
$aItem=end($aSection['items']);
|
||
$aSection['end']=$aItem[1]+mb_strlen($aItem[0],'utf-8');
|
||
$aSection['words']=array();
|
||
|
||
foreach($aSection['items'] as $aItem) {
|
||
$sKey=mb_strtolower($aItem[0],'utf-8');
|
||
$aSection['words'][$sKey]=$aItem[0];
|
||
}
|
||
|
||
/**
|
||
* Формируем фрагменты текста
|
||
*/
|
||
|
||
/**
|
||
* Определям правую границу текста по слову
|
||
*/
|
||
$iEnd=$aSection['end'];
|
||
for($i=$iEnd;($i<=$aSection['end']+$iLengthIndentSection) and $i<mb_strlen($sText,'utf-8');$i++) {
|
||
if (preg_match('#^\s$#',mb_substr($sText,$i,1,'utf-8'))) {
|
||
$iEnd=$i;
|
||
}
|
||
}
|
||
/**
|
||
* Определям левую границу текста по слову
|
||
*/
|
||
$iBegin=$aSection['begin'];
|
||
for($i=$iBegin;($i>=$aSection['begin']-$iLengthIndentSection) and $i>=0;$i--) {
|
||
if (preg_match('#^\s$#',mb_substr($sText,$i,1,'utf-8'))) {
|
||
$iBegin=$i;
|
||
}
|
||
}
|
||
/**
|
||
* Вырезаем фрагмент текста
|
||
*/
|
||
$sTextSection=trim(mb_substr($sText,$iBegin,$iEnd-$iBegin,'utf-8'));
|
||
if ($iBegin>0) {
|
||
$sTextSection='...'.$sTextSection;
|
||
}
|
||
if ($iEnd<mb_strlen($sText,'utf-8')) {
|
||
$sTextSection.='...';
|
||
}
|
||
$sTextSection=preg_replace("#{$sPregWords}#i",$sWordWrapBegin.'\\0'.$sWordWrapEnd,$sTextSection);
|
||
$sTextResult.=$sTextSection.$sGlueSections;
|
||
}
|
||
} else {
|
||
$iLength=$iMaxLengthBetweenWords*2;
|
||
if ($iLength>mb_strlen($sText,'utf-8')) {
|
||
$iLength=mb_strlen($sText,'utf-8');
|
||
}
|
||
$sTextResult=trim(mb_substr($sText,0,$iLength-1,'utf-8'));
|
||
}
|
||
return $sTextResult;
|
||
}
|
||
/**
|
||
* Возвращает массив слов из поискового запроса
|
||
*
|
||
* @param $sQuery
|
||
*
|
||
* @return array
|
||
*/
|
||
public function GetWordsForSearch($sQuery) {
|
||
/**
|
||
* Удаляем запрещенные символы
|
||
*/
|
||
$sQuery=preg_replace('#[^\w\sа-я\-]+#iu',' ',$sQuery);
|
||
/**
|
||
* Разбиваем фразу на слова
|
||
*/
|
||
$aWords=preg_split('#[\s]+#u',$sQuery);
|
||
foreach($aWords as $k=>$sWord) {
|
||
/**
|
||
* Короткие слова удаляем
|
||
*/
|
||
if (mb_strlen($sWord,'utf-8')<3) {
|
||
unset($aWords[$k]);
|
||
}
|
||
}
|
||
return $aWords;
|
||
}
|
||
/**
|
||
* Возвращает регулярное выражение для поиска в БД по словам
|
||
*
|
||
* @param $aWords
|
||
*
|
||
* @return string
|
||
*/
|
||
public function GetRegexpForWords($aWords) {
|
||
return join('|',$aWords);
|
||
}
|
||
} |