Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Pub/Controller/Search.php
<?php

namespace XF\Pub\Controller;

use
XF\Mvc\ParameterBag;
use
XF\Util\Arr;

use function
is_array;

class
Search extends AbstractController
{
    public function
actionIndex(ParameterBag $params)
    {
        if (
$params->search_id && !$this->filter('searchform', 'bool'))
        {
            return
$this->rerouteController(__CLASS__, 'results', $params);
        }

       
$this->assertNotEmbeddedImageRequest();

       
$visitor = \XF::visitor();
        if (!
$visitor->canSearch($error))
        {
            return
$this->noPermission($error);
        }

       
$input = $this->convertShortSearchInputNames();

       
$searcher = $this->app->search();
       
$type = $input['search_type'] ?: $this->filter('type', 'str');

       
$viewParams = [
           
'tabs' => $searcher->getSearchTypeTabs(),
           
'type' => $type,
           
'isRelevanceSupported' => $searcher->isRelevanceSupported(),
           
'input' => $input
       
];

       
$typeHandler = null;
        if (
$type && $searcher->isValidContentType($type))
        {
           
$typeHandler = $searcher->handler($type);
            if (!
$typeHandler->getSearchFormTab())
            {
               
$typeHandler = null;
            }
        }

        if (
$typeHandler)
        {
            if (
$sectionContext = $typeHandler->getSectionContext())
            {
               
$this->setSectionContext($sectionContext);
            }

           
$viewParams = array_merge($viewParams, $typeHandler->getSearchFormData());
           
$templateName = $typeHandler->getTypeFormTemplate();
        }
        else
        {
           
$viewParams['type'] = '';
           
$templateName = 'search_form_all';
        }

       
$viewParams['formTemplateName'] = $templateName;

        return
$this->view('XF:Search\Form', 'search_form', $viewParams);
    }

    public function
actionSearch()
    {
       
$this->assertNotEmbeddedImageRequest();

       
$visitor = \XF::visitor();
        if (!
$visitor->canSearch($error))
        {
            return
$this->noPermission($error);
        }

       
$filters = [
           
'search_type' => 'str',
           
'keywords' => 'str',
           
'c' => 'array',
           
'grouped' => 'bool',
           
'order' => 'str'
       
];

       
$input = $this->filter($filters);
       
$constraintInput = $this->filter('constraints', 'json-array');
        foreach (
$filters AS $k => $type)
        {
            if (isset(
$constraintInput[$k]))
            {
               
$cleaned = $this->app->inputFilterer()->filter($constraintInput[$k], $type);
                if (
is_array($cleaned))
                {
                   
$input[$k] = array_merge($input[$k], $cleaned);
                }
                else
                {
                   
$input[$k] = $cleaned;
                }
            }
        }

       
$query = $this->prepareSearchQuery($input, $constraints);

        if (
$query->getErrors())
        {
            return
$this->error($query->getErrors());
        }

       
$searcher = $this->app->search();
        if (
$searcher->isQueryEmpty($query, $error))
        {
            return
$this->error($error);
        }

        return
$this->runSearch($query, $constraints);
    }

    public function
actionResults(ParameterBag $params)
    {
       
$this->assertNotEmbeddedImageRequest();

       
/** @var \XF\Entity\Search $search */
       
$search = $this->em()->find('XF:Search', $params->search_id);
        if (!
$search || $search->user_id != \XF::visitor()->user_id)
        {
            if (!
$this->filter('q', 'str'))
            {
                return
$this->notFound();
            }

           
$searchData = $this->convertShortSearchInputNames();
           
$query = $this->prepareSearchQuery($searchData, $constraints);
            if (
$query->getErrors())
            {
                return
$this->notFound();
            }

            return
$this->runSearch($query, $constraints);
        }

       
$page = $this->filterPage();
       
$perPage = $this->options()->searchResultsPerPage;

       
$this->assertValidPage($page, $perPage, $search->result_count, 'search', $search);

       
$searcher = $this->app()->search();
       
$resultSet = $searcher->getResultSet($search->search_results);

       
$resultSet->sliceResultsToPage($page, $perPage);

        if (!
$resultSet->countResults())
        {
            return
$this->message(\XF::phrase('no_results_found'));
        }

       
$maxPage = ceil($search->result_count / $perPage);

        if (
$search->search_order == 'date'
           
&& $search->result_count > $perPage
           
&& $page == $maxPage)
        {
           
$lastResult = $resultSet->getLastResultData($lastResultType);
           
$getOlderResultsDate = $searcher->handler($lastResultType)->getResultDate($lastResult);
        }
        else
        {
           
$getOlderResultsDate = null;
        }

       
$resultOptions = [
           
'search' => $search,
           
'term' => $search->search_query
       
];
       
$resultsWrapped = $searcher->wrapResultsForRender($resultSet, $resultOptions);

       
$modTypes = [];
        foreach (
$resultsWrapped AS $wrapper)
        {
           
$handler = $wrapper->getHandler();
           
$entity = $wrapper->getResult();
            if (
$handler->canUseInlineModeration($entity))
            {
               
$type = $handler->getContentType();
                if (!isset(
$modTypes[$type]))
                {
                   
$modTypes[$type] = $this->app->getContentTypePhrase($type);
                }
            }
        }

       
$mod = $this->filter('mod', 'str');
        if (
$mod && !isset($modTypes[$mod]))
        {
           
$mod = '';
        }

       
$viewParams = [
           
'search' => $search,
           
'results' => $resultsWrapped,

           
'page' => $page,
           
'perPage' => $perPage,

           
'modTypes' => $modTypes,
           
'activeModType' => $mod,

           
'getOlderResultsDate' => $getOlderResultsDate
       
];
        return
$this->view('XF:Search\Results', 'search_results', $viewParams);
    }

    public function
actionMember()
    {
       
$this->assertNotEmbeddedImageRequest();

       
$userId = $this->filter('user_id', 'uint');
       
$user = $this->assertRecordExists('XF:User', $userId, null, 'requested_member_not_found');

       
$constraints = ['users' => $user->username];

       
$searcher = $this->app->search();
       
$query = $searcher->getQuery();
       
$query->byUserId($user->user_id)
            ->
orderedBy('date');

       
$content = $this->filter('content', 'str');
       
$type = $this->filter('type', 'str');
        if (
$content && $searcher->isValidContentType($content))
        {
           
$typeHandler = $searcher->handler($content);
           
$query->forTypeHandlerBasic($typeHandler);
           
// this applies the type limits that make sense

           
$constraints['content'] = $content;

           
$grouped = $this->filter('grouped', 'bool');
            if (
$grouped)
            {
               
$query->withGroupedResults();
            }
        }
        else if (
$type && $searcher->isValidContentType($type))
        {
           
$query->inType($type);
           
$constraints['type'] = $type;
        }

       
$threadType = $this->filter('thread_type', 'str');
        if (
$threadType && $query->getTypes() == ['thread'])
        {
           
$query->withMetadata('thread_type', $threadType);
           
$constraints['thread_type'] = $threadType;
        }

       
$before = $this->filter('before', 'uint');
        if (
$before)
        {
           
$query->olderThan($before);
        }

        return
$this->runSearch($query, $constraints, false);
    }

    public function
actionOlder(ParameterBag $params)
    {
       
$this->assertNotEmbeddedImageRequest();

       
/** @var \XF\Entity\Search $search */
       
$search = $this->em()->find('XF:Search', $params->search_id);
        if (!
$search || $search->user_id != \XF::visitor()->user_id)
        {
            return
$this->notFound();
        }

       
$searchData = $this->convertSearchToQueryInput($search);
       
$searchData['c']['older_than'] = $this->filter('before', 'uint');

       
$query = $this->prepareSearchQuery($searchData, $constraints);
        if (
$query->getErrors())
        {
            return
$this->error($query->getErrors());
        }

        return
$this->runSearch($query, $constraints);
    }

    protected function
convertShortSearchInputNames()
    {
       
$input = $this->filter([
           
't' => 'str',
           
'q' => 'str',
           
'c' => 'array',
           
'g' => 'bool',
           
'o' => 'str'
       
]);

        return [
           
'search_type' => $input['t'] ?: null,
           
'keywords' => $input['q'],
           
'c' => $input['c'],
           
'grouped' => $input['g'] ? 1 : 0,
           
'order' => $input['o'] ?: null
       
];
    }

    protected function
convertSearchToQueryInput(\XF\Entity\Search $search)
    {
        return [
           
'search_type' => $search->search_type,
           
'keywords' => $search->search_query,
           
'c' => $search->search_constraints,
           
'grouped' => $search->search_grouping ? 1 : 0,
           
'order' => $search->search_order
       
];
    }

    protected function
prepareSearchQuery(array $data, &$urlConstraints = [])
    {
       
$searchRequest = new \XF\Http\Request($this->app->inputFilterer(), $data, [], []);
       
$input = $searchRequest->filter([
           
'search_type' => 'str',
           
'keywords' => 'str',
           
'c' => 'array',
           
'c.title_only' => 'uint',
           
'c.newer_than' => 'datetime',
           
'c.older_than' => 'datetime',
           
'c.users' => 'str',
           
'c.content' => 'str',
           
'c.type' => 'str',
           
'c.thread_type' => 'str',
           
'grouped' => 'bool',
           
'order' => 'str'
       
]);

       
$urlConstraints = $input['c'];

       
$searcher = $this->app()->search();
       
$query = $searcher->getQuery();

        if (
$input['search_type'] && $searcher->isValidContentType($input['search_type']))
        {
           
$typeHandler = $searcher->handler($input['search_type']);
           
$query->forTypeHandler($typeHandler, $searchRequest, $urlConstraints);
        }

        if (
$input['grouped'])
        {
           
$query->withGroupedResults();
        }

       
$input['keywords'] = $this->app->stringFormatter()->censorText($input['keywords'], '');
        if (
$input['keywords'])
        {
           
$query->withKeywords($input['keywords'], $input['c.title_only']);
        }

        if (
$input['c.newer_than'])
        {
           
$query->newerThan($input['c.newer_than']);
        }
        else
        {
            unset(
$urlConstraints['newer_than']);
        }
        if (
$input['c.older_than'])
        {
           
$query->olderThan($input['c.older_than']);
        }
        else
        {
            unset(
$urlConstraints['older_than']);
        }

        if (
$input['c.users'])
        {
           
$users = Arr::stringToArray($input['c.users'], '/,\s*/');
            if (
$users)
            {
               
/** @var \XF\Repository\User $userRepo */
               
$userRepo = $this->repository('XF:User');
               
$matchedUsers = $userRepo->getUsersByNames($users, $notFound);
                if (
$notFound)
                {
                   
$query->error('users',
                        \
XF::phrase('following_members_not_found_x', ['members' => implode(', ', $notFound)])
                    );
                }
                else
                {
                   
$query->byUserIds($matchedUsers->keys());
                   
$urlConstraints['users'] = implode(', ', $users);
                }
            }
        }

        if (
$input['c.content'])
        {
           
$query->inType($input['c.content']);
        }
        else if (
$input['c.type'])
        {
           
$query->inType($input['c.type']);
        }

        if (
$input['c.thread_type'] && $query->getTypes() == ['thread'])
        {
           
$query->withMetadata('thread_type', $input['c.thread_type']);
        }

        if (
$input['order'])
        {
           
$query->orderedBy($input['order']);
        }

        return
$query;
    }

    protected function
runSearch(\XF\Search\Query\KeywordQuery $query, array $constraints, $allowCached = true)
    {
       
$visitor = \XF::visitor();
        if (!
$visitor->canSearch($error))
        {
            return
$this->noPermission($error);
        }

       
/** @var \XF\Repository\Search $searchRepo */
       
$searchRepo = $this->repository('XF:Search');
       
$search = $searchRepo->runSearch($query, $constraints, $allowCached);

        if (!
$search)
        {
            return
$this->message(\XF::phrase('no_results_found'));
        }

        return
$this->redirect($this->buildLink('search', $search), '');
    }

    public static function
getActivityDetails(array $activities)
    {
        return \
XF::phrase('searching');
    }
}