Version 4.7.23

This commit is contained in:
Neo committed 2025-12-19 16:21:27 -08:00
1 parent 7124a02564
commit 25ddeb65d6
1791 files changed
+76990 -44452

No files matched your search

+106 -25
View File
@@ -13,6 +13,8 @@ namespace IPS\Content;
/* To prevent PHP errors (extending class does not exist) revealing path */
use http\Exception\BadMethodCallException;
use function array_merge;
use function implode;
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
@@ -50,7 +52,7 @@ trait Statistics
*/
public function imageAttachments( $count = 10 ): array
{
$attachments = $this->_getAllAttachments( array( 'attach_is_image=1' ), $count, 'attach_date DESC' );
$attachments = $this->_getAllAttachments( array( 'attach_is_image=1' ), $count, 'attachment_id DESC' );
$attachments = \array_slice( $attachments, 0, $count );
return $attachments;
@@ -120,11 +122,12 @@ trait Statistics
/**
* Most Recent Participans
*
* @param string|NULL $name If we are looking for a specific user.
* @param int $limit The amount of results to return.
* @param string|NULL $name If we are looking for a specific user.
* @param int $limit The amount of results to return.
* @param bool $incBanned Include banned members? (Used to exclude from recent mentions)
* @return \IPS\Patterns\ActiveRecordIterator
*/
public function mostRecent( ?string $name = NULL, int $limit = 10 )
public function mostRecent( ?string $name = NULL, int $limit = 10, bool $incBanned = TRUE )
{
$commentClass = static::$commentClass;
@@ -135,11 +138,11 @@ trait Statistics
if ( $name )
{
$cacheKey = 'mostRecent_' . $limit . '_' . $name;
$cacheKey = 'mostRecent_' . $limit . '_' . $name . '_' . (int) $incBanned;
}
else
{
$cacheKey = 'mostRecent_' . $limit;
$cacheKey = 'mostRecent_' . $limit . '_' . (int) $incBanned;
}
try
@@ -152,7 +155,13 @@ trait Statistics
$where = $this->_getVisibleWhere();
if ( $name )
{
$subQuery = \IPS\Db::i()->select( 'core_members.member_id', 'core_members', \IPS\Db::i()->like( 'core_members.name', $name ) );
$subWhere = array();
$subWhere[] = \IPS\Db::i()->like( 'core_members.name', $name );
if ( !$incBanned )
{
$subWhere[] = array( "core_members.temp_ban=?", 0 );
}
$subQuery = \IPS\Db::i()->select( 'core_members.member_id', 'core_members', $subWhere );
$where[] = [ $commentClass::$databaseTable . '.' . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'] . ' IN(?)', $subQuery ];
}
@@ -299,13 +308,22 @@ trait Statistics
/**
* Clear any cached stats
*
* @param bool $force Force immediate cache delete
* @return void
* @throws \Exception
*/
public function clearCachedStatistics()
public function clearCachedStatistics( bool $force=FALSE )
{
$idField = static::$databaseColumnId;
\IPS\Db::i()->delete( 'core_item_statistics_cache', array( 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ) );
if( $force )
{
\IPS\Db::i()->delete( 'core_item_statistics_cache', [ 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ] );
}
else
{
/* Set cache to time out in 10 minutes. */
\IPS\Db::i()->update( 'core_item_statistics_cache', [ 'cache_added' => ( time() - 172200 ) ], [ 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ] );
}
}
/**
@@ -334,7 +352,13 @@ trait Statistics
}
catch( \OutOfRangeException $e )
{
$where = array( array( 'location_key=? and id1=? and id2 IN(?)', static::$application . '_' . mb_ucfirst( static::$module ), $this->$idField, $this->_subQueryVisibleComments( $this->$idField ) ) );
/* This is more efficient and avoids a very slow table join */
if ( \stristr( $orderBy, 'attach_date' ) )
{
$orderBy = str_replace( 'attach_date', 'attachment_id', $orderBy );
}
$where = array( array( 'location_key=? and id1=?', static::$application . '_' . mb_ucfirst( static::$module ), $this->$idField ) );
if ( $extraWhere !== NULL )
{
@@ -342,7 +366,24 @@ trait Statistics
}
/* Get attachments from all comments */
$return = iterator_to_array( \IPS\Db::i()->select( '*', 'core_attachments_map', $where, $orderBy, $limit )->join( 'core_attachments', array( 'attach_id=attachment_id' ) ) );
$commentClass = static::$commentClass;
$commentTableJoin = [ 'id2=' . $commentClass::$databasePrefix . $commentClass::$databaseColumnId ];
if ( isset( $commentClass::$databaseColumnMap['approved'] ) )
{
$approvedColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['approved'];
$commentTableJoin[] = "{$approvedColumn} = 1";
}
if ( isset( $commentClass::$databaseColumnMap['hidden'] ) )
{
$hiddenColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['hidden'];
$commentTableJoin[] = "{$hiddenColumn} = 0";
}
$return = iterator_to_array(
\IPS\Db::i()->select( '*', 'core_attachments_map', $where, $orderBy, $limit )
->join( 'core_attachments', array( 'attach_id=attachment_id' ) )
->join( $commentClass::$databaseTable, array( implode( ' AND ', $commentTableJoin ) ), 'INNER' )
);
/* Get link to comments */
foreach( $return as $k => $map )
@@ -443,6 +484,11 @@ trait Statistics
*/
static $cachedActivity = NULL;
/**
* @var bool|null Process has rebuild lock
*/
protected ?bool $hasRebuildLock = NULL;
/**
* Get the cached data
*
@@ -453,28 +499,57 @@ trait Statistics
protected function _getCached( $key )
{
$idField = static::$databaseColumnId;
if( $this->hasRebuildLock === FALSE )
{
return [];
}
$class = \get_class( $this );
$arrayKey = $class.'.'.$this->$idField;
if ( !isset( static::$cachedActivity[$arrayKey] ) )
$arrayKey = $class . '.' . $this->$idField;
if ( !isset( static::$cachedActivity[ $arrayKey ] ) )
{
try
{
$cache = \IPS\Db::i()->select( '*', 'core_item_statistics_cache', array( 'cache_class=? and cache_item_id=?', $class, $this->$idField ) )->first();
if ( $cache['cache_added'] > time() - 86400 )
$cache = \IPS\Db::i()->select( '*', 'core_item_statistics_cache', [ 'cache_class=? and cache_item_id=?', $class, $this->$idField ] )->first();
if ( $cache['cache_added'] > ( time() - 172800 ) )
{
static::$cachedActivity[ $arrayKey ] = json_decode( $cache['cache_contents'], TRUE );
}
else
{
\IPS\Db::i()->delete( 'core_item_statistics_cache', array( 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ) );
$this->hasRebuildLock = TRUE;
$affectedRows = \IPS\Db::i()->delete( 'core_item_statistics_cache', [ 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ] );
if( $affectedRows == 0 )
{
/* We did not delete the row, allow another process to rebuild the cache */
$this->hasRebuildLock = FALSE;
return [];
}
}
}
catch( \UnderflowException $e )
{
/* Try to get the lock for new cache generation */
try
{
\IPS\Db::i()->insert( 'core_item_statistics_cache', [
'cache_class' => \get_class( $this ),
'cache_item_id' => $this->$idField,
'cache_contents' => '[]',
'cache_added' => time()
] );
$this->hasRebuildLock = TRUE;
}
/* We didn't get the lock, return empty array and allow other process to build cache */
catch( \IPS\Db\Exception $e )
{
$this->hasRebuildLock = FALSE;
return [];
}
}
catch( \UnderflowException $e ) { }
}
if ( isset(static::$cachedActivity[ $arrayKey ] ) and isset( static::$cachedActivity[ $arrayKey ][ $key ] ) )
if ( isset( static::$cachedActivity[ $arrayKey ] ) and isset( static::$cachedActivity[ $arrayKey ][ $key ] ) )
{
return static::$cachedActivity[ $arrayKey ][ $key ];
}
@@ -482,10 +557,10 @@ trait Statistics
{
if( !isset( static::$cachedActivity[ $arrayKey ] ) )
{
static::$cachedActivity[ $arrayKey ] = array();
static::$cachedActivity[ $arrayKey ] = [];
}
static::$cachedActivity[ $arrayKey ][ $key ] = array();
static::$cachedActivity[ $arrayKey ][ $key ] = [];
throw new \OutOfRangeException;
}
}
@@ -528,14 +603,20 @@ trait Statistics
{
if( $this->storeCache )
{
$insert = [];
foreach( $this->storeCache as $key => $data )
{
\IPS\Db::i()->insert( 'core_item_statistics_cache', array(
$insert[] = array(
'cache_class' => \get_class( $this ),
'cache_item_id' => str_replace( \get_class($this) . '.', '', $key),
'cache_contents' => json_encode( static::$cachedActivity[$key] ),
'cache_item_id' => str_replace( \get_class( $this ) . '.', '', $key ),
'cache_contents' => json_encode( static::$cachedActivity[ $key ] ) ?? '[]',
'cache_added' => time()
), TRUE );
);
}
if( \count( $insert ) )
{
\IPS\Db::i()->insert( 'core_item_statistics_cache', $insert, TRUE );
}
}