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
@@ -11,30 +11,48 @@
|
||||
namespace IPS\Content\Search\Mysql;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\Application;
|
||||
use IPS\Content;
|
||||
use IPS\Content\Comment;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Content\Search\Index as SearchIndex;
|
||||
use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\IPS;
|
||||
use IPS\Member;
|
||||
use OutOfRangeException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL Search Index
|
||||
*/
|
||||
class _Index extends \IPS\Content\Search\Index
|
||||
class Index extends SearchIndex
|
||||
{
|
||||
/**
|
||||
* Get index data
|
||||
*
|
||||
* @param \IPS\Content\Searchable $object Item to add
|
||||
* @param Content $object Item to add
|
||||
* @return array|NULL
|
||||
*/
|
||||
public function indexData( \IPS\Content\Searchable $object )
|
||||
public function indexData( Content $object ): array|NULL
|
||||
{
|
||||
$indexData = parent::indexData( $object );
|
||||
|
||||
if( $indexData === NULL )
|
||||
{
|
||||
return $indexData;
|
||||
return null;
|
||||
}
|
||||
|
||||
/* The index_title in core_search_index is varchar(255) so we have to limit to this length */
|
||||
@@ -49,14 +67,16 @@ class _Index extends \IPS\Content\Search\Index
|
||||
/**
|
||||
* Index an item
|
||||
*
|
||||
* @param \IPS\Content\Searchable $object Item to add
|
||||
* @param Content $object Item to add
|
||||
* @return void
|
||||
*/
|
||||
public function index( \IPS\Content\Searchable $object )
|
||||
public function index( Content $object ): void
|
||||
{
|
||||
/* Get the index data */
|
||||
$indexData = $this->indexData( $object );
|
||||
$class = \get_class( $object );
|
||||
|
||||
/* @var Content $class */
|
||||
$class = get_class( $object );
|
||||
|
||||
/* If we got the data... */
|
||||
if( $indexData )
|
||||
@@ -77,10 +97,10 @@ class _Index extends \IPS\Content\Search\Index
|
||||
|
||||
try
|
||||
{
|
||||
$existingData = \IPS\Db::i()->select( 'index_id, index_class, index_object_id, index_item_id, index_hidden, index_is_last_comment, index_author', 'core_search_index', array( 'index_class=? AND index_object_id=?', $indexData['index_class'], $indexData['index_object_id'] ) )->first();
|
||||
$existingData = Db::i()->select( 'index_id, index_class, index_object_id, index_item_id, index_hidden, index_is_last_comment, index_author', 'core_search_index', array( 'index_class=? AND index_object_id=?', $indexData['index_class'], $indexData['index_object_id'] ) )->first();
|
||||
$existingIndexId = $existingData['index_id'];
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
catch( Exception ) { }
|
||||
|
||||
/* Adjust tags */
|
||||
$tags = NULL;
|
||||
@@ -92,7 +112,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
unset( $indexData['index_prefix'] );
|
||||
}
|
||||
|
||||
if ( $object instanceof \IPS\Content\Comment and $existingIndexId and $existingData['index_is_last_comment'] and $indexData['index_item_id'] and $indexData['index_hidden'] !== 0 )
|
||||
if ( $object instanceof Comment and $existingIndexId and $existingData['index_is_last_comment'] and $indexData['index_is_last_comment'] and $indexData['index_item_id'] and $indexData['index_hidden'] !== 0 )
|
||||
{
|
||||
/* We do not allow hidden or needing approval comments to become flagged as the last comment as this means users without hidden view permission never see the item in an item only stream */
|
||||
$indexData['index_is_last_comment'] = 0;
|
||||
@@ -104,7 +124,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$classes = array( $class );
|
||||
|
||||
/* If this is the latest comment, unflag what was set before on both item and comment */
|
||||
if ( $object instanceof \IPS\Content\Comment )
|
||||
if ( $object instanceof Comment )
|
||||
{
|
||||
$itemClass = $object::$itemClass;
|
||||
if ( ! $itemClass::$firstCommentRequired )
|
||||
@@ -117,7 +137,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$classes[] = $itemClass::$reviewClass;
|
||||
}
|
||||
}
|
||||
else if ( $object instanceof \IPS\Content\Item )
|
||||
else if ( $object instanceof Item )
|
||||
{
|
||||
if ( isset( $class::$commentClass ) )
|
||||
{
|
||||
@@ -129,59 +149,60 @@ class _Index extends \IPS\Content\Search\Index
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexData['index_item_id'] ) );
|
||||
Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexData['index_item_id'] ) );
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_date_updated' => $indexData['index_date_updated'], 'index_date_commented' => $indexData['index_date_commented'] ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_object_id=?', $indexData['index_item_id'], ( $firstCommentId ?? $indexData['index_item_id'] ) ) );
|
||||
Db::i()->update( 'core_search_index', array( 'index_date_updated' => $indexData['index_date_updated'], 'index_date_commented' => $indexData['index_date_commented'] ), array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_object_id=?', $indexData['index_item_id'], ( $firstCommentId ?? $indexData['index_item_id'] ) ) );
|
||||
}
|
||||
|
||||
if ( $existingData !== NULL and ( $indexData['index_class'] == $existingData['index_class'] and $indexData['index_object_id'] == $existingData['index_object_id'] ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_search_index', $indexData, array( 'index_class=? and index_object_id=?', $indexData['index_class'], $indexData['index_object_id'] ) );
|
||||
Db::i()->update( 'core_search_index', $indexData, array( 'index_class=? and index_object_id=?', $indexData['index_class'], $indexData['index_object_id'] ) );
|
||||
$newIndexId = $existingIndexId;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $existingData !== NULL )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? and index_object_id=?', $indexData['index_class'], $indexData['index_object_id'] ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? and index_object_id=?', $indexData['index_class'], $indexData['index_object_id'] ) );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$newIndexId = \IPS\Db::i()->insert( 'core_search_index', $indexData );
|
||||
$newIndexId = Db::i()->insert( 'core_search_index', $indexData );
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
catch( Db\Exception $e )
|
||||
{
|
||||
if ( $e->getCode() == 1062 )
|
||||
{
|
||||
/* Duplicate key which could be caused by a race condition on rebuild. Use replace in this case, as it is more expensive than an insert, so we only use it when we have to */
|
||||
$newIndexId = \IPS\Db::i()->replace( 'core_search_index', $indexData );
|
||||
$newIndexId = Db::i()->replace( 'core_search_index', $indexData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If that was successful... */
|
||||
/* @var array $databaseColumnMap */
|
||||
if ( $newIndexId )
|
||||
{
|
||||
/* Remove existing tags */
|
||||
if ( $existingIndexId )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags', array( 'index_id=?', $existingIndexId ) );
|
||||
Db::i()->delete( 'core_search_index_tags', array( 'index_id=?', $existingIndexId ) );
|
||||
}
|
||||
|
||||
/* Add add them back if we have any */
|
||||
if ( \count( $tags ) )
|
||||
/* Add them back if we have any */
|
||||
if ( count( $tags ) )
|
||||
{
|
||||
foreach( $tags as $tag )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_search_index_tags', array( 'index_id' => $newIndexId, 'index_tag' => $tag, 'index_is_prefix' => ( $tag == $prefix ) ) );
|
||||
Db::i()->replace( 'core_search_index_tags', array( 'index_id' => $newIndexId, 'index_tag' => $tag, 'index_is_prefix' => ( isset( $prefix ) AND $tag == $prefix ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the map table, we always populate it under the item class regardless */
|
||||
if ( $existingData == NULL or ( $existingData !== NULL and ( $existingData['index_author'] != $indexData['index_author'] OR $existingData['index_item_id'] != $indexData['index_item_id'] ) ) )
|
||||
if ( $existingData == NULL or ( $existingData['index_author'] != $indexData['index_author'] OR $existingData['index_item_id'] != $indexData['index_item_id'] ) )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_search_index_item_map', array( 'index_author_id' => $indexData['index_author'], 'index_item_id' => $indexData['index_item_id'], 'index_class' => ( $object instanceof \IPS\Content\Comment ? $object::$itemClass : $class ) ) );
|
||||
Db::i()->replace( 'core_search_index_item_map', array( 'index_author_id' => $indexData['index_author'], 'index_item_id' => $indexData['index_item_id'], 'index_class' => ( $object instanceof Comment ? $object::$itemClass : $class ) ) );
|
||||
}
|
||||
|
||||
$databaseColumnId = $object::$databaseColumnId;
|
||||
@@ -189,7 +210,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
/* Set index_item_index_id on other index items */
|
||||
if ( $existingIndexId != $newIndexId )
|
||||
{
|
||||
if ( $object instanceof \IPS\Content\Item )
|
||||
if ( $object instanceof Item )
|
||||
{
|
||||
$subClasses = array( $class );
|
||||
if ( isset( $class::$commentClass ) )
|
||||
@@ -201,15 +222,15 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$subClasses[] = $class::$reviewClass;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_item_index_id' => $newIndexId ), array( array( \IPS\Db::i()->in( 'index_class', $subClasses ) ), array( 'index_item_id=?', $object->$databaseColumnId ) ) );
|
||||
Db::i()->update( 'core_search_index', array( 'index_item_index_id' => $newIndexId ), array( array( Db::i()->in( 'index_class', $subClasses ) ), array( 'index_item_id=?', $object->$databaseColumnId ) ) );
|
||||
}
|
||||
elseif ( $object instanceof \IPS\Content\Comment )
|
||||
elseif ( $object instanceof Comment )
|
||||
{
|
||||
$itemClass = $object::$itemClass;
|
||||
if ( $itemClass::$firstCommentRequired and $object->isFirst() )
|
||||
{
|
||||
$itemColumnId = $class::$databaseColumnMap['item'];
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_item_index_id' => $newIndexId ), array( \IPS\Db::i()->in( 'index_class', array( $class, $class::$itemClass ) ) . ' AND index_item_id=?', $object->$itemColumnId ) );
|
||||
Db::i()->update( 'core_search_index', array( 'index_item_index_id' => $newIndexId ), array( Db::i()->in( 'index_class', array( $class, $class::$itemClass ) ) . ' AND index_item_id=?', $object->$itemColumnId ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,33 +247,33 @@ class _Index extends \IPS\Content\Search\Index
|
||||
/**
|
||||
* Retrieve the search ID for an item
|
||||
*
|
||||
* @param \IPS\Content\Searchable $object Item to add
|
||||
* @return string
|
||||
* @param Content $object Item to add
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIndexId( \IPS\Content\Searchable $object ): string
|
||||
public function getIndexId( Content $object ): mixed
|
||||
{
|
||||
$databaseColumnId = $object::$databaseColumnId;
|
||||
return \IPS\Db::i()->select( 'index_id', 'core_search_index', array( 'index_class=? AND index_object_id=?', \get_class( $object ),$object->$databaseColumnId ) )->first();
|
||||
return Db::i()->select( 'index_id', 'core_search_index', array( 'index_class=? AND index_object_id=?', get_class( $object ),$object->$databaseColumnId ) )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item
|
||||
*
|
||||
* @param \IPS\Content\Searchable $object Item to remove
|
||||
* @param Content $object Item to remove
|
||||
* @return void
|
||||
*/
|
||||
public function removeFromSearchIndex( \IPS\Content\Searchable $object )
|
||||
public function removeFromSearchIndex( Content $object ): void
|
||||
{
|
||||
$class = \get_class( $object );
|
||||
$class = get_class( $object );
|
||||
$idColumn = $class::$databaseColumnId;
|
||||
|
||||
/* Tags */
|
||||
$this->_deleteTagsFromIndex( $class, $object->$idColumn );
|
||||
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_object_id=?', $class, $object->$idColumn ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_object_id=?', $class, $object->$idColumn ) );
|
||||
|
||||
/* If this was a comment, we really need to reset the index_is_last_comment flag if it was set */
|
||||
if ( $object instanceof \IPS\Content\Comment )
|
||||
if ( $object instanceof Comment )
|
||||
{
|
||||
$itemClass = $object::$itemClass;
|
||||
$classes = array( $class );
|
||||
@@ -269,38 +290,38 @@ class _Index extends \IPS\Content\Search\Index
|
||||
|
||||
try
|
||||
{
|
||||
$this->resetLastComment( $classes, $object->mapped('item'), $object->$idColumn, $this->getFirstCommentId( $object ) );
|
||||
$this->resetLastComment( $classes, $object->mapped('item'), $object->$idColumn, null, $this->getFirstCommentId( $object ) );
|
||||
}
|
||||
catch( \Exception $ex ) { }
|
||||
catch( Exception ) { }
|
||||
|
||||
/* We need to see if this is the only comment the author has in this item and if so, remove their map */
|
||||
if ( ! \IPS\Db::i()->select( 'COUNT(*)', 'core_search_index', array( \IPS\Db::i()->in('index_class', $classes ) . ' and index_item_id=? and index_author=?', $object->mapped('item'), (int) $object->mapped('author') ) )->first() )
|
||||
if ( ! Db::i()->select( 'COUNT(*)', 'core_search_index', array( Db::i()->in('index_class', $classes ) . ' and index_item_id=? and index_author=?', $object->mapped('item'), (int) $object->mapped('author') ) )->first() )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? AND index_item_id=? and index_author_id=?', $itemClass, $object->mapped('item'), (int) $object->mapped('author') ) );
|
||||
Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? AND index_item_id=? and index_author_id=?', $itemClass, $object->mapped('item'), (int) $object->mapped('author') ) );
|
||||
}
|
||||
catch( \Exception $ex ) { }
|
||||
catch( Exception ) { }
|
||||
}
|
||||
}
|
||||
else if ( $object instanceof \IPS\Content\Item )
|
||||
else if ( $object instanceof Item )
|
||||
{
|
||||
/* Just remove all rows matching the item and class. */
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? AND index_item_id=?', $class, $object->$idColumn ) );
|
||||
Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? AND index_item_id=?', $class, $object->$idColumn ) );
|
||||
}
|
||||
|
||||
if ( isset( $class::$commentClass ) )
|
||||
{
|
||||
$commentClass = $class::$commentClass;
|
||||
$this->_deleteTagsFromIndex( $commentClass, $object->$idColumn );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $commentClass, $object->$idColumn ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $commentClass, $object->$idColumn ) );
|
||||
}
|
||||
|
||||
if ( isset( $class::$reviewClass ) )
|
||||
{
|
||||
$reviewClass = $class::$reviewClass;
|
||||
$this->_deleteTagsFromIndex( $reviewClass, $object->$idColumn );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $reviewClass, $object->$idColumn ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $reviewClass, $object->$idColumn ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,106 +332,84 @@ class _Index extends \IPS\Content\Search\Index
|
||||
* @param int $id ID
|
||||
* @return void
|
||||
*/
|
||||
public function directIndexRemoval( $class, $id )
|
||||
public function directIndexRemoval( string $class, int $id ): void
|
||||
{
|
||||
/* Tags */
|
||||
$this->_deleteTagsFromIndex( $class, $id );
|
||||
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_object_id=?', $class, $id ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_object_id=?', $class, $id ) );
|
||||
|
||||
/* If this was a comment, we really need to reset the index_is_last_comment flag if it was set */
|
||||
if ( is_subclass_of( $class, 'IPS\Content\Item' ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? AND index_item_id=?', $class, $id ) );
|
||||
Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? AND index_item_id=?', $class, $id ) );
|
||||
}
|
||||
|
||||
if ( isset( $class::$commentClass ) )
|
||||
{
|
||||
$commentClass = $class::$commentClass;
|
||||
$this->_deleteTagsFromIndex( $commentClass, $id );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $commentClass, $id ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $commentClass, $id ) );
|
||||
}
|
||||
|
||||
if ( isset( $class::$reviewClass ) )
|
||||
{
|
||||
$reviewClass = $class::$reviewClass;
|
||||
$this->_deleteTagsFromIndex( $reviewClass, $id );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $reviewClass, $id ) );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_class=? AND index_item_id=?', $reviewClass, $id ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index IDs associated with this class and $id
|
||||
*
|
||||
* @param \IPS\Content object $class The class
|
||||
* @param string $class The class
|
||||
* @param int $id The index_item_id
|
||||
* @return array
|
||||
*/
|
||||
protected function _deleteTagsFromIndex( $class, $id )
|
||||
protected function _deleteTagsFromIndex( string $class, int $id ): array
|
||||
{
|
||||
try
|
||||
{
|
||||
$ids = iterator_to_array( \IPS\Db::i()->select( 'index_id', 'core_search_index', array( 'index_class=? AND index_item_id=?', $class, $id ) ) );
|
||||
$ids = iterator_to_array( Db::i()->select( 'index_id', 'core_search_index', array( 'index_class=? AND index_item_id=?', $class, $id ) ) );
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
catch( Exception )
|
||||
{
|
||||
$ids = FALSE;
|
||||
}
|
||||
|
||||
if ( \is_array( $ids ) and \count( $ids ) < 1000 )
|
||||
if ( is_array( $ids ) and count( $ids ) < 1000 )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags', array( \IPS\Db::i()->in( 'index_id', $ids ) ) );
|
||||
Db::i()->delete( 'core_search_index_tags', array( Db::i()->in( 'index_id', $ids ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', \IPS\Db::i()->select( 'index_id', 'core_search_index', array( 'index_class=? AND index_item_id=?', $class, $id ) ) ) );
|
||||
Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', Db::i()->select( 'index_id', 'core_search_index', array( 'index_class=? AND index_item_id=?', $class, $id ) ) ) );
|
||||
}
|
||||
|
||||
return is_array( $ids ) ? $ids : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all content for a specific application from the index (for example, when uninstalling).
|
||||
*
|
||||
* @param \IPS\Application $application The application
|
||||
* @param Application $application The application
|
||||
* @return void
|
||||
*/
|
||||
public function removeApplicationContent( \IPS\Application $application )
|
||||
public function removeApplicationContent( Application $application ): void
|
||||
{
|
||||
$classes = array();
|
||||
|
||||
foreach ( $application->extensions( 'core', 'ContentRouter' ) as $router )
|
||||
foreach ( $application->extensions( 'core', 'SearchContent' ) as $extension )
|
||||
{
|
||||
foreach( $router->classes AS $class )
|
||||
{
|
||||
if ( is_subclass_of( $class, 'IPS\Content\Searchable' ) )
|
||||
{
|
||||
$classes[] = $class;
|
||||
|
||||
if ( isset( $class::$commentClass ) )
|
||||
{
|
||||
$commentClass = $class::$commentClass;
|
||||
if ( is_subclass_of( $commentClass, 'IPS\Content\Searchable' ) )
|
||||
{
|
||||
$classes[] = $commentClass;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $class::$reviewClass ) )
|
||||
{
|
||||
$reviewClass = $class::$reviewClass;
|
||||
if ( is_subclass_of( $reviewClass, 'IPS\Content\Searchable' ) )
|
||||
{
|
||||
$classes[] = $reviewClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$classes = array_merge( $classes, $extension::supportedClasses() );
|
||||
}
|
||||
|
||||
$where = array( \IPS\Db::i()->in( 'index_class', $classes ) );
|
||||
$where = array( Db::i()->in( 'index_class', $classes ) );
|
||||
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map', $where );
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', \IPS\Db::i()->select( 'index_id', 'core_search_index', $where ) ) );
|
||||
\IPS\Db::i()->delete( 'core_search_index', $where );
|
||||
Db::i()->delete( 'core_search_index_item_map', $where );
|
||||
Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', Db::i()->select( 'index_id', 'core_search_index', $where ) ) );
|
||||
Db::i()->delete( 'core_search_index', $where );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -421,7 +420,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
* @param int|NULL $authorId The author ID to delete, or NULL
|
||||
* @return void
|
||||
*/
|
||||
public function removeClassFromSearchIndex( $class, $containerId=NULL, $authorId=NULL )
|
||||
public function removeClassFromSearchIndex( string $class, int|null $containerId=null, int|null $authorId=NULL ): void
|
||||
{
|
||||
$where = array( array( 'index_class=?', $class ) );
|
||||
if ( $containerId !== NULL )
|
||||
@@ -433,9 +432,9 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$where[] = array( 'index_author=?', $authorId );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? and index_item_id IN( ? )', $class, \IPS\Db::i()->select( 'index_item_id', 'core_search_index', $where ) ) );
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', \IPS\Db::i()->select( 'index_id', 'core_search_index', $where ) ) );
|
||||
\IPS\Db::i()->delete( 'core_search_index', $where );
|
||||
Db::i()->delete( 'core_search_index_item_map', array( 'index_class=? and index_item_id IN( ? )', $class, Db::i()->select( 'index_item_id', 'core_search_index', $where ) ) );
|
||||
Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', Db::i()->select( 'index_id', 'core_search_index', $where ) ) );
|
||||
Db::i()->delete( 'core_search_index', $where );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -453,8 +452,13 @@ class _Index extends \IPS\Content\Search\Index
|
||||
* @param bool $addAuthorToPermissions If true, the index_author_id will be added to $newPermissions - used when changing the permissions for a node which allows access only to author's items
|
||||
* @return void
|
||||
*/
|
||||
public function massUpdate( $class, $containerId = NULL, $itemId = NULL, $newPermissions = NULL, $newHiddenStatus = NULL, $newContainer = NULL, $authorId = NULL, $newItemId = NULL, $newItemAuthorId = NULL, $addAuthorToPermissions = FALSE )
|
||||
public function massUpdate( string $class, int|null $containerId = null, int|null $itemId = NULL, string|null $newPermissions = NULL, int|null $newHiddenStatus = NULL, int|null $newContainer = NULL, int|null $authorId = NULL, int|null $newItemId = NULL, int|null $newItemAuthorId = NULL, bool $addAuthorToPermissions = FALSE ): void
|
||||
{
|
||||
if( !Content\Search\SearchContent::isSearchable( $class) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$where = array( array( 'index_class=?', $class ) );
|
||||
if ( $containerId !== NULL )
|
||||
{
|
||||
@@ -478,13 +482,13 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
$update['index_container_id'] = $newContainer;
|
||||
|
||||
if ( $itemClass = ( \in_array( 'IPS\Content\Item', class_parents( $class ) ) ? $class : $class::$itemClass ) and $containerClass = $itemClass::$containerNodeClass and \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) and $clubIdColumn = $containerClass::clubIdColumn() )
|
||||
if ( $itemClass = ( in_array( 'IPS\Content\Item', class_parents( $class ) ) ? $class : $class::$itemClass ) and $containerClass = $itemClass::$containerNodeClass and IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) and $clubIdColumn = $containerClass::clubIdColumn() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$update['index_club_id'] = $containerClass::load( $newContainer )->$clubIdColumn;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch ( OutOfRangeException )
|
||||
{
|
||||
$update['index_club_id'] = NULL;
|
||||
}
|
||||
@@ -499,15 +503,15 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$update['index_item_author'] = $newItemAuthorId;
|
||||
}
|
||||
|
||||
if ( \count( $update ) )
|
||||
if ( count( $update ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_search_index', $update, $where );
|
||||
Db::i()->update( 'core_search_index', $update, $where );
|
||||
}
|
||||
if ( $addAuthorToPermissions )
|
||||
{
|
||||
$addAuthorToPermissionsWhere = $where;
|
||||
$addAuthorToPermissionsWhere[] = array( 'index_author<>0' );
|
||||
\IPS\Db::i()->update( 'core_search_index', "index_permissions = CONCAT( index_permissions, ',m', index_author )", $addAuthorToPermissionsWhere );
|
||||
Db::i()->update( 'core_search_index', "index_permissions = CONCAT( index_permissions, ',m', index_author )", $addAuthorToPermissionsWhere );
|
||||
}
|
||||
|
||||
if ( $newHiddenStatus !== NULL )
|
||||
@@ -521,7 +525,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$where[] = array( 'index_hidden=2' );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_hidden' => $newHiddenStatus ), $where );
|
||||
Db::i()->update( 'core_search_index', array( 'index_hidden' => $newHiddenStatus ), $where );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,10 +533,10 @@ class _Index extends \IPS\Content\Search\Index
|
||||
* Update data for the first and last comment after a merge
|
||||
* Sets index_is_last_comment on the last comment, and, if this is an item where the first comment is indexed rather than the item, sets index_title and index_tags on the first comment
|
||||
*
|
||||
* @param \IPS\Content\Item $item The item
|
||||
* @param Item $item The item
|
||||
* @return void
|
||||
*/
|
||||
public function rebuildAfterMerge( \IPS\Content\Item $item )
|
||||
public function rebuildAfterMerge( Item $item ): void
|
||||
{
|
||||
if ( $item::$commentClass )
|
||||
{
|
||||
@@ -545,7 +549,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
{
|
||||
$update['index_title'] = NULL;
|
||||
}
|
||||
\IPS\Db::i()->update( 'core_search_index', $update, array( 'index_class=? AND index_item_id=?', $item::$commentClass, $item->$idColumn ) );
|
||||
Db::i()->update( 'core_search_index', $update, array( 'index_class=? AND index_item_id=?', $item::$commentClass, $item->$idColumn ) );
|
||||
|
||||
if ( $firstComment )
|
||||
{
|
||||
@@ -561,22 +565,22 @@ class _Index extends \IPS\Content\Search\Index
|
||||
/**
|
||||
* Prune search index
|
||||
*
|
||||
* @param \IPS\DateTime|NULL $cutoff The date to delete index records from, or NULL to delete all
|
||||
* @param DateTime|NULL $cutoff The date to delete index records from, or NULL to delete all
|
||||
* @return void
|
||||
*/
|
||||
public function prune( \IPS\DateTime $cutoff = NULL )
|
||||
public function prune( DateTime|null $cutoff = NULL ): void
|
||||
{
|
||||
if ( $cutoff )
|
||||
{
|
||||
\IPS\Db::i()->delete( array( 'core_search_index_item_map', 'core_search_index' ), array( "core_search_index_item_map.index_item_id=core_search_index.index_item_id AND (core_search_index.index_id=core_search_index.index_item_index_id AND index_date_updated < ?)", $cutoff->getTimestamp() ), NULL, NULL, NULL, 'core_search_index_item_map' );
|
||||
\IPS\Db::i()->delete( array( 'core_search_index_tags', 'core_search_index' ), array( "core_search_index_tags.index_id=core_search_index.index_id AND (core_search_index.index_id=core_search_index.index_item_index_id AND index_date_updated < ?)", $cutoff->getTimestamp() ), NULL, NULL, NULL, 'core_search_index_tags' );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) );
|
||||
Db::i()->delete( array( 'core_search_index_item_map', 'core_search_index' ), array( "core_search_index_item_map.index_item_id=core_search_index.index_item_id AND (core_search_index.index_id=core_search_index.index_item_index_id AND index_date_updated < ?)", $cutoff->getTimestamp() ), NULL, NULL, NULL, 'core_search_index_item_map' );
|
||||
Db::i()->delete( array( 'core_search_index_tags', 'core_search_index' ), array( "core_search_index_tags.index_id=core_search_index.index_id AND (core_search_index.index_id=core_search_index.index_item_index_id AND index_date_updated < ?)", $cutoff->getTimestamp() ), NULL, NULL, NULL, 'core_search_index_tags' );
|
||||
Db::i()->delete( 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index_item_map' );
|
||||
\IPS\Db::i()->delete( 'core_search_index_tags' );
|
||||
\IPS\Db::i()->delete( 'core_search_index' );
|
||||
Db::i()->delete( 'core_search_index_item_map' );
|
||||
Db::i()->delete( 'core_search_index_tags' );
|
||||
Db::i()->delete( 'core_search_index' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,72 +590,71 @@ class _Index extends \IPS\Content\Search\Index
|
||||
* @param array $classes The classes (when first post is required, this is typically just \IPS\forums\Topic\Post but for others, it will be both item and comment classes)
|
||||
* @param int|NULL $indexItemId The index item ID
|
||||
* @param int|NULL $ignoreId ID to ignore because it is being removed
|
||||
* @param int|null $firstCommentId The first comment in this item, used only if $firstCommentRequired
|
||||
* @param int|null $firstCommentId The first comment in this item, used only if $firstCommentRequired
|
||||
* @return void
|
||||
*/
|
||||
public function resetLastComment( $classes, $indexItemId, $ignoreId = NULL, $firstCommentId = NULL )
|
||||
public function resetLastComment( array $classes, int|null $indexItemId, int|null $ignoreId = null, int|null $firstCommentId=null ): void
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexItemId ) );
|
||||
Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexItemId ) );
|
||||
try
|
||||
{
|
||||
$latest = \IPS\Db::i()->select( 'index_object_id, index_date_updated, index_class, index_date_commented', 'core_search_index', array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_hidden=0', $indexItemId ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
$latest = Db::i()->select( 'index_object_id, index_date_updated, index_class', 'core_search_index', array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_hidden=0', $indexItemId ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
}
|
||||
catch( \Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
/* Didn't find a latest? Was it because the entire thing is hidden? */
|
||||
try
|
||||
{
|
||||
$index = \IPS\Db::i()->select( 'index_id, index_item_index_id, index_hidden', 'core_search_index', array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=?', $indexItemId ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
$index = Db::i()->select( 'index_id, index_item_index_id, index_hidden', 'core_search_index', array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=?', $indexItemId ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
|
||||
/* Is the root item hidden? */
|
||||
if ( $index['index_id'] == $index['index_item_index_id'] and in_array( $index['index_hidden'], [ -1, 2 ] ) )
|
||||
{
|
||||
$latest = \IPS\Db::i()->select( 'index_object_id, index_date_updated, index_class, index_date_commented', 'core_search_index', array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_hidden=?', $indexItemId, $index['index_hidden'] ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
$latest = Db::i()->select( 'index_object_id, index_date_updated, index_class, index_date_commented', 'core_search_index', array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_hidden=?', $indexItemId, $index['index_hidden'] ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, so we can't find a latest item that is hidden, so skip this */
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch( \Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 1 ), array( 'index_class=? AND index_object_id=?', $latest['index_class'], $latest['index_object_id'] ) );
|
||||
Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 1 ), array( 'index_class=? AND index_object_id=?', $latest['index_class'], $latest['index_object_id'] ) );
|
||||
|
||||
/* Now reset the item index with the latest comment time */
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_date_updated' => $latest['index_date_updated'], 'index_date_commented' => $latest['index_date_commented'] ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_object_id=?', $indexItemId, ( $firstCommentId ?? $indexItemId ) ) );
|
||||
|
||||
Db::i()->update( 'core_search_index', array( 'index_date_updated' => $latest['index_date_updated'], 'index_date_commented' => $latest['index_date_commented'] ), array( Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_object_id=?', $indexItemId, ( $firstCommentId ?? $indexItemId ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of item index IDs, return the ones that a given member has participated in
|
||||
*
|
||||
* @param array $itemIndexIds Item index IDs
|
||||
* @param \IPS\Member $member The member
|
||||
* @param Member $member The member
|
||||
* @return array
|
||||
*/
|
||||
public function iPostedIn( array $itemIndexIds, \IPS\Member $member )
|
||||
public function iPostedIn( array $itemIndexIds, Member $member ): array
|
||||
{
|
||||
return iterator_to_array( \IPS\Db::i()->select( 'index_item_index_id', 'core_search_index', array( array( \IPS\Db::i()->in( 'index_item_index_id', $itemIndexIds ) ), array( 'index_author=?', $member->member_id ) ) )->setKeyField('index_item_index_id') );
|
||||
return iterator_to_array( Db::i()->select( 'index_item_index_id', 'core_search_index', array( array( Db::i()->in( 'index_item_index_id', $itemIndexIds ) ), array( 'index_author=?', $member->member_id ) ) )->setKeyField('index_item_index_id') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of "index_class_type_id_hash"s, return the ones that a given member has permission to view
|
||||
*
|
||||
* @param array $itemIndexIds Item index IDs
|
||||
* @param \IPS\Member $member The member
|
||||
* @param array $hashes Item index IDs
|
||||
* @param Member $member The member
|
||||
* @param int|NULL $limit Number of results to return
|
||||
* @return array
|
||||
*/
|
||||
public function hashesWithPermission( array $hashes, \IPS\Member $member, $limit = NULL )
|
||||
public function hashesWithPermission( array $hashes, Member $member, int|null $limit = null ): array
|
||||
{
|
||||
return iterator_to_array( \IPS\Db::i()->select( 'index_class_type_id_hash', array( 'core_search_index', 'si' ), array(
|
||||
array( "( si.index_permissions = '*' OR " . \IPS\Db::i()->findInSet( 'si.index_permissions', \IPS\Member::loggedIn()->permissionArray() ) . ' AND si.index_hidden=0 )' ),
|
||||
array( \IPS\Db::i()->in( 'si.index_class_type_id_hash', $hashes ) )
|
||||
return iterator_to_array( Db::i()->select( 'index_class_type_id_hash', array( 'core_search_index', 'si' ), array(
|
||||
array( "( si.index_permissions = '*' OR " . Db::i()->findInSet( 'si.index_permissions', Member::loggedIn()->permissionArray() ) . ' AND si.index_hidden=0 )' ),
|
||||
array( Db::i()->in( 'si.index_class_type_id_hash', $hashes ) )
|
||||
), NULL, $limit )->setKeyField('index_class_type_id_hash') );
|
||||
}
|
||||
|
||||
@@ -660,8 +663,8 @@ class _Index extends \IPS\Content\Search\Index
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function firstIndexDate()
|
||||
public function firstIndexDate(): int|NULL
|
||||
{
|
||||
return \IPS\Db::i()->select( 'MIN(index_date_updated)', 'core_search_index' )->first();
|
||||
return Db::i()->select( 'MIN(index_date_updated)', 'core_search_index' )->first();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user