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
+72
-68
@@ -13,10 +13,17 @@ namespace IPS\Node;
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use Exception;
|
||||
use IPS\Content\Comment;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Db;
|
||||
use IPS\Member;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function is_array;
|
||||
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -28,7 +35,7 @@ trait Statistics
|
||||
/**
|
||||
* @brief Cached array of IDs a member has posted in
|
||||
*/
|
||||
protected $authorsPostedIn = array();
|
||||
protected array $authorsPostedIn = array();
|
||||
|
||||
/**
|
||||
* Get authors posted in
|
||||
@@ -36,7 +43,7 @@ trait Statistics
|
||||
* @param array $inSet The item_ids to check
|
||||
* @return array
|
||||
*/
|
||||
public function authorsPostedIn( array $inSet )
|
||||
public function authorsPostedIn( array $inSet ): array
|
||||
{
|
||||
if ( !isset( static::$contentItemClass ) )
|
||||
{
|
||||
@@ -59,12 +66,12 @@ trait Statistics
|
||||
return array();
|
||||
}
|
||||
|
||||
$items = iterator_to_array( \IPS\Db::i()->select( 'map_item_id, map_member_id', 'core_item_member_map', array( array( 'map_class=?', $contentItemClass ), array( \IPS\Db::i()->in( 'map_item_id', $inSet ) ) ) ) );
|
||||
$items = iterator_to_array( Db::i()->select( 'map_item_id, map_member_id', 'core_item_member_map', array( array( 'map_class=?', $contentItemClass ), array( Db::i()->in( 'map_item_id', $inSet ) ) ) ) );
|
||||
$reload = FALSE;
|
||||
$itemIds = array();
|
||||
|
||||
/* Do we have the items we need? */
|
||||
if ( \count( $items ) )
|
||||
if ( count( $items ) )
|
||||
{
|
||||
foreach ( $items as $row )
|
||||
{
|
||||
@@ -73,7 +80,7 @@ trait Statistics
|
||||
|
||||
$diff = array_diff( $inSet, $itemIds );
|
||||
|
||||
if ( \count( $diff ) )
|
||||
if ( count( $diff ) )
|
||||
{
|
||||
$reload = TRUE;
|
||||
$this->rebuildPostedIn( $diff );
|
||||
@@ -89,10 +96,10 @@ trait Statistics
|
||||
/* Do we need to reload? */
|
||||
if ( $reload )
|
||||
{
|
||||
$items = iterator_to_array( \IPS\Db::i()->select( 'map_item_id, map_member_id', 'core_item_member_map', array(array('map_class=?', $contentItemClass), array(\IPS\Db::i()->in( 'map_item_id', $inSet ) ) ) ) );
|
||||
$items = iterator_to_array( Db::i()->select( 'map_item_id, map_member_id', 'core_item_member_map', array(array('map_class=?', $contentItemClass), array(Db::i()->in( 'map_item_id', $inSet ) ) ) ) );
|
||||
$itemIds = [];
|
||||
|
||||
if ( \count( $items ) )
|
||||
if ( count( $items ) )
|
||||
{
|
||||
foreach ( $items as $row )
|
||||
{
|
||||
@@ -105,11 +112,11 @@ trait Statistics
|
||||
/* Check to see if there are any item IDs that can't be set because of missing posts, etc. This prevents an attempted rebuild from occuring over and over again */
|
||||
$diff = array_diff( $inSet, $itemIds );
|
||||
|
||||
if ( \count( $diff ) )
|
||||
if ( count( $diff ) )
|
||||
{
|
||||
foreach( $diff as $id )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_item_member_map', array( 'map_class' => $contentItemClass, 'map_item_id' => $id, 'map_member_id' => NULL ), TRUE );
|
||||
Db::i()->replace( 'core_item_member_map', array( 'map_class' => $contentItemClass, 'map_item_id' => $id, 'map_member_id' => NULL ), TRUE );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,22 +136,22 @@ trait Statistics
|
||||
/**
|
||||
* @brief Cached array of IDs a member has posted in (calculated the expensive way so cached separately)
|
||||
*/
|
||||
protected $contentPostedIn = array();
|
||||
protected array $contentPostedIn = array();
|
||||
|
||||
/**
|
||||
* Retrieve an array of IDs a member has posted in.
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member (NULL for currently logged in member)
|
||||
* @param array|NULL $inSet If supplied, checks will be restricted to only the ids provided
|
||||
* @param array|NULL $additionalWhere Additional where clause
|
||||
* @param array|NULL $commentJoinWhere Additional join clause for comments table
|
||||
* @param Member|null $member The member (NULL for currently logged in member)
|
||||
* @param array|null $inSet If supplied, checks will be restricted to only the ids provided
|
||||
* @param array|null $additionalWhere Additional where clause
|
||||
* @param array|null $commentJoinWhere Additional join clause for comments table
|
||||
* @return array An array of content item ids
|
||||
*/
|
||||
public function contentPostedIn( $member=NULL, $inSet=NULL, $additionalWhere=NULL, $commentJoinWhere=NULL )
|
||||
public function contentPostedIn(Member $member=NULL, array $inSet=NULL, array $additionalWhere=NULL, array $commentJoinWhere=NULL ): array
|
||||
{
|
||||
if ( $member === NULL )
|
||||
{
|
||||
$member = \IPS\Member::loggedIn();
|
||||
$member = Member::loggedIn();
|
||||
}
|
||||
|
||||
if( !$member->member_id )
|
||||
@@ -157,7 +164,7 @@ trait Statistics
|
||||
return array();
|
||||
}
|
||||
|
||||
if ( \is_array( $inSet ) AND $additionalWhere === NULL AND $commentJoinWhere === NULL )
|
||||
if ( is_array( $inSet ) AND $additionalWhere === NULL AND $commentJoinWhere === NULL )
|
||||
{
|
||||
/* Hooray, the easy efficient way */
|
||||
$members = $this->authorsPostedIn( $inSet );
|
||||
@@ -172,7 +179,10 @@ trait Statistics
|
||||
else
|
||||
{
|
||||
/* The complicated way, which doesn't happen that often */
|
||||
/* @var Item $contentItemClass */
|
||||
$contentItemClass = static::$contentItemClass;
|
||||
|
||||
/* @var Comment $commentClass */
|
||||
$commentClass = $contentItemClass::$commentClass;
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$_key = md5( $member->member_id . json_encode( $inSet ) );
|
||||
@@ -184,6 +194,7 @@ trait Statistics
|
||||
|
||||
$where = array();
|
||||
|
||||
/* @var array $databaseColumnMap */
|
||||
if ( $contentItemClass::$firstCommentRequired )
|
||||
{
|
||||
$where[] = array( '(' . $commentClass::$databaseTable . '.' . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'] . '=? )', $member->member_id );
|
||||
@@ -194,7 +205,7 @@ trait Statistics
|
||||
$where[] = array( '(' . $commentClass::$databaseTable . '.' . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'] . '=? OR ' . $contentItemClass::$databaseTable . '.' . $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnMap['author'] . '=?)', $member->member_id, $member->member_id );
|
||||
}
|
||||
|
||||
if( \is_array( $inSet ) AND \count( $inSet ) )
|
||||
if( is_array( $inSet ) AND count( $inSet ) )
|
||||
{
|
||||
$where[] = array( $contentItemClass::$databaseTable . '.' . $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnId . ' IN(' . implode( ',', $inSet ) . ')' );
|
||||
}
|
||||
@@ -206,7 +217,7 @@ trait Statistics
|
||||
|
||||
$joinClause = array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['item'] . '=' . $contentItemClass::$databaseTable . '.' . $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnId );
|
||||
|
||||
$items = \IPS\Db::i()->select( $contentItemClass::$databaseTable . '.' . $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnId, $contentItemClass::$databaseTable, $where, NULL, NULL, NULL, NULL, \IPS\Db::SELECT_DISTINCT );
|
||||
$items = Db::i()->select( $contentItemClass::$databaseTable . '.' . $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnId, $contentItemClass::$databaseTable, $where, NULL, NULL, NULL, NULL, Db::SELECT_DISTINCT );
|
||||
$items->join( $commentClass::$databaseTable, ( $commentJoinWhere !== NULL ) ? array( $joinClause, $commentJoinWhere ) : $joinClause );
|
||||
|
||||
$ids = array();
|
||||
@@ -227,30 +238,32 @@ trait Statistics
|
||||
* Note that we do fetch guests content here. That is to prevent content from being rebuilt on each click if it solely populated by guests
|
||||
*
|
||||
* @param array $inSet Array of item IDs
|
||||
* @param array $members Optional array of member objects to limit by
|
||||
* @param array $members Optional array of member objects to limit by\
|
||||
* @return void
|
||||
*/
|
||||
public function rebuildPostedIn( array $inSet, $members=array() )
|
||||
public function rebuildPostedIn( array $inSet, array $members=array() ) : void
|
||||
{
|
||||
/* @var array $databaseColumnMap */
|
||||
$contentItemClass = static::$contentItemClass;
|
||||
$commentClass = $contentItemClass::$commentClass;
|
||||
$commentItemField = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['item'];
|
||||
$authorColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'];
|
||||
$where = array();
|
||||
$memberIds = array();
|
||||
|
||||
$deleteWhere = array( array( \IPS\Db::i()->in( 'map_item_id', $inSet ) ) );
|
||||
if ( \count( $members ) )
|
||||
$deleteWhere = array( array( Db::i()->in( 'map_item_id', $inSet ) ) );
|
||||
if ( count( $members ) )
|
||||
{
|
||||
$memberIds = array();
|
||||
foreach ( $members as $member )
|
||||
{
|
||||
$memberIds[] = $member->member_id;
|
||||
}
|
||||
|
||||
$where[] = array(\IPS\Db::i()->in( $authorColumn, $memberIds ));
|
||||
$deleteWhere[] = array( \IPS\Db::i()->in( 'map_member_id', $memberIds ) );
|
||||
$where[] = array(Db::i()->in( $authorColumn, $memberIds ));
|
||||
$deleteWhere[] = array( Db::i()->in( 'map_member_id', $memberIds ) );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_item_member_map', $deleteWhere );
|
||||
Db::i()->delete( 'core_item_member_map', $deleteWhere );
|
||||
|
||||
/* Do the item first if the first comment is not required */
|
||||
if ( ! $contentItemClass::$firstCommentRequired )
|
||||
@@ -261,18 +274,38 @@ trait Statistics
|
||||
if ( isset( $contentItemClass::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$approvedColumn = $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnMap['approved'];
|
||||
$itemWhere[] = array( \IPS\Db::i()->in( $approvedColumn, array( 1, 2 ) ) ); # We want approved comments but also comments hidden because the item is hidden
|
||||
$itemWhere[] = array( Db::i()->in( $approvedColumn, array( 1, 2 ) ) ); # We want approved comments but also comments hidden because the item is hidden
|
||||
}
|
||||
if ( isset( $contentItemClass::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$hiddenColumn = $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnMap['hidden'];
|
||||
$itemWhere[] = array( \IPS\Db::i()->in( $hiddenColumn, array( 0, 2 ) ) ); # We want approved comments but also comments hidden because the item is hidden
|
||||
$itemWhere[] = array( Db::i()->in( $hiddenColumn, array( 0, 2 ) ) ); # We want approved comments but also comments hidden because the item is hidden
|
||||
}
|
||||
|
||||
$itemWhere[] = array( \IPS\Db::i()->in( $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnId, $inSet ) );
|
||||
$itemWhere[] = array( Db::i()->in( $contentItemClass::$databasePrefix . $contentItemClass::$databaseColumnId, $inSet ) );
|
||||
|
||||
$insertFromSelect = \IPS\Db::i()->select( "'" . str_replace( '\\', '\\\\', $contentItemClass ) . "', `{$contentItemClass::$databasePrefix}{$contentItemClass::$databaseColumnId}`, `{$itemAuthorColumn}`, `{$itemDateColumn}`" , $contentItemClass::$databaseTable, $itemWhere );
|
||||
\IPS\Db::i()->replace( 'core_item_member_map', $insertFromSelect, TRUE );
|
||||
try
|
||||
{
|
||||
$seen = array();
|
||||
/* We don't want a complex query on a large table (forums_posts) hitting a write server, so split this for forums to select (read server) and insert (write server) */
|
||||
foreach( Db::i()->select( "`{$authorColumn}`, `{$commentItemField}`", $commentClass::$databaseTable, $where, NULL, 1 ) as $row )
|
||||
{
|
||||
$key = $row[ $authorColumn ] . '_' . $row[ $commentItemField ];
|
||||
if ( isset( $seen[ $key ] ) or ! $row[ $authorColumn ] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$seen[ $key ] = true;
|
||||
|
||||
Db::i()->insert( 'core_item_member_map', [
|
||||
'map_member_id' => $row[ $authorColumn ],
|
||||
'map_item_id' => $row[ $commentItemField ],
|
||||
'map_latest_date' => time(),
|
||||
'map_class' => $contentItemClass
|
||||
] );
|
||||
}
|
||||
}
|
||||
catch( Exception ) { }
|
||||
}
|
||||
|
||||
/* If forums are being used for Pages comments, we don't want to look at those */
|
||||
@@ -285,12 +318,12 @@ trait Statistics
|
||||
if ( isset( $commentClass::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$approvedColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['approved'];
|
||||
$where[] = array(\IPS\Db::i()->in( $approvedColumn, array(1, 2) )); # We want approved comments but also comments hidden because the item is hidden
|
||||
$where[] = array(Db::i()->in( $approvedColumn, array(1, 2) )); # We want approved comments but also comments hidden because the item is hidden
|
||||
}
|
||||
if ( isset( $commentClass::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$hiddenColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['hidden'];
|
||||
$where[] = array(\IPS\Db::i()->in( $hiddenColumn, array(0, 2) )); # We want approved comments but also comments hidden because the item is hidden
|
||||
$where[] = array(Db::i()->in( $hiddenColumn, array(0, 2) )); # We want approved comments but also comments hidden because the item is hidden
|
||||
}
|
||||
|
||||
if ( $commentClass::commentWhere() !== NULL )
|
||||
@@ -298,39 +331,10 @@ trait Statistics
|
||||
$where[] = $commentClass::commentWhere();
|
||||
}
|
||||
|
||||
$where[] = array(\IPS\Db::i()->in( $commentItemField, $inSet ));
|
||||
$where[] = array(Db::i()->in( $commentItemField, $inSet ));
|
||||
|
||||
try
|
||||
{
|
||||
$seen = array();
|
||||
|
||||
/* If we don't have member(s) in the where clause, or we have a lot of member ids in the where clause, we can't do individual inserts as this could be 10,000+ inserts on very large topics */
|
||||
if ( ! count( $memberIds ) or ( count( $memberIds ) > 100 ) )
|
||||
{
|
||||
$insertFromSelect = \IPS\Db::i()->select( "DISTINCT `{$authorColumn}`, `{$commentItemField}`, UNIX_TIMESTAMP(), '" . str_replace( '\\', '\\\\', $contentItemClass ) . "'", $commentClass::$databaseTable, $where );
|
||||
\IPS\Db::i()->replace( 'core_item_member_map', [ 'map_member_id, map_item_id, map_latest_date, map_class', $insertFromSelect ], TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( "DISTINCT `{$authorColumn}` as {$authorColumn}, `{$commentItemField}`", $commentClass::$databaseTable, $where ) as $row )
|
||||
{
|
||||
$key = $row[ $authorColumn ] . '_' . $row[ $commentItemField ];
|
||||
if ( isset( $seen[ $key ] ) or ! $row[ $authorColumn ] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$seen[ $key ] = true;
|
||||
|
||||
\IPS\Db::i()->insert( 'core_item_member_map', [
|
||||
'map_member_id' => $row[ $authorColumn ],
|
||||
'map_item_id' => $row[ $commentItemField ],
|
||||
'map_latest_date' => time(),
|
||||
'map_class' => $contentItemClass
|
||||
] );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception ) { }
|
||||
$insertFromSelect = Db::i()->select( "DISTINCT `{$authorColumn}`, `{$commentItemField}`, UNIX_TIMESTAMP(), '" . str_replace( '\\', '\\\\', $contentItemClass ) . "'", $commentClass::$databaseTable, $where );
|
||||
Db::i()->replace( 'core_item_member_map', [ 'map_member_id, map_item_id, map_latest_date, map_class', $insertFromSelect ], TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user