| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- <?php
- // +----------------------------------------------------------------------
- // | 搜索管理
- // +----------------------------------------------------------------------
- namespace addons\cms\controller;
- use addons\cms\library\FulltextSearch;
- use addons\cms\library\MeiliSearch;
- use addons\cms\model\Cms as CmsModel;
- use addons\cms\model\Models;
- use think\exception\ValidateException;
- use think\facade\Db;
- class Search extends Cmsbase
- {
- protected $noNeedLogin = ['*'];
- protected $noNeedRight = [];
- protected $cms_model = null;
- protected function initialize()
- {
- parent::initialize();
- $this->cms_model = new CmsModel;
- }
- public function index()
- {
- if ($this->cmsConfig['site_searchtype'] == 'xunsearch') {
- $info = get_addon_info('xunsearch');
- if (!$info || $info['status'] != 1) {
- return $this->error('请在后台插件管理中安装《迅搜搜索》并启用后再尝试');
- }
- return $this->xunsearch();
- }
- if ($this->cmsConfig['site_searchtype'] == 'meilisearch') {
- $info = get_addon_info('meilisearch');
- if (!$info || $info['status'] != 1) {
- return $this->error('请在后台插件管理中安装《Meilisearch》并启用后再尝试');
- }
- return $this->meilisearch();
- }
- $seo = seo('', cms_t('site_search', '站内搜索'));
- $modelid = $this->request->param('modelid/d', 0);
- $q = $this->request->param('q/s', '', 'trim,safe_replace,strip_tags,htmlspecialchars');
- $q = str_replace('%', '', $q);
- $time = $this->request->param('time/s', '');
- $scope = $this->request->param('scope/s', 'site');
- $tab = $this->request->param('tab/s', '');
- try {
- $this->validate([
- 'q' => $q,
- ], [
- 'q|标题关键词' => 'chsDash|max:25',
- ]);
- } catch (ValidateException $e) {
- $this->error($e->getMessage());
- }
- $begin = microtime(true);
- if ($time == 'day') {
- $search_time = time() - 86400;
- $sql_time = ' AND publish_time > ' . $search_time;
- } elseif ($time == 'week') {
- $search_time = time() - 604800;
- $sql_time = ' AND publish_time > ' . $search_time;
- } elseif ($time == 'month') {
- $search_time = time() - 2592000;
- $sql_time = ' AND publish_time > ' . $search_time;
- } elseif ($time == 'year') {
- $search_time = time() - 31536000;
- $sql_time = ' AND publish_time > ' . $search_time;
- } else {
- $search_time = 0;
- $sql_time = '';
- }
- $shistory = session('shistory');
- if (!$shistory) {
- $shistory = [];
- }
- if (!empty($q)) {
- array_unshift($shistory, $q);
- $shistory = array_slice(array_unique(array_filter($shistory)), 0, 10);
- session('shistory', $shistory);
- }
- $modellist = Models::where('status', 1)->where('module', 'cms')->column('*', 'id');
- if (!$modellist) {
- return $this->error('没有可搜索模型~');
- }
- $newsModelIds = [1];
- $productModelIds = [2];
- $helpModelIds = [9];
- $tabModelMap = [
- 'product' => $productModelIds,
- 'news' => $newsModelIds,
- 'help' => $helpModelIds,
- ];
- $isSupportSearch = $scope === 'support_faq';
- $defaultTab = in_array($tab, ['product', 'news', 'help'], true) ? $tab : ($isSupportSearch ? 'help' : 'product');
- $allowedModelIds = array_merge($newsModelIds, $productModelIds, $helpModelIds);
- $currentLang = function_exists('cms_current_lang') ? (string)cms_current_lang() : '';
- $currentPage = max(1, (int)$this->request->param('page/d', 1));
- $perPage = 10;
- $pages = '';
- $simplePages = [];
- $groupedResults = [
- 'product' => [],
- 'news' => [],
- 'help' => [],
- ];
- $groupCounts = [
- 'product' => 0,
- 'news' => 0,
- 'help' => 0,
- ];
- $buildSearchWhere = function ($modelKey, $modelMeta) use ($q, $currentLang, $sql_time) {
- $searchField = Db::name('cms_field')->where('modelid', $modelKey)->where('ifsystem', 1)->where('ifsearch', 1)->column('name');
- $tableName = $modelMeta['tablename'] ?? '';
- $extMatchedIds = [];
- $hasLangExtTable = false;
- if (!empty($tableName)) {
- $extTable = $tableName . '_data';
- try {
- $extFields = array_map('strtolower', array_keys(Db::name($extTable)->getFields()));
- if (in_array('did', $extFields, true) && in_array('lang', $extFields, true) && !empty($currentLang)) {
- $hasLangExtTable = true;
- $extSearchFields = array_values(array_intersect($searchField ?: [], $extFields));
- if (!in_array('title', $extSearchFields, true) && in_array('title', $extFields, true)) {
- $extSearchFields[] = 'title';
- }
- $extSearchFields = array_unique(array_filter($extSearchFields));
- if (!empty($extSearchFields)) {
- $dataWhereParts = [];
- foreach ($extSearchFields as $fieldName) {
- $dataWhereParts[] = "$fieldName like '%$q%'";
- }
- if (!empty($dataWhereParts)) {
- $dataWhere = '(' . implode(' OR ', $dataWhereParts) . ") AND lang='" . addslashes($currentLang) . "'";
- $extMatchedIds = Db::name($extTable)->whereRaw($dataWhere)->column('did');
- $extMatchedIds = array_map('intval', array_filter((array)$extMatchedIds));
- }
- }
- }
- } catch (\Throwable $e) {
- }
- }
- $whereParts = [];
- if ($hasLangExtTable && !empty($currentLang)) {
- if (!empty($extMatchedIds)) {
- $whereParts[] = 'id in (' . implode(',', $extMatchedIds) . ')';
- }
- } else {
- foreach ($searchField as $fieldName) {
- $whereParts[] = "$fieldName like '%$q%'";
- }
- if (!empty($extMatchedIds)) {
- $whereParts[] = 'id in (' . implode(',', $extMatchedIds) . ')';
- }
- }
- if (empty($whereParts)) {
- return '';
- }
- $where = '(' . implode(' OR ', $whereParts) . ')';
- $where .= " AND status='1' $sql_time";
- return $where;
- };
- if ($modelid) {
- if (!array_key_exists($modelid, $modellist) || !in_array((int)$modelid, $allowedModelIds, true)) {
- $this->error('模型错误~');
- }
- $where = $buildSearchWhere($modelid, $modellist[$modelid]);
- if ($where === '') {
- $this->error('没有设置搜索字段~');
- }
- $list = $this->cms_model->getList($modelid, $where, true, '*', 'listorder DESC,id DESC', $perPage, true, false, ['strict_lang' => true]);
- if (method_exists($list, 'items')) {
- $items = $list->items();
- foreach ($items as &$item) {
- if (!isset($item['modelid'])) {
- $item['modelid'] = (int)$modelid;
- }
- }
- unset($item);
- }
- $count = $list->total();
- $pages = $list->render();
- } else {
- foreach ($tabModelMap as $tabKey => $tabModelIds) {
- foreach ($tabModelIds as $tabModelId) {
- if (!array_key_exists($tabModelId, $modellist) || !in_array((int)$tabModelId, $allowedModelIds, true)) {
- continue;
- }
- $where = $buildSearchWhere($tabModelId, $modellist[$tabModelId]);
- if ($where === '') {
- continue;
- }
- $groupCounts[$tabKey] += (int)Db::name($modellist[$tabModelId]['tablename'])->whereRaw($where)->count();
- }
- }
- $activeModelIds = $tabModelMap[$defaultTab] ?? [];
- $activeModelId = 0;
- foreach ($activeModelIds as $candidateModelId) {
- if (array_key_exists($candidateModelId, $modellist) && in_array((int)$candidateModelId, $allowedModelIds, true)) {
- $activeModelId = (int)$candidateModelId;
- break;
- }
- }
- if ($activeModelId > 0) {
- $activeWhere = $buildSearchWhere($activeModelId, $modellist[$activeModelId]);
- if ($activeWhere !== '') {
- $list = $this->cms_model->getList($activeModelId, $activeWhere, true, '*', 'listorder DESC,id DESC', $perPage, true, false, ['strict_lang' => true]);
- if (method_exists($list, 'items')) {
- $items = $list->items();
- foreach ($items as &$item) {
- if (!isset($item['modelid'])) {
- $item['modelid'] = (int)$activeModelId;
- }
- }
- unset($item);
- }
- $count = $groupCounts[$defaultTab] ?? (method_exists($list, 'total') ? $list->total() : 0);
- $pages = $list->render();
- } else {
- $list = collect([]);
- $count = 0;
- }
- } else {
- $list = collect([]);
- $count = 0;
- }
- $sourceItems = method_exists($list, 'all') ? $list->all() : (is_array($list) ? $list : []);
- $groupedResults[$defaultTab] = $sourceItems;
- }
- if ($modelid) {
- $sourceItems = method_exists($list, 'all') ? $list->all() : (is_array($list) ? $list : []);
- foreach ($sourceItems as $item) {
- $itemModelId = (int)($item['modelid'] ?? 0);
- if (in_array($itemModelId, $productModelIds, true)) {
- $groupedResults['product'][] = $item;
- } elseif (in_array($itemModelId, $newsModelIds, true)) {
- $groupedResults['news'][] = $item;
- } elseif (in_array($itemModelId, $helpModelIds, true)) {
- $groupedResults['help'][] = $item;
- }
- }
- $groupCounts = [
- 'product' => count($groupedResults['product']),
- 'news' => count($groupedResults['news']),
- 'help' => count($groupedResults['help']),
- ];
- }
- $end = microtime(true);
- $this->assign([
- 'time' => $time,
- 'modelid' => $modelid,
- 'q' => $q,
- 'scope' => $scope,
- 'tab' => $tab,
- 'shistory' => $shistory,
- 'SEO' => $seo,
- 'list' => $list,
- 'count' => $count,
- 'modellist' => $modellist,
- 'search_time' => number_format(($end - $begin), 6),
- 'pages' => $pages,
- 'simplePages' => isset($simplePages) ? $simplePages : [],
- 'isSupportSearch' => $isSupportSearch,
- 'defaultTab' => $defaultTab,
- 'groupedResults' => $groupedResults,
- 'groupCounts' => $groupCounts,
- ]);
- if (!empty($q)) {
- return $this->fetch('/search_result');
- }
- return $this->fetch('/search');
- }
- public function xunsearch()
- {
- $seo = seo('', cms_t('site_search', '站内搜索'));
- $modelid = $this->request->param('modelid/d', 0);
- $q = $this->request->param('q/s', '', 'trim,safe_replace,strip_tags,htmlspecialchars');
- $q = str_replace('%', '', $q);
- $time = $this->request->param('time/s', '');
- $page = $this->request->get('page/d', 1);
- $pagesize = 5;
- $order = $this->request->get('order', '');
- $fulltext = $this->request->get('fulltext/d', '1');
- $fuzzy = $this->request->get('fuzzy/d', '0');
- $synonyms = $this->request->get('synonyms/d', '0');
- try {
- $this->validate([
- 'q' => $q,
- ], [
- 'q|标题关键词' => 'max:25',
- ]);
- } catch (ValidateException $e) {
- $this->error($e->getMessage());
- }
- $search = FulltextSearch::setQuery($q, $fulltext, $fuzzy, $synonyms);
- if ($modelid > 0) {
- $search->addQueryString("modelid:({$modelid})");
- }
- if ($time == 'day') {
- $search_time = time() - 86400;
- $search->addRange('publish_time', $search_time, time());
- } elseif ($time == 'week') {
- $search_time = time() - 604800;
- $search->addRange('publish_time', $search_time, time());
- } elseif ($time == 'month') {
- $search_time = time() - 2592000;
- $search->addRange('publish_time', $search_time, time());
- } elseif ($time == 'year') {
- $search_time = time() - 31536000;
- $search->addRange('publish_time', $search_time, time());
- }
- $modellist = Models::where('status', 1)->where('module', 'cms')->select()->toArray();
- if (!$modellist) {
- return $this->error('没有可搜索模型~');
- }
- $query = ['q' => $q, 'modelid' => $modelid];
- $result = FulltextSearch::search($page, $pagesize, $order, $query);
- $hot = FulltextSearch::hot();
- $this->assign([
- 'time' => $time,
- 'modelid' => $modelid,
- 'q' => $q,
- 'SEO' => $seo,
- 'list' => $result['list'],
- 'count' => $result['count'],
- 'total' => $result['total'],
- 'search_time' => $result['search_time'],
- 'pages' => $result['list'] ? $result['list']->render() : '',
- 'search' => $result['search'],
- 'corrected' => $result['corrected'],
- 'related' => $result['related'],
- 'hot' => $hot,
- 'modellist' => $modellist,
- ]);
- if (!empty($q)) {
- return $this->fetch('/xunsearch_result');
- }
- return $this->fetch('/search');
- }
- public function meilisearch()
- {
- $seo = seo('', cms_t('site_search', '站内搜索'));
- $modelid = $this->request->param('modelid/d', 0);
- $q = $this->request->param('q/s', '', 'trim,safe_replace,strip_tags,htmlspecialchars');
- $q = str_replace('%', '', $q);
- $time = $this->request->param('time/s', '');
- $page = $this->request->get('page/d', 1);
- $pagesize = 5;
- $sort = $this->request->get('sort/s', '');
- $order = $this->request->get('order/s', 'desc');
- try {
- $this->validate([
- 'q' => $q,
- ], [
- 'q|标题关键词' => 'max:25',
- ]);
- } catch (ValidateException $e) {
- $this->error($e->getMessage());
- }
- $query = $pagequery = ['q' => $q];
- $modellist = Models::where('status', 1)->where('module', 'cms')->column('*', 'id');
- if (!$modellist) {
- return $this->error('没有可搜索模型~');
- }
- if ($modelid > 0) {
- $pagequery['modelid'] = $modelid;
- if (isset($query['filter'])) {
- $query['filter'] .= " AND modelid = {$modelid}";
- } else {
- $query['filter'] = "modelid = {$modelid}";
- }
- }
- if ($time) {
- $timeRanges = [
- 'day' => time() - 86400,
- 'week' => time() - 604800,
- 'month' => time() - 2592000,
- 'year' => time() - 31536000,
- ];
- $pagequery['time'] = $time;
- if (isset($timeRanges[$time])) {
- $search_time = $timeRanges[$time];
- if (isset($query['filter'])) {
- $query['filter'] .= " AND publish_time >= {$search_time}";
- } else {
- $query['filter'] = "publish_time >= {$search_time}";
- }
- }
- }
- if ($sort) {
- $pagequery['sort'] = $sort;
- $pagequery['order'] = $order;
- }
- $query['attributesToHighlight'] = ['title', 'content'];
- $result = MeiliSearch::search($page, $pagesize, "{$sort},{$order}", $query, $pagequery);
- $this->assign([
- 'SEO' => $seo,
- 'q' => $q,
- 'modelid' => $modelid,
- 'time' => $time,
- 'count' => $result['count'],
- 'search_time' => $result['search_time'],
- 'list' => $result['list'],
- 'pages' => $result['list'] ? $result['list']->render() : '',
- 'modellist' => $modellist,
- 'sort' => $sort,
- 'order' => $order,
- ]);
- if (!empty($q)) {
- return $this->fetch('/meilisearch_result');
- }
- return $this->fetch('/search');
- }
- }
|