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

namespace XF\Search;

use
XF\Mvc\Entity\Entity;
use
XF\Search\Source\AbstractSource;

use function
count, intval, is_array, is_int;

class
Search implements \XF\ResultSetInterface
{
   
/**
     * @var AbstractSource
     */
   
protected $source;

    protected
$types;
    protected
$handlers = [];

    public function
__construct(AbstractSource $source, array $types)
    {
       
$this->source = $source;
       
$this->types = $types;
    }

    public function
index($contentType, $entity, $deleteIfNeeded = true)
    {
       
$handler = $this->handler($contentType);

        if (!
$entity instanceof Entity)
        {
           
$entity = $handler->getContent(intval($entity));
            if (!
$entity)
            {
                return
false;
            }
        }

       
$record = $handler->getIndexData($entity);
        if (
$record)
        {
           
$this->source->index($record);
            return
true;
        }
        else
        {
            if (
$deleteIfNeeded)
            {
               
$this->delete($contentType, $entity);
            }
            return
false;
        }
    }

    public function
indexEntities($contentType, $entities)
    {
       
$this->enableBulkIndexing();

        foreach (
$entities AS $entity)
        {
           
$this->index($contentType, $entity);
        }

       
$this->disableBulkIndexing();
    }

    public function
indexByIds($contentType, array $contentIds)
    {
        if (!
$contentIds)
        {
            return;
        }

       
$entities = $this->handler($contentType)->getContent($contentIds);
       
$this->indexEntities($contentType, $entities);
    }

    public function
indexRange($contentType, $lastId, $amount)
    {
       
$handler = $this->handler($contentType);
       
$entities = $handler->getContentInRange($lastId, $amount);
        if (!
$entities->count())
        {
            return
false;
        }

       
$this->indexEntities($contentType, $entities);

       
$keys = $entities->keys();
        return
$keys ? max($keys) : false;
    }

    public function
enableBulkIndexing()
    {
       
$this->source->enableBulkIndexing();
    }

    public function
disableBulkIndexing()
    {
       
$this->source->disableBulkIndexing();
    }

    public function
delete($contentType, $del)
    {
        if (
$del instanceof Entity)
        {
           
$del = $del->getIdentifierValues();
            if (!
$del || count($del) != 1)
            {
                throw new \
InvalidArgumentException("Entity does not have an ID or does not have a simple key");
            }
           
$del = intval(reset($del));
        }

        if (!
is_int($del) && !is_array($del))
        {
            throw new \
InvalidArgumentException("IDs to delete must be an array or an integer");
        }
        if (!
$del)
        {
            return;
        }

       
$this->source->delete($contentType, $del);
    }

    public function
truncate($type = null)
    {
        return
$this->source->truncate($type);
    }

    public function
reassignContent($oldUserId, $newUserId)
    {
       
$this->source->reassignContent($oldUserId, $newUserId);
    }

   
/**
     * @return \XF\Search\Query\KeywordQuery
     */
   
public function getQuery()
    {
       
$extendClass = \XF::extendClass('XF\Search\Query\KeywordQuery');
        return new
$extendClass($this);
    }

   
/**
     * @param Query\Query       $query
     * @param \XF\Phrase|string $error
     *
     * @return bool
     */
   
public function isQueryEmpty(Query\Query $query, &$error = null)
    {
        return
$this->source->isQueryEmpty($query, $error);
    }

    public function
getParsedKeywords($keywords, &$error = null, &$warning = null)
    {
        return
$this->source->parseKeywords($keywords, $error, $warning);
    }

    public function
isRelevanceSupported()
    {
        return
$this->source->isRelevanceSupported();
    }

   
/**
     * @param Query\KeywordQuery $query
     * @param int|null           $maxResults
     * @param bool               $applyVisitorPermissions
     *
     * @return array
     */
   
public function search(
       
Query\KeywordQuery $query,
       
$maxResults = null,
       
$applyVisitorPermissions = true
   
)
    {
        return
$this->executeSearch(
           
$query,
           
$maxResults,
            function(
$query, $maxResults)
            {
                return
$this->source->search($query, $maxResults);
            },
           
$applyVisitorPermissions
       
);
    }

   
/**
     * @param Query\Query $query
     * @param int|null    $maxResults
     * @param \Closure    $resultBuilder
     * @param bool        $applyVisitorPermissions
     *
     * @return array
     */
   
protected function executeSearch(
       
Query\Query $query,
       
$maxResults,
        \
Closure $resultBuilder,
       
$applyVisitorPermissions = true
   
)
    {
       
$maxResults = intval($maxResults);
        if (
$maxResults <= 0)
        {
           
$maxResults = max(\XF::options()->maximumSearchResults, 20);
        }

       
$this->applyPermissionConstraints($query);

       
$results = $resultBuilder($query, $maxResults);

       
$resultSet = $this->getResultSet($results)->limitResults($maxResults, $applyVisitorPermissions);
        return
$resultSet->getResults();
    }

    protected function
applyPermissionConstraints(Query\Query $query)
    {
       
$this->applyGlobalPermissionConstraints($query);

       
$handler = $query->getHandler();
        if (
$handler)
        {
           
// we're already restricted to the correct content types, so we can skip the permission constraint approach
           
foreach ($handler->getTypePermissionConstraints($query, true) AS $constraint)
            {
               
$query->withMetadata($constraint);
            }
        }
        else
        {
            foreach (
$this->getValidHandlers() AS $handler)
            {
               
$query->withPermissionConstraints(
                   
$handler->getSearchableContentTypes(),
                   
$handler->getTypePermissionConstraints($query, false)
                );
            }
        }
    }

    protected function
applyGlobalPermissionConstraints(Query\Query $query)
    {
        if (\
XF::visitor()->is_moderator && $query->getAllowHidden() === null)
        {
           
$query->allowHidden();
        }
    }

    public function
getResultSet(array $results)
    {
        return new \
XF\ResultSet($this, $results);
    }

    public function
getResultSetData($type, array $ids, $filterViewable = true, array $results = null)
    {
        if (!
$this->isValidContentType($type))
        {
            return [];
        }

       
$handler = $this->handler($type);
       
$entities = $handler->getContent($ids, true);

        if (
$filterViewable)
        {
           
$entities = $entities->filter(function($entity) use ($handler)
            {
                return
$handler->canViewContent($entity);
            });
        }

        if (
is_array($results))
        {
           
$entities = $entities->filter(function($entity) use ($handler, $results)
            {
                return
$handler->canIncludeInResults($entity, $results);
            });
        }

        return
$entities;
    }

   
/**
     * @param \XF\ResultSet $resultSet
     * @param array $options
     *
     * @return RenderWrapper[]
     */
   
public function wrapResultsForRender(\XF\ResultSet $resultSet, array $options = [])
    {
        return
$resultSet->getResultsDataCallback(function($result, $type, $id) use ($options)
        {
            return new
RenderWrapper($this->handler($type), $result, $options);
        });
    }

    public function
isValidContentType($type)
    {
        return isset(
$this->types[$type]) && class_exists($this->types[$type]);
    }

    public function
getAvailableTypes()
    {
        return
array_keys($this->types);
    }

   
/**
     * @param string $type
     *
     * @return \XF\Search\Data\AbstractData
     */
   
public function handler($type)
    {
        if (isset(
$this->handlers[$type]))
        {
            return
$this->handlers[$type];
        }

        if (!isset(
$this->types[$type]))
        {
            throw new \
InvalidArgumentException("Unknown search handler type '$type'");
        }

       
$class = $this->types[$type];
        if (
class_exists($class))
        {
           
$class = \XF::extendClass($class);
        }

       
$this->handlers[$type] = new $class($type, $this);
        return
$this->handlers[$type];
    }

   
/**
     * @return \XF\Search\Data\AbstractData[]
     */
   
public function getValidHandlers()
    {
       
$handlers = [];
        foreach (
$this->getAvailableTypes() AS $type)
        {
            if (
$this->isValidContentType($type))
            {
               
$handlers[$type] = $this->handler($type);
            }
        }

        return
$handlers;
    }

    public function
getSearchTypeTabs()
    {
       
$tabs = [];
        foreach (
$this->getValidHandlers() AS $type => $handler)
        {
           
$tab = $handler->getSearchFormTab();
            if (
$tab)
            {
                if (!isset(
$tab['order']))
                {
                   
$tab['order'] = 10;
                }
               
$tabs[$type] = $tab;
            }
        }

       
$tabs = \XF\Util\Arr::columnSort($tabs, 'order');

        return
$tabs;
    }
}