Вход Регистрация
Файл: library/XenForo/Model/Search.php
Строк: 536
<?php

/**
 * Search model.
 *
 * @package XenForo_Search
 */
class XenForo_Model_Search extends XenForo_Model
{
    const 
CONTENT_TYPE 0;
    const 
CONTENT_ID 1;

    
/**
     * Gets the specified search.
     *
     * @param integer $searchId
     *
     * @return array|false
     */
    
public function getSearchById($searchId)
    {
        return 
$this->_getDb()->fetchRow('
            SELECT *
            FROM xf_search
            WHERE search_id = ?
        '
$searchId);
    }

    
/**
     * Inserts the specified search.
     *
     * @param array $results List of results, in format [] => array(content type, content id)
     * @param string $searchType The type of the search (usually content type or blank, but could be general string)
     * @param string $searchQuery Text that was queried for
     * @param array $constraints Additional search constraints
     * @param string $order Search sort order
     * @param boolean $groupByDiscussion True if results should be folded up into their discussion (or other container)
     * @param array $userResults List of user IDs that matched the keyword search
     * @param array $warnings Any search warnings that occurred
     * @param integer|null $userId User doing search
     * @param integer|null $searchDate Time of search or null for now
     *
     * @return array Search info, including search_id
     */
    
public function insertSearch(array $results$searchType$searchQuery, array $constraints$order$groupByDiscussion,
        array 
$userResults = array(), array $warnings = array(), $userId null$searchDate null
    
)
    {
        if (
$userId === null)
        {
            
$userId XenForo_Visitor::getUserId();
        }

        if (
$searchDate === null)
        {
            
$searchDate XenForo_Application::$time;
        }

        
$searchType utf8_substr($searchType050);
        
$order utf8_substr($order050);

        
$search = array(
            
'search_results' => json_encode(array_values($results)),
            
'result_count' => count($results),
            
'search_type' => $searchType,
            
'search_query' => utf8_substr($searchQuery0200),
            
'search_constraints' => json_encode($constraints),
            
'search_order' => $order,
            
'search_grouping' => $groupByDiscussion 0,
            
'user_results' => implode(','$userResults),
            
'warnings' => json_encode(array_map('strval'$warnings)),
            
'user_id' => $userId,
            
'search_date' => $searchDate,
            
'query_hash' => $this->getSearchQueryHash($searchType$searchQuery$constraints$order$groupByDiscussion)
        );

        
$this->_getDb()->insert('xf_search'$search);

        
$search['search_id'] = $this->_getDb()->lastInsertId();

        return 
$search;
    }

    
/**
     * Gets a search that matches the given criteria.
     *
     * @param string $searchType The type of the search (usually content type or blank, but could be general string)
     * @param string $searchQuery Text being queried for
     * @param array $constraints Search constraints
     * @param string $order Search order
     * @param boolean $groupByDiscussion True if results should be folded up into their discussion (or other container)
     * @param integer $userId User ID doing the search
     * @param boolean $forceUsage True to force the usage of the cache (in debug mode)
     *
     * @return array|false
     */
    
public function getExistingSearch($searchType$searchQuery, array $constraints$order$groupByDiscussion$userId$forceUsage false)
    {
        if (
XenForo_Application::debugMode() && !$forceUsage)
        {
            return 
false;
        }

        
$queryHash $this->getSearchQueryHash($searchType$searchQuery$constraints$order$groupByDiscussion);

        return 
$this->_getDb()->fetchRow('
            SELECT *
            FROM xf_search
            WHERE query_hash = ?
                AND search_type = ?
                AND search_query = ?
                AND user_id = ?
                AND search_date > ?
            ORDER BY search_date DESC
            LIMIT 1
        '
, array($queryHash$searchType$searchQuery$userIdXenForo_Application::$time 3600));
    }

    
/**
     * Generates the search query hash for the given criteria.
     *
     * @param string $searchType The type of the search (usually content type or blank, but could be general string)
     * @param string $searchQuery Text being queried for
     * @param array $constraints Search constraints
     * @param string $order Search order
     * @param boolean $groupByDiscussion True if results should be folded up into their discussion (or other container)
     *
     * @return string Query hash
     */
    
public function getSearchQueryHash($searchType$searchQuery, array $constraints$order$groupByDiscussion)
    {
        
$hashSource = array($searchType$searchQuery$constraints$order$groupByDiscussion 0);
        return 
md5(serialize($hashSource));
    }

    
/**
     * Prepares a search for display/use.
     *
     * @param array $search
     *
     * @return array
     */
    
public function prepareSearch(array $search)
    {
        
$search['searchConstraints'] = $this->_decodeSearchTableData($search['search_constraints'], false);
        
$search['searchWarnings'] = $this->_decodeSearchTableData($search['warnings'], false);

        
$search['users'] = $this->getModelFromCache('XenForo_Model_User')->getUsersByIds(
            
explode(','$search['user_results']),
            array(
'join' => XenForo_Model_User::FETCH_USER_FULL)
        );

        return 
$search;
    }

    
/**
     * Backwards compatability for search data, which was serialized up to 1.0.0 RC3
     * and thereafter json_encoded.
     *
     * @param string $data
     *
     * @return array
     */
    
protected function _decodeSearchTableData($data$isSearchResults true)
    {
        
$decoded json_decode($datatrue);

        if (
$decoded === null)
        {
            
$decoded unserialize($data);

            if (
$isSearchResults)
            {
                foreach (
$decoded AS &$result)
                {
                    
$result = array($result['content_type'], $result['content_id']);
                }
            }
        }

        return 
$decoded;
    }

    
/**
     * Gets the list of content types that have search handlers.
     *
     * @return array Format: [content type] => search_handler_class
     */
    
public function getSearchContentTypes()
    {
        return 
$this->getContentTypesWithField('search_handler_class');
    }

    
/**
     * Creates search data handler objects for the specified content types.
     *
     * @param array|null $handlerContentTypes List of content types. If null, get all
     *
     * @return array Format: [content type] => XenForo_Search_DataHandler_Abstract object
     */
    
public function getSearchDataHandlers(array $handlerContentTypes null)
    {
        
$contentTypes $this->getSearchContentTypes();
        
$handlers = array();
        if (
$handlerContentTypes === null)
        {
            
$handlerContentTypes array_keys($contentTypes);
        }

        foreach (
$handlerContentTypes AS $contentType)
        {
            if (isset(
$contentTypes[$contentType]))
            {
                if (!
class_exists($contentTypes[$contentType]))
                {
                    continue;
                }

                
$handlers[$contentType] = XenForo_Search_DataHandler_Abstract::create($contentTypes[$contentType]);
            }
        }

        return 
$handlers;
    }

    
/**
     * Gets the search data handler for a specific content type.
     *
     * @param string $contentType
     *
     * @return XenForo_Search_DataHandler_Abstract|false
     */
    
public function getSearchDataHandler($contentType)
    {
        
$handlers $this->getSearchDataHandlers(array($contentType));
        return 
reset($handlers);
    }

    
/**
     * Groups search results by the content type they belong to.
     *
     * @param array $results Format: [] => array(content type, content id)
     *
     * @return array Format: [content type][content id] => content id
     */
    
public function groupSearchResultsByType(array $results)
    {
        
$resultsGrouped = array();
        foreach (
$results AS $result)
        {
            
$resultsGrouped[$result[self::CONTENT_TYPE]][$result[self::CONTENT_ID]] = $result[self::CONTENT_ID];
        }

        return 
$resultsGrouped;
    }

    
/**
     * Gets the data for the search results that are actually viewable. If no
     * data is returned, the result is not viewable and should be hidden.
     *
     * @param array $resultsGrouped Search results, grouped by type (see {@link groupSearchResultsByType()})
     * @param array $handlers Search data handler objects for all necessary content types
     * @param boolean $prepareData True if the data should be prepared as well
     * @param array|null $viewingUser Information about the viewing user (keys: user_id, permission_combination_id, permissions) or null for visitor
     *
     * @return array Result data grouped, format: [content type][content id] => data
     */
    
public function getViewableSearchResultData(array $resultsGrouped, array $handlers$prepareData true, array $viewingUser null)
    {
        
$this->standardizeViewingUserReference($viewingUser);

        
$dataGrouped = array();
        foreach (
$handlers AS $contentType => $handler)
        {
            if (!isset(
$resultsGrouped[$contentType]))
            {
                continue;
            }

            
$dataResults $handler->getDataForResults($resultsGrouped[$contentType], $viewingUser$resultsGrouped);
            foreach (
$dataResults AS $dataId => $data)
            {
                if (!
$handler->canViewResult($data$viewingUser))
                {
                    unset(
$dataResults[$dataId]);
                    continue;
                }

                if (
$prepareData)
                {
                    
$dataResults[$dataId] = $handler->prepareResult($data$viewingUser);
                }
            }

            
$dataGrouped[$contentType] = $dataResults;
        }

        return 
$dataGrouped;
    }

    
/**
     * Filters a list of search results to those that are viewable.
     *
     * @param array $results Search results ([] => array(content type, content id)
     * @param array|null $viewingUser Information about the viewing user (keys: user_id, permission_combination_id, permissions) or null for visitor
     *
     * @return array Same as input results, but unviewable entries removed
     */
    
public function getViewableSearchResults(array $results, array $viewingUser null)
    {
        
$resultsGrouped $this->groupSearchResultsByType($results);
        
$handlers $this->getSearchDataHandlers(array_keys($resultsGrouped));

        
$dataGrouped $this->getViewableSearchResultData($resultsGrouped$handlersfalse$viewingUser);

        foreach (
$results AS $resultId => $result)
        {
            if (!isset(
$dataGrouped[$result[self::CONTENT_TYPE]][$result[self::CONTENT_ID]]))
            {
                unset(
$results[$resultId]);
            }
        }

        return 
$results;
    }

    
/**
     * Gets the search results ready for display (using the handlers).
     * The results (in the returned "results" key) have extra, type-specific data
     * included with them.
     *
     * @param array $results Search results ([] => array(content type, content id)
     * @param array|null $viewingUser Information about the viewing user (keys: user_id, permission_combination_id, permissions) or null for visitor
     *
     * @return array Keys: results, handlers
     */
    
public function getSearchResultsForDisplay(array $results, array $viewingUser null)
    {
        
$resultsGrouped $this->groupSearchResultsByType($results);
        
$handlers $this->getSearchDataHandlers(array_keys($resultsGrouped));

        
$dataGrouped $this->getViewableSearchResultData($resultsGrouped$handlerstrue$viewingUser);

        foreach (
$results AS $resultId => $result)
        {
            if (isset(
$dataGrouped[$result[self::CONTENT_TYPE]][$result[self::CONTENT_ID]]))
            {
                
$results[$resultId]['content'] = $dataGrouped[$result[self::CONTENT_TYPE]][$result[self::CONTENT_ID]];
            }
            else
            {
                unset(
$results[$resultId]);
            }
        }

        if (!
$results)
        {
            return 
false;
        }

        return array(
            
'results' => $results,
            
'handlers' => $handlers
        
);
    }

    
/**
     * Returns the slice of search results for the requested page.
     *
     * @param array $search Search, containing search results
     * @param integer $page
     * @param integer $perPage
     *
     * @return array Results for the specified page
     */
    
public function sliceSearchResultsToPage(array $search$page$perPage)
    {
        if (
$page 1)
        {
            
$page 1;
        }

        if (!isset(
$search['searchResults']))
        {
            
$search['searchResults'] = $this->_decodeSearchTableData($search['search_results'], true);
        }

        return 
array_slice($search['searchResults'], ($page 1) * $perPage$perPage);
    }

    
/**
     * Gets the general search constraints from an array of input.
     *
     * @param array $input
     * @param mixed $errors Returns a list of errors that occurred when getting constraints
     *
     * @return array Constraints
     */
    
public function getGeneralConstraintsFromInput(array $input, &$errors null)
    {
        
$constraints = array();
        
$errors = array();

        if (!empty(
$input['date']))
        {
            
$constraints['date'] = $input['date'];
        }
        if (!empty(
$input['title_only']))
        {
            
$constraints['title_only'] = $input['title_only'];
        }
        if (!empty(
$input['nodes']) && reset($input['nodes']))
        {
            if (!empty(
$input['child_nodes']))
            {
                
$childNodeIds array_keys($this->getModelFromCache('XenForo_Model_Node')->getChildNodesForNodeIds($input['nodes']));
                
$input['nodes'] = array_unique(array_merge($input['nodes'], $childNodeIds));
            }
            
$constraints['node'] = implode(' '$input['nodes']);
            if (!
$constraints['node'])
            {
                unset(
$constraints['node']); // just 0
            
}
        }
        if (!empty(
$input['users']))
        {
            
/* @var $userModel XenForo_Model_User */
            
$userModel $this->getModelFromCache('XenForo_Model_User');
            
$usernames explode(','$input['users']);
            
$users $userModel->getUsersByNames($usernames, array(), $notFound);

            if (
$notFound)
            {
                
$errors[] = new XenForo_Phrase('following_members_not_found_x', array('members' => implode(', '$notFound)));
            }

            
$constraints['user'] = array_keys($users);

            if (
$constraints['user'] && !empty($input['user_content']))
            {
                
$constraints['user_content'] = $input['user_content'];
            }
        }

        return 
$constraints;
    }
}
Онлайн: 2
Реклама