Files
IPB/system/Content/Search/Query.php
T
2025-12-19 04:57:54 -08:00

282 lines
7.6 KiB
PHP

<?php
/**
* @brief Abstract Search Query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 21 Aug 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Content\Search;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Abstract Search Query
*/
abstract class _Query
{
const TERM_OR_TAGS = 1;
const TERM_AND_TAGS = 2;
const HIDDEN_VISIBLE = 0;
const HIDDEN_UNAPPROVED = 1;
const HIDDEN_HIDDEN = -1;
const HIDDEN_PARENT_HIDDEN = 2;
const ORDER_NEWEST_UPDATED = 1;
const ORDER_NEWEST_CREATED = 2;
const ORDER_RELEVANCY = 3;
const SUPPORTS_JOIN_FILTERS = TRUE;
/**
* Create new query
*
* @param \IPS\Member $member The member performing the search (NULL for currently logged in member)
* @return \IPS\Content\Search
*/
public static function init( \IPS\Member $member = NULL )
{
$class = '\\IPS\\Content\\Search\\' . ucfirst( \IPS\Settings::i()->search_engine ) . '\\Query';
return new $class( $member ?: \IPS\Member::loggedIn() );
}
/**
* @brief Number of results to get
*/
public $resultsToGet = 25;
/**
* @brief The member performing the search
*/
protected $member;
/**
* Constructor
*
* @param \IPS\Member $member The member performing the search
* @return void
*/
public function __construct( \IPS\Member $member )
{
$this->member = $member;
if ( !$member->modPermission('can_view_hidden_content') )
{
$this->setHiddenFilter( static::HIDDEN_VISIBLE );
}
}
/**
* Exclude "first post" content items
* Useful for cases such as activity streams where you do not want both the topic and the first post to show
*
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
public function excludeFirstPostContentItems()
{
$classes = array();
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
{
if ( in_array( 'IPS\Content\Searchable', class_implements( $class ) ) and $class::$firstCommentRequired )
{
$classes[] = $class;
}
}
if ( !empty( $classes ) )
{
return $this->filterByExcludeContent( $classes );
}
else
{
return $this;
}
}
/**
* Exclude disabled applications
*
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
public function excludeDisabledApps()
{
$includeClasses = array();
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
{
if ( in_array( 'IPS\Content\Searchable', class_implements( $class ) ) )
{
$includeClasses[] = $class;
if ( isset( $class::$commentClass ) )
{
$includeClasses[] = $class::$commentClass;
}
if ( isset( $class::$reviewClass ) )
{
$includeClasses[] = $class::$reviewClass;
}
}
}
$allClasses = array();
foreach ( \IPS\Content::routedClasses( FALSE, FALSE, TRUE ) as $class )
{
if ( in_array( 'IPS\Content\Searchable', class_implements( $class ) ) )
{
$allClasses[] = $class;
if ( isset( $class::$commentClass ) )
{
$allClasses[] = $class::$commentClass;
}
if ( isset( $class::$reviewClass ) )
{
$allClasses[] = $class::$reviewClass;
}
}
}
$classes = array_diff( $allClasses, $includeClasses );
if ( !empty( $classes ) )
{
return $this->filterByExcludeContent( $classes );
}
else
{
return $this;
}
}
/**
* Filter by content type
*
* @param string $class The type of content to search (including all comment/review classes)
* @param array|NULL $containers An array of container IDs to filter by, or NULL to not filter by containers
* @param int|NULL $minimumComments The minimum number of comments
* @param int|NULL $minimumReviews The minimum number of reviews
* @param int|NULL $minimumViews The minimum number of views
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function filterByContent( $class, $containers = NULL, $minimumComments = NULL, $minimumReviews = NULL, $minimumViews = NULL );
/**
* Filter by content type to exclude
*
* @param string $classes The types of content to search (not including all comment/review classes)
* @param bool $allowedContiners If TRUE, $class should be an array of allowed containers for that class - e.g. array( 'IPS\forums\Topic' => array( 1, 2 ) - otherwise, a simple array - e.g. array( 'IPS\forums\Topic' )
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function filterByExcludeContent( array $classes, $allowedContiners=FALSE );
/**
* Filter by content item
*
* @param \IPS\Content\Item $item The item
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function filterByItem( \IPS\Content\Item $item );
/**
* Filter by author
*
* @param \IPS\Member $author The author
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function filterByAuthor( \IPS\Member $author );
/**
* Filter by start date
*
* @param \IPS\DateTime|NULL $start The start date (only results AFTER this date will be returned)
* @param \IPS\DateTime|NULL $end The end date (only results BEFORE this date will be returned)
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function filterByCreateDate( \IPS\DateTime $start = NULL, \IPS\DateTime $end = NULL );
/**
* Filter by last updated date
*
* @param \IPS\DateTime|NULL $start The start date (only results AFTER this date will be returned)
* @param \IPS\DateTime|NULL $end The end date (only results BEFORE this date will be returned)
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function filterByLastUpdatedDate( \IPS\DateTime $start = NULL, \IPS\DateTime $end = NULL );
/**
* Set hidden status
*
* @param int|array|NULL $statuses The statuses (see HIDDEN_ constants) or NULL for any
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function setHiddenFilter( $statuses );
/**
* Set limit
*
* @param int $limit Number per page
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
public function setLimit( $limit )
{
$this->resultsToGet = $limit;
return $this;
}
/**
* Set page
*
* @param int $page The page number
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function setPage( $page );
/**
* Set order
*
* @param int $order Order (see ORDER_ constants)
* @return \IPS\Content\Search\Query (for daisy chaining)
*/
abstract public function setOrder( $order );
/**
* Permission Array
*
* @return array
*/
public function permissionArray()
{
return $this->member->permissionArray();
}
/**
* Search
*
* @param string|null $term The term to search for
* @param array|null $tags The tags to search for
* @param int $method \IPS\Content\Search\Index::i()->TERM_OR_TAGS or \IPS\Content\Search\Index::i()->TERM_AND_TAGS
* @return \Traversable
*/
abstract public function search( $term = NULL, $tags = NULL, $method = 1 );
/**
* Get count
*
* @param string|null $term The term to search for
* @param array|null $tags The tags to search for
* @param int $method \IPS\Content\Search\Index::i()->TERM_OR_TAGS or \IPS\Content\Search\Index::i()->TERM_AND_TAGS
* @return int
*/
public function count( $term = NULL, $tags = NULL, $method = 1 )
{
return $this->search( $term, $tags, $method )->count( TRUE );
}
}