Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
+112
-71
@@ -11,16 +11,28 @@
|
||||
namespace IPS\Content\Search;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Content;
|
||||
use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\Db\Select;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Club;
|
||||
use IPS\Settings;
|
||||
use function defined;
|
||||
use function is_null;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Search Query
|
||||
*/
|
||||
abstract class _Query
|
||||
abstract class Query
|
||||
{
|
||||
const TERM_OR_TAGS = 1; // If both tags and a term are provided, match results where either the tags or the term match
|
||||
const TERM_AND_TAGS = 2; // If both tags and a term are provided, match only results where BOTH the tags or the term match
|
||||
@@ -47,38 +59,38 @@ abstract class _Query
|
||||
/**
|
||||
* Create new query
|
||||
*
|
||||
* @param \IPS\Member $member The member performing the search (NULL for currently logged in member)
|
||||
* @return \IPS\Content\Search\Query
|
||||
* @param Member|null $member The member performing the search (NULL for currently logged in member)
|
||||
* @return Query
|
||||
*/
|
||||
public static function init( \IPS\Member $member = NULL )
|
||||
public static function init( Member|null $member = NULL ): static
|
||||
{
|
||||
if ( \IPS\Settings::i()->search_method == 'elastic' )
|
||||
if ( Settings::i()->search_method == 'elastic' )
|
||||
{
|
||||
return new \IPS\Content\Search\Elastic\Query( $member ?: \IPS\Member::loggedIn(), \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
|
||||
return new Elastic\Query( $member ?: Member::loggedIn(), Url::external( rtrim( Settings::i()->search_elastic_server, '/' ) . '/' . Settings::i()->search_elastic_index ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return new \IPS\Content\Search\Mysql\Query( $member ?: \IPS\Member::loggedIn() );
|
||||
return new Mysql\Query( $member ?: Member::loggedIn() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Number of results to get
|
||||
*/
|
||||
public $resultsToGet = 25;
|
||||
public int $resultsToGet = 25;
|
||||
|
||||
/**
|
||||
* @brief The member performing the search
|
||||
*/
|
||||
protected $member;
|
||||
protected Member $member;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\Member $member The member performing the search
|
||||
* @param Member $member The member performing the search
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( \IPS\Member $member )
|
||||
public function __construct( Member $member )
|
||||
{
|
||||
$this->member = $member;
|
||||
|
||||
@@ -90,9 +102,9 @@ abstract class _Query
|
||||
|
||||
/* Exclude disabled applications */
|
||||
$filters = array();
|
||||
foreach ( \IPS\Content::routedClasses( $member, FALSE, TRUE ) as $class )
|
||||
foreach ( Content::routedClasses( $member, FALSE, TRUE ) as $class )
|
||||
{
|
||||
$filters[] = \IPS\Content\Search\ContentFilter::init( $class );
|
||||
$filters[] = ContentFilter::init( $class );
|
||||
}
|
||||
if ( !empty( $filters ) )
|
||||
{
|
||||
@@ -105,50 +117,50 @@ abstract class _Query
|
||||
*
|
||||
* @param array $contentFilters Array of \IPS\Content\Search\ContentFilter objects
|
||||
* @param bool $type TRUE means only include results matching the filters, FALSE means exclude all results matching the filters
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByContent( array $contentFilters, $type = TRUE );
|
||||
abstract public function filterByContent( array $contentFilters, bool $type = TRUE ): static;
|
||||
|
||||
/**
|
||||
* Filter by author
|
||||
*
|
||||
* @param \IPS\Member|int|array $author The author, or an array of author IDs
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @param Member|int|array $author The author, or an array of author IDs
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByAuthor( $author );
|
||||
abstract public function filterByAuthor( Member|int|array $author ): static;
|
||||
|
||||
/**
|
||||
* Filter by club
|
||||
*
|
||||
* @param \IPS\Member\Club|int|array $club The club, or array of club IDs
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @param Club|int|array|null $club The club, or array of club IDs
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByClub( $club );
|
||||
abstract public function filterByClub( Club|int|array|null $club ): static;
|
||||
|
||||
/**
|
||||
* Filter for profile
|
||||
*
|
||||
* @param \IPS\Member $member The member whose profile is being viewed
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @param Member $member The member whose profile is being viewed
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterForProfile( \IPS\Member $member );
|
||||
abstract public function filterForProfile( Member $member ): static;
|
||||
|
||||
/**
|
||||
* Filter by item author
|
||||
*
|
||||
* @param \IPS\Member $author The author
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @param Member $author The author
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByItemAuthor( \IPS\Member $author );
|
||||
abstract public function filterByItemAuthor( Member $author ): static;
|
||||
|
||||
/**
|
||||
* Filter by container class
|
||||
*
|
||||
* @param array $classes Container classes to exclude from results.
|
||||
* @param array $exclude Content classes to exclude from the filter. For cases where multiple content classes may have the same container class such as Gallery images, comments and reviews.
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByContainerClasses( $classes=array(), $exclude=array() );
|
||||
abstract public function filterByContainerClasses( array $classes=array(), array $exclude=array() ): static;
|
||||
|
||||
/**
|
||||
* Filter by content the user follows
|
||||
@@ -156,72 +168,72 @@ abstract class _Query
|
||||
* @param bool $includeContainers Include content in containers the user follows?
|
||||
* @param bool $includeItems Include items and comments/reviews on items the user follows?
|
||||
* @param bool $includeMembers Include content posted by members the user follows?
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByFollowed( $includeContainers, $includeItems, $includeMembers );
|
||||
abstract public function filterByFollowed( bool $includeContainers, bool $includeItems, bool $includeMembers ): static;
|
||||
|
||||
/**
|
||||
* Filter by content the user has posted in
|
||||
*
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByItemsIPostedIn();
|
||||
abstract public function filterByItemsIPostedIn(): static;
|
||||
|
||||
/**
|
||||
* Filter by content the user has not read
|
||||
*
|
||||
* @note If applicable, it is more efficient to call filterByContent() before calling this method
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByUnread();
|
||||
abstract public function filterByUnread(): static;
|
||||
|
||||
/**
|
||||
* Filter by content the user has not read
|
||||
*
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterBySolved();
|
||||
abstract public function filterBySolved(): static;
|
||||
|
||||
/**
|
||||
* Filter by content the user has not read
|
||||
*
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByUnsolved();
|
||||
abstract public function filterByUnsolved(): static;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @param DateTime|NULL $start The start date (only results AFTER this date will be returned)
|
||||
* @param DateTime|NULL $end The end date (only results BEFORE this date will be returned)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByCreateDate( \IPS\DateTime $start = NULL, \IPS\DateTime $end = NULL );
|
||||
abstract public function filterByCreateDate( DateTime|null $start = NULL, DateTime|null $end = NULL ): static;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @param DateTime|NULL $start The start date (only results AFTER this date will be returned)
|
||||
* @param DateTime|NULL $end The end date (only results BEFORE this date will be returned)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function filterByLastUpdatedDate( \IPS\DateTime $start = NULL, \IPS\DateTime $end = NULL );
|
||||
abstract public function filterByLastUpdatedDate( DateTime|null $start = NULL, DateTime|null $end = NULL ): static;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function setHiddenFilter( $statuses );
|
||||
abstract public function setHiddenFilter( int|array|null $statuses ): static;
|
||||
|
||||
/**
|
||||
* Set limit
|
||||
*
|
||||
* @param int $limit Number per page
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
public function setLimit( $limit )
|
||||
public function setLimit( int $limit ): static
|
||||
{
|
||||
$this->resultsToGet = $limit;
|
||||
return $this;
|
||||
@@ -231,24 +243,24 @@ abstract class _Query
|
||||
* Set page
|
||||
*
|
||||
* @param int $page The page number
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function setPage( $page );
|
||||
abstract public function setPage( int $page ): static;
|
||||
|
||||
/**
|
||||
* Set order
|
||||
*
|
||||
* @param int $order Order (see ORDER_ constants)
|
||||
* @return \IPS\Content\Search\Query (for daisy chaining)
|
||||
* @return Query (for daisy chaining)
|
||||
*/
|
||||
abstract public function setOrder( $order );
|
||||
abstract public function setOrder( int $order ): static;
|
||||
|
||||
/**
|
||||
* Permission Array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function permissionArray()
|
||||
public function permissionArray(): array
|
||||
{
|
||||
return $this->member->permissionArray();
|
||||
}
|
||||
@@ -260,16 +272,16 @@ abstract class _Query
|
||||
* @param array|null $tags The tags to search for
|
||||
* @param int $method See \IPS\Content\Search\Query::TERM_* contants
|
||||
* @param string|null $operator If $term contains more than one word, determines if searching for both ("and") or any ("or") of those terms. NULL will go to admin-defined setting
|
||||
* @return \IPS\Content\Search\Results
|
||||
* @return Results
|
||||
*/
|
||||
abstract public function search( $term = NULL, $tags = NULL, $method = 1, $operator = NULL );
|
||||
abstract public function search( string|null $term = NULL, array|null $tags = NULL, int $method = 1, string|null $operator = NULL ): Results;
|
||||
|
||||
/**
|
||||
* Get the default date cut off
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultDateCutOff()
|
||||
public function getDefaultDateCutOff(): string
|
||||
{
|
||||
return 'any';
|
||||
}
|
||||
@@ -279,7 +291,7 @@ abstract class _Query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultSortMethod()
|
||||
public function getDefaultSortMethod(): string
|
||||
{
|
||||
return 'relevancy';
|
||||
}
|
||||
@@ -301,9 +313,9 @@ abstract class _Query
|
||||
* @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
|
||||
* @param string|null $operator If $term contains more than one word, determines if searching for both ("and") or any ("or") of those terms. NULL will go to admin-defined setting
|
||||
* @return int
|
||||
* @return Select|int
|
||||
*/
|
||||
public function count( $term = NULL, $tags = NULL, $method = 1, $operator = NULL )
|
||||
public function count( string|null $term = NULL, array|null $tags = NULL, int $method = 1, string|null $operator = NULL ): Select|int
|
||||
{
|
||||
return $this->search( $term, $tags, $method, $operator )->count( TRUE );
|
||||
}
|
||||
@@ -314,9 +326,9 @@ abstract class _Query
|
||||
* @param string $term The term to search for
|
||||
* @return boolean
|
||||
*/
|
||||
public static function termIsPhrase( $term )
|
||||
public static function termIsPhrase( string $term ): bool
|
||||
{
|
||||
return (boolean) preg_match( '#^".*"$#', $term );
|
||||
return (bool) preg_match( '#^".*"$#', $term );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,10 +340,10 @@ abstract class _Query
|
||||
* @param int|NULL $maxLength The maximum length a sequence of characters can be for it to be considered a word. If null, ft_max_word_len/innodb_ft_max_token_size is used.
|
||||
* @return array
|
||||
*/
|
||||
public static function termAsWordsArray( $term, $ignorePhrase=FALSE, $minLength=NULL, $maxLength=NULL )
|
||||
public static function termAsWordsArray( string $term, bool $ignorePhrase=FALSE, int|null $minLength=NULL, int|null $maxLength=NULL ): array
|
||||
{
|
||||
$minLength = \is_null( $minLength ) ? 0 : $minLength;
|
||||
$maxLength = \is_null( $maxLength ) ? 255 : $maxLength;
|
||||
$minLength = is_null( $minLength ) ? 0 : $minLength;
|
||||
$maxLength = is_null( $maxLength ) ? 255 : $maxLength;
|
||||
|
||||
/* Sub quotes with smaller than min word strings can cause issues for larger tables, so we convert the sub quote into normal words for a boolean search */
|
||||
if ( ! static::termIsPhrase( $term ) )
|
||||
@@ -405,8 +417,37 @@ abstract class _Query
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isRebuildRunning()
|
||||
public static function isRebuildRunning(): bool
|
||||
{
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', 'core_queue', array( '`key`=?', 'RebuildSearchIndex' ) )->first() ? TRUE : FALSE;
|
||||
return (bool) Db::i()->select( 'COUNT(*)', 'core_queue', array( '`key`=?', 'RebuildSearchIndex' ) )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run custom search engine filters
|
||||
*
|
||||
* @param bool $itemsOnly
|
||||
* @return void
|
||||
*/
|
||||
public function customFiltering( bool $itemsOnly=FALSE ) : void
|
||||
{
|
||||
/* Get the list of valid classes */
|
||||
$classesChecked = array();
|
||||
foreach( SearchContent::searchableClasses() as $class )
|
||||
{
|
||||
if ( $itemsOnly AND in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
{
|
||||
$classesChecked[] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give content item classes a chance to inspect and manipulate filters */
|
||||
$filters = array();
|
||||
foreach( $classesChecked as $itemClass )
|
||||
{
|
||||
if( $extension = SearchContent::extension( $itemClass ) )
|
||||
{
|
||||
$extension::searchEngineFiltering( $filters, $this );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user