Вход Регистрация
Файл: admin/sources/classes/itemmarking/classItemMarking.php
Строк: 769
<?php

/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.3.3
 * Item Marking
 * Owner: Matt "Oh Lord, why did I get assigned this?" Mecham
 * Last Updated: $Date: 2012-05-31 08:17:13 -0400 (Thu, 31 May 2012) $
 * </pre>
 *
 * @author         $Author: mmecham $
 * @copyright    (c) 2001 - 2009 Invision Power Services, Inc.
 * @license        http://www.invisionpower.com/company/standards.php#license
 * @package        IP.Board
 * @link        http://www.invisionpower.com
 * @since        9th March 2005 11:03
 * @version        $Revision: 10829 $
 *
 * @todo     [Future] Perhaps find more ways to reduce the size of items_read
 * @todo     [Future] Maybe add an IN_DEV tool to warn when markers have been cancelled out / size drastically reduced
 */

class classItemMarking
{
    
/**#@+
     * Registry objects
     *
     * @access    protected
     * @var        object
     */    
    
protected $registry;
    protected 
$DB;
    protected 
$settings;
    protected 
$request;
    protected 
$lang;
    protected 
$member;
    protected 
$memberData;
    protected 
$cache;
    protected 
$caches;
    
/**#@-*/
    
    /**
     * Dead session data
     *
     * @access    protected
     * @var        array
     */
    
protected $_deadSessionData    = array();
    
    
/**
     * Module apps
     *
     * @access    protected
     * @var        array
     */
    
protected $_moduleApps        = array();
    
    
/**
     * Cache for internal use
     *
     * @access    protected
     * @var        array
     */
    
protected $_cache                = array();
    
    
/**
     * Cookie Data
     *
     * @access    protected
     * @var        array
     */
    
protected $_cookie            = array();
    
    
/**
     * Item Markers Data
     *
     * @access    protected
     * @var        array
     */
    
protected $_itemMarkers        = array();
    
    
/**
     * Last cleared time for key
     *
     * @access    protected
     * @var        int
     */
    
protected $_keyLastCleared    0;
    
    
/**
     * DB cut off time stamp
     *
     * @access    protected
     * @var        int
     */
    
protected $_dbCutOff            0;
    
    
/**
     * Cookie counter
     *
     * @access    protected
     * @var        int
     */
    
protected $_cookieCounter        0;
    
    
/**
     * Instant save on/off
     * 
     * @access    protected
     * @var        bool
     */
    
protected $_instantSave     true;

    
    
/**
     * Enable cookies?
     *
     */
    
protected $_useCookies            true;
    
    
/**
     * Can compress cookies
     */
    
protected $_canCompressCookies false;
    
    
/**
     * Disable all marking for guests
     */
    
protected $_noGuestMarking     false;
    
    protected 
$_setSaveCookie      false;
    
    protected 
$_dbFields           = array( 'item_key''item_member_id''item_app''item_last_update''item_last_saved''item_unread_count''item_read_array''item_global_reset',
                                            
'item_app_key_1''item_app_key_2''item_app_key_3''item_is_deleted' );
    
/**
     * Method constructor
     *
     * @access    public
     * @param    object        Registry Object
     * @return    @e void
     */
    
public function __constructipsRegistry $registry )
    {
        
$_NOW IPSDebug::getMemoryDebugFlag();
    
        
/* Make object */
        
$this->registry   =  $registry;
        
$this->DB          =  $this->registry->DB();
        
$this->settings   =& $this->registry->fetchSettings();
        
$this->request    =& $this->registry->fetchRequest();
        
$this->member     =  $this->registry->member();
        
$this->memberData =& $this->registry->member()->fetchMemberData();
        
$this->cache      =  $this->registry->cache();
        
$this->caches     =& $this->registry->cache()->fetchCaches();
            
         
/* Task? */
        
if ( IPS_IS_TASK === TRUE )
        {
            return;
        }
        
        
/* Search engine? */
        
if ( $this->member->is_not_human === TRUE )
        {
            return;
        }
        
        
/* Track markers for guests? */
        
$this->_noGuestMarking = ( $this->settings['topic_marking_guests'] ) ? 1;
        
        
/* Use cookie marking for guests */
        
if ( ! $this->memberData['member_id'] )
        {
            
$this->settings['topic_marking_enable'] = 0;
            
            if ( 
$this->_noGuestMarking )
            {
                return;
            }
        }
        
        
/* Switch off cookies for members */
        
if ( $this->memberData['member_id'] )
        {
            
/* If we've disabled DB marking, best use cookies anyway */
            
$this->_useCookies = ( $this->settings['topic_marking_enable'] ) ? false true;
        }
        
        
/* Build */
        
$this->memberData['item_markers'] = $this->_generateIncomingItemMarkers();

        
/* Set Up */
        
if ( is_array$this->memberData['item_markers'] ) )
        {
            foreach( 
$this->memberData['item_markers'] as $app => $key )
            {
                foreach( 
$this->memberData['item_markers'][ $app ] as $key => $data )
                {
                    if ( 
$app AND $key )
                    {
                        if ( 
$data['item_last_saved'] )
                        {
                            
$data['item_last_saved'] = intval$data['item_last_saved'] );
                        }
                        
                        
$this->_itemMarkers$app ][ $key ] = $data;
                    }
                }
            }
        }

        
/* Fetch cookies */
        
if ( $this->_useCookies )
        {
            
/* Test for cookie compression */
            
if ( function_exists('gzdeflate') AND function_exists('gzinflate') )
            {
                
$this->_canCompressCookies true;
            }
        
            foreach( 
IPSLib::getEnabledApplications() as $_app => $data )
            {
                
$_value  $this->_inflateCookieIPSCookie::get'itemMarking_' $_app ) );
                
$_value2 $this->_inflateCookieIPSCookie::get'itemMarking_' $_app '_items' ) );
                
                
$this->_cookie'itemMarking_' $_app ]           = ( is_array$_value ) )  ? $_value  : array();
                
$this->_cookie'itemMarking_' $_app '_items'] = ( is_array$_value2 ) ) ? $_value2 : array();
                
                
/* Clean up  */
                
if ( $this->_cookie'itemMarking_' $_app '_items'] )
                {
                    
$_items = ( is_array$this->_cookie'itemMarking_' $_app '_items'] ) ) ? $this->_cookie'itemMarking_' $_app '_items'] : unserialize$this->_cookie'itemMarking_' $_app '_items'] );
                
                    
$this->_cookieCounter 0;
                    
arsort$_itemsSORT_NUMERIC );
            
                    
$_newData array_filter$_items, array( $this'arrayFilterCookieItems' ) );
                    
                    
$this->_cookie'itemMarking_' $_app '_items'] = $_newData;
                    
                    
IPSDebug::addMessage'Cookie loaded: itemMarking_' $_app '_items' ' - ' serialize$_newData ) );
                    
IPSDebug::addMessage'Cookie loaded: itemMarking_' $_app ' - ' serialize$_value ) );
                }
            }
        }
        
        
IPSDebug::setMemoryDebugFlag"Topic markers initialized"$_NOW );
    }
    
    
/**
    * Compressed the cookie
    *
    * @access    protected
    * @param    mixed        Data (array or string)
    * @return    string        compressed data
    */
    
protected function _compressCookie$data )
    {
        if ( 
$this->_canCompressCookies )
        {
            if ( 
is_array$data ) )
            {
                
$data serialize$data );
            }
            
            
$data strtrbase64_encodeaddslashes( @gzcompress$data ) ) ), '+/=''-_,' );
        }
        
        return 
$data;
    }
    
    
/**
    * Inflate the cookie
    *
    * @access    protected
    * @param    mixed        Compressed string
    * @return    string        Uncompressed data
    */
    
protected function _inflateCookie$data )
    {
        
/* already inflated? */
        
if ( ! $data OR is_array$data ) )
        {
            return 
$data;
        }
        
        if ( 
$this->_canCompressCookies )
        {
            
$data = @gzuncompressstripslashesbase64_decodestrtr$data'-_,''+/=' ) ) ) );
            
            if ( 
substr$data0) == 'a:' )
            {
                
$data unserialize$data );
            }
        }
        
        return 
$data;
    }
        
    
/**
     * Disable instant save
     *
     * @access    public
     * @return    @e void
     */
    
public function disableInstantSave()
    {
        
$this->_instantSave false;
    }
    
    
/**
     * Enable instant save (Default mode anyway)
     *
     * @access    public
     * @return    @e void
     */
    
public function enableInstantSave()
    {
        
$this->_instantSave true;
    }
    
    
/**
     * Fetch status
     *
     * @access    public
     * @return    @e void
     */
    
public function fetchInstantSaveStatus()
    {
        return ( 
$this->_instantSave === true ) ? true false;
    }
    
    
/**
     * Add to cookie
     *
     * @access    protected
     * @param    string         Key
     * @param    array
     * @return    @e void
     */
    
protected function _updateCookieData$key$array )
    {
        
$this->_cookie$key ] = $array;
    }
    
    
/**
     * Fetch cookie data
     *
     * @access    protected
     * @param    key
     * @return    array
     */
    
protected function _fetchCookieData$key )
    {
        if ( ! 
$this->_useCookies )
        {
            return array();
        }
        
        if ( 
is_array$this->_cookie$key ] ) )
        {
            return 
$this->_cookie$key ];
        }
        else
        {
            return array();
        }
    }
    
    
/**
     * Public method to get cookie
     *
     * @access    public
     * @param    string        APP
     * @param    string        Type of key (items, read)
     * @return    mixed
     */
    
public function fetchCookieData$app$type )
    {
        if ( 
$app )
        {
            
$key = ( $type != 'items' ) ? 'itemMarking_' $app 'itemMarking_' $app '_items';
            
            return 
$this->_fetchCookieData$key );
        }
    }
    
    
/**
     * Set the flag to save cookies in mydestruct
     *
     * @access    protected
     * @return    @e void
     */
    
protected function _setSaveCookie()
    {
        
$this->_setSaveCookie true;
    }
    
    
/**
     * Save cookie
     *
     * @access    protected
     * @param    string        Key name (leave blank to save out all cookies)
     * @return    @e void
     */
    
protected function _saveCookie$key='' )
    {
        if ( ! 
$this->_useCookies )
        {
            return;
        }

        if ( 
$key AND is_array$this->_cookie$key ] ) )
        {
            
IPSCookie::set$key$this->_cookie$key ], );
        }
        else
        {
            foreach( 
$this->_cookie as $k => $v )
            { 
                if ( 
is_array$v ) AND ! count$v ) )
                {
                    
/* Do we have a cookie? */
                    
$test IPSCookie::get$k );
                    
                    if ( 
$test )
                    { 
                        
/* set a blank, non sticky cookie */
                        
IPSCookie::set$k'-'0, -);
                    }
                    else
                    {
                        continue;
                    }
                }
                else
                {
                    
IPSDebug::addMessage'Cookie SAVED: ' $k ' - ' .$this->_compressCookie$v ) );
                    
IPSCookie::set$k$this->_compressCookie$v ), );
                }
            }
        }
    }
    
    
/**
     * Fetch marking data via a join
     * 
     * <code>$join = $itemMarking->getSqlJoin( array( 'item_app_key_1' => 'prefix.field' ) );</code>
     * 
     * @param array $data
     * @param string $app
     */
    
public function getSqlJoin$data$app='' )
    {
        if ( ! 
$this->memberData['member_id'] OR ! $this->settings['topic_marking_enable'] )
        {
            return 
false;
        }
        
        
$app = ( $app ) ? $app IPS_APP_COMPONENT;
        
        
/* Set up where */
        
$where[] = 'itemmarking.item_member_id=' intval$this->memberData['member_id'] );
        
$where[] = 'itemmarking.item_app='' . $app . "'";
        
        foreach( 
$data as $key => $value )
        {
            if ( strstr( 
$key, 'item_app_key_' ) )
            {
                
$where[] = 'itemmarking.' . $key . '=' . $value;
            } 
        }
        
        /* Still here? */
        return array( 'select' => 'itemmarking.*',
                      'from'   => array( 'core_item_markers' => 'itemmarking' ),
                      'where'  => implode( ' AND ', 
$where ) );
    }
    
    /**
     * Sets internal data based on data fetched from a join
     * @param array 
$data
     */
    public function setFromSqlJoin( 
$data$app='' )
    {
        
$app     = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$data    = $this->_fetchModule$app )->convertData( $data );
        
$_key    = array();
        
$_data   = array();
        
        /* Check key */
        if ( empty( 
$data['item_key'] ) )
        {
            return 
$data;
        }
        
        foreach( 
$this->_dbFields as $field )
        {
            if ( isset( 
$data[ $field ] ) )
            {
                
$_data[ $field ] = $data[ $field ];
                
                unset( 
$data[ $field ] );
            }
        }
        
        if ( count( 
$_data ) && empty( $_data['item_is_deleted'] ) )
        {
            if ( IPSLib::isSerialized( 
$_data['item_read_array'] ) )
            {
                
$_data['item_read_array'] = unserialize( $_data['item_read_array'] );
            }
            
            
$this->_itemMarkers$app ][ $_data['item_key'] ] = $_data;
        }
        
        /* Recommend you always use the returned array as it removes the marking data to reduce memory footprint */
        return 
$data;
    }
    
    /**
     * Check the read status of an item
     *
     * Forum example (forumID is mapped to :item_app_key_1). itemID is the topic ID
     *
     * <code>
$read = $itemMarking->isRead( array( 'forumID' => 2, 'itemID' => 99, 'itemLastUpdate' => 1989098989 ) );</code>
     *
     * @access    public
     * @param    array         Array of data
     * @param    string        Optional app
     * @return    boolean     TRUE is read / FALSE is unread
     */
    public function isRead( 
$data$app='' )
    {
        
$app         = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$data        = $this->_fetchModule$app )->convertData( $data );
        
$_data       = $data;
        
$times       = array();
        
$cookie      = $this->_fetchCookieData( 'itemMarking_' . $app );
        
$cookieItems = $this->_fetchCookieData( 'itemMarking_' . $app . '_items');
        
        if ( ! 
$this->memberData['member_id'] AND $this->_noGuestMarking )
        {
            return 1;
        }
        
        /* Check check for how long we're tracking for */
        if ( 
$data['itemLastUpdate'] && $this->settings['topic_marking_keep_days'] )
        {
            if ( ( IPS_UNIX_TIME_NOW - ( 
$this->settings['topic_marking_keep_days'] * 86400 ) ) > $data['itemLastUpdate'] )
            {
                return 1;
            }
        }
        
        unset( 
$_data['itemLastUpdate'] );
    
        
$times[] = $this->fetchTimeLastMarked$_data$app );
        
        if ( 
$data['itemID'] )
        {
            if ( isset( 
$cookieItems[ $data['itemID'] ] ) )
            {
                
$times[] = intval( $cookieItems[ $data['itemID'] ] );
            }
            
            /* Update the main row? */
            if ( 
$this->settings['topic_marking_enable'] AND isset( $cookieItems[ $data['itemID'] ] ) AND $cookieItems[ $data['itemID'] ] > $times[1] )
            {
                
$mainKey = $this->_findMainRowByKey$data$app );
                
                if ( 
$mainKey )
                {
                    
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'][ $data['itemID'] ] = $cookieItems[ $data['itemID'] ];
                }
            }
        }
    
        return ( IPSLib::fetchHighestNumber( 
$times ) >= $data['itemLastUpdate'] ) ? TRUE : FALSE; 
    }
    
    /**
     * Mark as read
     *
     * Forum example (forumID is mapped to :item_app_key_1). itemID is the topic ID
     *
     * <code>
$itemMarking->markAsRead( array( 'forumID' => 34, 'itemID' => 99 ) );</code>
     * <code>
$itemMarking->markAsRead( array( 'forumID' => 34 ) );</code>
     * If you pass in a timestamp, it will set that as the read date so a topic, for example
     * won't appear read until you're on the last page
     * <code>
$itemMarking->markAsRead( array( 'forumID' => 34, 'itemID' => 99, 'markDate' => 123456790 ) );</code>
     * 
     * If you pass a "
containerLastActivityDate" timestamp it will compare the markDate against it and not run the fetchUnreadCount query
     * <code>
$itemMarking->markAsRead( array( 'forumID' => 34, 'itemID' => 99, 'markDate' => 123456790, 'containerLastActivityDate' => 1234567890 ) );</code>
     * @access    public
     * @param    array
     * @param     string    [App]
     * @return    @e void
     */
    public function markRead( 
$data$app='' )
    {
        
$app                        = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$origData                  = $data;
        
$data                       = $this->_fetchModule$app )->convertData( $data );
        
$cookie                     = $this->_fetchCookieData( 'itemMarking_' . $app );
        
$cookieItems                = $this->_fetchCookieData( 'itemMarking_' . $app . '_items');
        
$mainKey                    = $this->_findMainRowByKey$data$app );
        
$markDate                   = ( ! empty( $data['markDate'] ) ) ? intval( $data['markDate'] ) : time();
        
$containerLastActivityDate = ( ! empty( $data['containerLastActivityDate'] ) ) ? intval( $data['containerLastActivityDate'] ) : false;
        
        /* Search engine? */
        if ( 
$this->member->is_not_human === TRUE )
        {
            return;
        }
        
        if ( ! 
$this->memberData['member_id'] AND $this->_noGuestMarking )
        {
            return;
        }
        
        if ( 
$data['itemID'] )
        {
            /* Cookie */
            
$cookieItems[ $data['itemID'] ] = $markDate;
            
$this->_updateCookieData( 'itemMarking_' . $app . '_items', $cookieItems );
            
            
$_cookieGreset = isset( $cookie['greset'][ $this->_makeKey$data, TRUE ) ] ) ? intval( $cookie['greset'][ $this->_makeKey$data, TRUE ) ] ) : 0;
            
$_readItems    = $cookieItems
            
            /* Do we need to clean up? */
            if ( 
$this->settings['topic_marking_enable'] )
            {
                /* DB */
                
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'][ $data['itemID'] ] = $markDate;
                
                /* Check the cookie again.. */
                if ( 
$_cookieGreset AND $_cookieGreset > $this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] )
                {
                    
$this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] = $_cookieGreset;
                }
                
                /* Overwrite read items */
                if ( is_array( 
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'] ) )
                {
                    foreach( 
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'] as $i => $d )
                    {
                        
$_readItems[ $i ] = $d;
                    }
                }
            }
            
            /* Check last reset time */
            
$_lastReset = IPSLib::fetchHighestNumber( array( $_cookieGreset, isset( $cookie['global']) ? $cookie['global'] : 0, intval( $this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] ), intval( $this->memberData['_cache']['gb_mark__'. $app ] ) ) );
            
$_doQuery   = ( $this->settings['topic_marking_enable'] ) ? true : false;
            
            /* Fetch unread items */
            if ( 
$_doQuery === true )
            {
                
$_oldest      = IPS_UNIX_TIME_NOW - ( $this->settings['topic_marking_keep_days'] * 86400 );
                
$_lastReset   = ( $_lastReset >= $_oldest ) ? $_lastReset : $_oldest;
                
                
$_unreadCount = $this->_fetchModule$app )->fetchUnreadCount( $origData$_readItems$_lastReset );
            
                if ( 
$_unreadCount['count'] > 0 )
                {
                    if ( 
$this->settings['topic_marking_enable'] )
                    {
                        
$this->_itemMarkers$app ][ $mainKey ]['item_unread_count'] = $_unreadCount['count'];
                    }
                }
                else
                {
                    if ( 
$this->settings['topic_marking_enable'] )
                    {
                        /* Update the last global reset time and clear the read array */
                        
$this->_itemMarkers$app ][ $mainKey ]['item_read_array']   = array();
                        
$this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] = time();
                        
$this->_itemMarkers$app ][ $mainKey ]['item_unread_count'] = 0;
                    }
                    
                    /* Cookie */
                    
$cookie['greset'][ $this->_makeKey$data, TRUE ) ] = time();
                    
$this->_updateCookieData( 'itemMarking_' . $app$cookie );
                    
$this->_updateCookieData( 'itemMarking_' . $app . '_items', array() );
                }
            }
        }
        else
        {
            if ( 
$this->settings['topic_marking_enable'] )
            {
                /* Update the last global reset time and clear the read array */
                
$this->_itemMarkers$app ][ $mainKey ]['item_read_array']   = array();
                
$this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] = time();
                
$this->_itemMarkers$app ][ $mainKey ]['item_unread_count'] = 0;
            }
            
            /* Cookie */
            
$cookie['greset'][ $this->_makeKey$data, TRUE ) ] = time();
            
$this->_updateCookieData( 'itemMarking_' . $app$cookie );
            
$this->_updateCookieData( 'itemMarking_' . $app . '_items', array() );
        }
        
        /* Add in global update */
        
$this->_itemMarkers$app ][ $mainKey ]['item_last_update'] = time();
        
        /* Save cookie */
        
$this->_setSaveCookie();
        
        /* Save DB */
        
$this->_save$app$mainKey );
    }
    
    /**
     * Marks everything within an app as read
     *
     * @access    public
     * @param    string    [App Optional. If ommited, all apps are marked as read]
     * @return    @e void
     */
    public function markAppAsRead( 
$app='' )
    {
        /* Search engine? */
        if ( 
$this->member->is_not_human === TRUE )
        {
            return;
        }
        
        /* Cookie */
        
$cookie['global'] = time();
        
$cookie['greset'] = array();
        
        /* One app or all? */
        if ( 
$app )
        {
            /* Reset member cache */
            IPSMember::packMemberCache( 
$this->memberData['member_id'], array('gb_mark__' . $app => time() ) );
            
            /* Mark rows for deletion */
            
$this->DB->update( 'core_item_markers', array( 'item_is_deleted' => 1 ), "item_app='" . $app . "' AND item_member_id=" . intval( $this->memberData['member_id'] ) );
                    
            /* Update cookies */
            
$this->_updateCookieData( 'itemMarking_' . $app . '_items', array() );
            
$this->_updateCookieData( 'itemMarking_' . $app$cookie );
        }
        else
        {
            /* Do 'em all */
            
$cache = array();
            
$apps  = IPSLib::getEnabledApplications( array('itemMarking') );
            
            foreach( 
$apps as $app => $data )
            {
                
$cache[ 'gb_mark__' . $app ] = time();
                
                /* Update cookies */
                
$this->_updateCookieData( 'itemMarking_' . $app . '_items', array() );
                
$this->_updateCookieData( 'itemMarking_' . $app$cookie );
            }
            
            if ( count( 
$cache ) )
            {
                /* Reset member cache */
                IPSMember::packMemberCache( 
$this->memberData['member_id'], $cache );
            }
            
            /* Mark rows for deletion */
            
$this->DB->update( 'core_item_markers', array( 'item_is_deleted' => 1 ), 'item_member_id=' . intval( $this->memberData['member_id'] ) );
            
            /* Reset internal array */
            
$this->_itemMarkers = array();
        }
        
        /* Save cookie */
        
$this->_setSaveCookie();
    }
    
    /**
     * Fetch the last time an item was marked
     * checks app reset... then the different key resets.. then an individual key
     *
     * In this example: itemID is within 'item_read_array'.
     * 
$lastReset = $this->fetchTimeLastMarked( array( 'forumID' => 2, 'itemID' => '99' ) );
     *
     * @access    public
     * @param    array         Data
     * @param    string        Optional app
     * @return    int         Timestamp item was last marked or 0 if unread
     */
    public function fetchTimeLastMarked( 
$data$app='' )
    {
        
$app   = ( $app ) ? $app : IPS_APP_COMPONENT;
        
        /* Check check for how long we're tracking for */
        if ( 
$data['itemLastUpdate'] && $this->settings['topic_marking_keep_days'] )
        {
            if ( ( IPS_UNIX_TIME_NOW - ( 
$this->settings['topic_marking_keep_days'] * 86400 ) ) > $data['itemLastUpdate'] )
            {
                return IPS_UNIX_TIME_NOW;
            }
        }
        
        unset( 
$data['itemLastUpdate'] );
        
        
$data  = $this->_fetchModule$app )->convertData( $data );

        
$times = array();
        
        
$times[] = intval( $this->_findLatestGlobalReset$data$app ) );

        if ( isset( 
$data['itemID'] ) )
        {
            
$times[] = intval( $this->_findLatestItemReset$data$app ) );
        }
        
        return IPSLib::fetchHighestNumber( 
$times );
    }
    
    /**
     * Fetch the unread count
     *
     * In this example we are retrieving the number of unread items for a forum id 2
     * 
$unreadCount = $this->fetchUnreadCount( array( 'forumID' => 2 ) );
     *
     * @access    public
     * @param    array         Data
     * @param    string        App
     * @return    int         Number of unread items left
     */
    public function fetchUnreadCount( 
$data$app='' )
    {
        
$app   = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$data  = $this->_fetchModule$app )->convertData( $data );

        
$times = array();
        
        if ( isset( 
$data['item_app_key_1'] ) )
        {
            
$mainKey  = $this->_findMainRowByKey$data$app );
            
            return intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_unread_count'] );
        }

        return 0;
    }
    
    /**
     * Fetches the oldest unread timestamp
     *
     * In this example we are retrieving the number of unread items for a forum id 2
     * 
$unreadCount = $this->fetchOldestUnreadTimestamp( array( 'forumID' => 2 ) );
     *
     * @access    public
     * @param    array         Data
     * @param    string        App
     * @return    int         Number of unread items left
     */
    public function fetchOldestUnreadTimestamp( 
$data$app='' )
    {
        
$app   = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$data  = $this->_fetchModule$app )->convertData( $data );
        
$time  = IPS_UNIX_TIME_NOW;
        
        if ( ! isset( 
$data['item_app_key_1'] ) )
        {
            if ( is_array( 
$this->_itemMarkers$app ] ) AND count( $this->_itemMarkers$app ] ) )
            {
                foreach( 
$this->_itemMarkers$app ] as $key => $_data )
                {
                    if ( 
$_data['item_global_reset'] && ( $_data['item_global_reset'] < $time ) )
                    {
                        
$time = $_data['item_global_reset'];
                    }
                }
            }
        }
        else
        {
            
$mainKey  = $this->_findMainRowByKey$data$app );
            
$_data    = $this->_itemMarkers$app ][ $mainKey ];
            
            if ( 
$_data['item_global_reset'] && ( $_data['item_global_reset'] < $time ) )
            {
                
$time = $_data['item_global_reset'];
            }
        }
        
        return 
$time;
    }

    
    /**
     * Fetch read IDs since last global reset
     * Returns IDs read based on incoming data
     *
     * <code>
$readIDs = $itemMarking->fetchReadIds( array( 'forumID' => 2 ) );</code>
     * @access        public
     * @param        array         Array of data
     * @param        strng        [App]
     * @return        array         Array of read item IDs
     */
    public function fetchReadIds( 
$data$app='', $keysOnly=true )
    {
        
$app      = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$origData = $data;

        /* Get all read ids */
        if ( ! isset( 
$data['item_app_key_1'] ) )
        {
            
$_results    = array();

            if ( is_array( 
$this->_itemMarkers$app ] ) AND count( $this->_itemMarkers$app ] ) )
            {
                foreach( 
$this->_itemMarkers$app ] as $key => $_data )
                {
                    if ( 
$_data['item_read_array'] )
                    {
                        /* + is intentionally used as the arrays will preserve their keys, but will not with array_merge */
                        
$_results    = $_results + $_data['item_read_array'];
                    }
                }
            }

            return ( 
$keysOnly ) ? array_keys( $_results ) : $_results;
        }
        else
        {
            
$data     = $this->_fetchModule$app )->convertData( $data );
            
$mainKey  = $this->_findMainRowByKey$data$app );

            if ( isset( 
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'] ) AND is_array($this->_itemMarkers$app ][ $mainKey ]['item_read_array']) )
            {
                return ( 
$keysOnly ) ? array_keys( $this->_itemMarkers$app ][ $mainKey ]['item_read_array'] ) : $this->_itemMarkers$app ][ $mainKey ]['item_read_array'];
            }
        }

        return array();
    }
    
    /**
     * Fetch read ID
     * If forum was cleared, it may not exist as global reset takes precidence. 
     * <code>
$readIDs = $itemMarking->fetchReadId( array( 'forumID' => 2, 'itemId' => 2 ) );</code>
     * @access        public
     * @param        array         Array of data
     * @param        strng        [App]
     * @return        int            0 or timestamp
     */
    public function fetchItemReadTime( 
$data$app='' )
    {
        
$app      = ( $app ) ? $app : IPS_APP_COMPONENT;
        
$origData = $data;
        
$data     = $this->_fetchModule$app )->convertData( $data );
        
$mainKey  = $this->_findMainRowByKey$data$app );
        
        if ( isset( 
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'] ) AND is_array($this->_itemMarkers$app ][ $mainKey ]['item_read_array']) )
        {
            return intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'][ $data['itemID'] ] );
        }
        else
        {
            return 0;
        }
    }
        
    /**
     * Find latest Item reset
     *
     * @access    protected
     * @param    array         Array of data (DB field names)
     * @param    string         App to check
     * @return    int            Timestamp
     */
    protected function _findLatestItemReset( 
$data$app )
    {
        
$cookie      = $this->_fetchCookieData( 'itemMarking_' . $app );
        
$cookieItems = $this->_fetchCookieData( 'itemMarking_' . $app . '_items');
        
$_times      = array();
        
        if ( ! 
$this->memberData['member_id'] AND $this->_noGuestMarking )
        {
            return time();
        }
        
        
$mainKey = $this->_findMainRowByKey$data$app );
        
$mainRow = $this->_itemMarkers$app ][ $mainKey ];
        
        /* Got a DB field? */
        if ( isset( 
$mainRow['item_read_array'] ) AND is_array( $mainRow['item_read_array'] ) )
        {
            if( isset( 
$mainRow['item_read_array'][ $data['itemID'] ] ) )
            {
                
$_times[] = intval( $mainRow['item_read_array'][ $data['itemID'] ] );
            }
        }
        
        /* Got a cookie field? */
        if ( isset( 
$cookieItems[ $data['itemID'] ] ) )
        {
            
$_times[] = $cookieItems[ $data['itemID'] ];
        }
        
        
$_time = IPSLib::fetchHighestNumber( $_times );
        
        return 
$_time;
    }
        
    /**
     * Find latest Global reset
     *
     * @access    protected
     * @param    array         Array of data (DB field names)
     * @param    string         App to check
     * @return    int            Timestamp
     */
    protected function _findLatestGlobalReset( 
$data$app )
    {
        
$_time       = 0;
        
$_times      = array();
        
$_key        = $this->_makeKey$data );
        
$cookie      = $this->_fetchCookieData( 'itemMarking_' . $app );
        
$cookieItems = $this->_fetchCookieData( 'itemMarking_' . $app . '_items');
        
        if ( ! 
$this->memberData['member_id'] AND $this->_noGuestMarking )
        {
            return time();
        }

        
$mainKey = $this->_findMainRowByKey$data$app );
        
        /* Got all fields? */
        if ( isset( 
$this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] ) )
        {
            
$_times[] = $this->_itemMarkers$app ][ $mainKey ]['item_global_reset'];
        }
        
        if ( isset( 
$cookie['greset'][ $this->_makeKey$data, TRUE ) ] ) )
        {
            
$_times[] = intval( $cookie['greset'][ $this->_makeKey$data, TRUE ) ] );
        }
        
        if ( isset( 
$cookie['global'] ) )
        {
            
$_times[] = intval( $cookie['global'] );
        }
        
        if ( isset( 
$this->memberData['_cache']['gb_mark__'. $app ] ) )
        {
            
$_times[] = $this->memberData['_cache']['gb_mark__'.  $app ];
        }
        
        /* Get most recent time */
        
$_time = IPSLib::fetchHighestNumber( $_times );
        
        return 
$_time;
    }
    
    /**
     * Find a particular row
     *
     * @access    protected
     * @param    array         Array of data
     * @param    string        App
     * @return    array         Array of data: core_item_marking row, effectively
     */
    protected function _findMainRowByKey( 
$data$app )
    {
        /* Not interested in this for the main row */
        unset( 
$data['itemID'], $data['itemLastUpdate'] );
        
        
$_key  = $this->_makeKey$data );
        
        if ( ! isset( 
$this->_itemMarkers$app ] ) OR ! is_array( $this->_itemMarkers$app ] ) )
        {
            /* Mark markers as having changed */
            
$this->_changesMade = TRUE;
            
            /* Add in extra items */
            
$data['item_app']         = $app;
            
$data['item_key']         = $_key;
            
$data['item_member_id']     = $this->memberData['member_id'];
            
$data['item_read_array'] = array();
            
$this->_itemMarkers$app ]          = array();
            
$this->_itemMarkers$app ][ $_key ] = $data;
            
            IPSDebug::addMessage( "
Item Marking Key Created$_key" );
            
            return 
$_key;
        }
        
        if ( ! empty( 
$this->_itemMarkers$app ][ $_key ] ) AND is_array( $this->_itemMarkers$app ][ $_key ] ) )
        {
            /* Make sure it contains the app & key */
            
$this->_itemMarkers$app ][ $_key ]['item_app']        = $app;
            
$this->_itemMarkers$app ][ $_key ]['item_key']        = $_key;
            
$this->_itemMarkers$app ][ $_key ]['item_member_id']    = $this->memberData['member_id'];
            
            /* Make sure read IDs are unserialized */
            if ( isset( 
$this->_itemMarkers$app ][ $_key ]['item_read_array'] ) AND ! is_array( $this->_itemMarkers$app ][ $_key ]['item_read_array'] ) )
            {
                
$this->_itemMarkers$app ][ $_key ]['item_read_array'] = unserialize( $this->_itemMarkers$app ][ $_key ]['item_read_array'] );
            }
            
            return 
$_key;
        }
        else
        {
            /* Mark markers as having changed */
            
$this->_changesMade = TRUE;
            
            /* Make sure it contains the app & key */
            
$this->_itemMarkers$app ][ $_key ]['item_app']        = $app;
            
$this->_itemMarkers$app ][ $_key ]['item_key']        = $_key;
            
$this->_itemMarkers$app ][ $_key ]['item_member_id']    = $this->memberData['member_id'];
            
$this->_itemMarkers$app ][ $_key ]['item_read_array'] = array();
            
$this->_itemMarkers$app ][ $_key ] = $data;
            
            IPSDebug::addMessage( "
Item Marking Key returned$_key" );

            return 
$_key;
        }
        
        /* Mark markers as having changed */
        
        /**
         * @todo    Matt: this code is not used anymore? We already return in the if/else above..
         */
        
$this->_changesMade = TRUE;
        
        // Create a new key ...
        
$data['item_app']         = $app;
        
$data['item_key']         = $_key;
        
$data['item_member_id']     = $this->memberData['member_id'];
        
$data['item_read_array'] = array();
        
        
$this->_itemMarkers$app ]          = array();
        
$this->_itemMarkers$app ][ $_key ] = $data;
        
        return 
$_key;
    }
    
    /**
     * Fetch module class
     *
     * @access    protected
     * @param    string            App to fetch
     * @return    object
     */
    protected function _fetchModule( 
$app='' )
    {
        
$app = ( $app ) ? $app : IPS_APP_COMPONENT;
        
        if ( isset( 
$this->_moduleApps$app ] ) && is_object( $this->_moduleApps$app ] ) )
        {
            return 
$this->_moduleApps$app ];
        }
        else
        {
            
$_file = IPSLib::getAppDir( $app ) . '/extensions/coreExtensions.php';
            
            if ( is_file( 
$_file ) )
            {
                
$classToLoad = IPSLib::loadLibrary( $_file, 'itemMarking__'.$app$app );
                
                if ( class_exists( 
$classToLoad ) )
                {
                    
$this->_moduleApps$app ] = new $classToLoad$this->registry );
                    
                    return 
$this->_moduleApps$app ];
                }
                else
                {
                    throw new Exception( "
No itemMarking class available for $app" );
                }
            }
            else
            {
                throw new Exception( "
No itemMarking class available for $app" );
            }
        }
    }

    /**
     * Make a new key
     *
     * @access    protected
     * @param   array
     * @param    bool        Is cookie?
     * @return    string
     */
    protected function _makeKey( 
$data$isCookie=FALSE )
    {
        /* Not interested in this for the main row */
        unset( 
$data['itemID'], $data['itemLastUpdate'], $data['containerLastActivityDate'], $data['markDate'] );
        
        return ( 
$isCookie === TRUE ) ? $data['item_app_key_1'] : md5( serialize( $data ) );
    }
    
    /**
     * Update topic markers
     *
     * @access    protected
     * @param    string    app
     * @param    string    mainkey
     * @return    @e void
     */
    protected function _save( 
$app$mainKey )
    {
        if ( ! 
$this->settings['topic_marking_enable'] )
        {
            return FALSE;
        }
        
        if ( ! 
$this->memberData['member_id'] )
        {
            return FALSE;
        }
        
        
$row = array( 'item_key'          => $mainKey,
                      'item_member_id'    => 
$this->memberData['member_id'],
                      'item_app'          => 
$app,
                      'item_last_update'  => intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_last_update'] ),
                      'item_last_saved'   => time(),
                      'item_read_array'   => ( is_array( 
$this->_itemMarkers$app ][ $mainKey ]['item_read_array'] ) ) ? serialize( $this->_itemMarkers$app ][ $mainKey ]['item_read_array'] ) : $this->_itemMarkers$app ][ $mainKey ]['item_read_array'],
                      'item_global_reset' => intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_global_reset'] ),
                      'item_unread_count' => intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_unread_count'] ),
                      'item_app_key_1'      => intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_app_key_1'] ),
                      'item_app_key_2'      => intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_app_key_2'] ),
                      'item_app_key_3'      => intval( 
$this->_itemMarkers$app ][ $mainKey ]['item_app_key_3'] ),
                      'item_is_deleted'   => 0 );
        
        
$this->DB->replace( 'core_item_markers', $row, array( 'item_key', 'item_app', 'item_member_id' ) );
    }
    
    /**
     * Manual destructor called by ips_MemberRegistry::__myDestruct()
     * Gives us a chance to do anything we need to do before other
     * classes are culled
     *
     * @access    public
     * @return    @e void
     */
    public function __myDestruct()
    {
        /* Task? */
        if ( IPS_IS_TASK === TRUE )
        {
            return;
        }
        
        /* Search engine? */
        if ( 
$this->member->is_not_human === TRUE )
        {
            return;
        }
        
        /* Save cookies */
        if ( 
$this->_setSaveCookie )
        {
            
$this->_saveCookie();
        }
    }
    
    /**
     * Build item markers.
     * Ok, this function attempts to gather the corret item markers. 
     * The function also loads data from the markers DB and attempts to build a 'merged' set of markers
     * based on all the data it has.
     *
     * @access    protected
     * @return    array
     */
    protected function _generateIncomingItemMarkers()
    {
        
$items = NULL;
        
        /* Not playing? */
        if ( ! 
$this->settings['topic_marking_enable'] )
        {
            return array();
        }
        
        /* Not a member */
        if ( ! 
$this->memberData['member_id'] )
        {
            return array();
        }
        
        /* Not loading on init? */
        try
        {
            if ( method_exists( 
$this->_fetchModule(), 'loadAllMarkers' ) )
            {
                
$result = $this->_fetchModule()->loadAllMarkers();
                
                if ( 
$result === false )
                {
                    return;
                }
            }
        }
        catch( Exception 
$e )
        {
        }    
        
        
$this->DB->build( array( 'select' => '*',
                                 'from'   => 'core_item_markers',
                                 'where'  => 'item_member_id=' . 
$this->memberData['member_id'] ) );

        
$itemMarking = $this->DB->execute();

        while( 
$row = $this->DB->fetch( $itemMarking ) )
        {
            if ( ! 
$row['item_is_deleted'] )
            {
                
$items[ $row['item_app'] ][ $row['item_key'] ] = $row;
            }
        }
        
        /* Check data */
        if ( is_array( 
$items ) AND count( $items ) )
        {
            foreach( 
$items as $app => $item )
            {
                foreach( 
$item as $key => $_data )
                {
                    if ( 
$app AND $key )
                    {
                        /* Ensure INT values */
                        
$items[ $app ][ $key ]['item_last_update']  = intval( $_data['item_last_update'] );
                        
$items[ $app ][ $key ]['item_global_reset'] = intval( $_data['item_global_reset'] );
                        
$items[ $app ][ $key ]['item_unread_count'] = intval( $_data['item_unread_count'] );
                        
$items[ $app ][ $key ]['item_member_id']    = intval( $_data['item_member_id'] );
                        
$items[ $app ][ $key ]['item_last_saved']   = intval( $_data['item_last_saved'] );
                    
                        /* Ensure read array is unserialized correctly */
                        if ( isset( 
$_data['item_read_array'] ) AND ! is_array( $_data['item_read_array'] ) )
                        {
                            
$items[ $app ][ $key ]['item_read_array'] = unserialize( $_data['item_read_array'] );
                        }
                        
                        /* Now clean it up */
                        if ( isset( 
$_data['item_read_array'] ) AND is_array( $items[ $app ][ $key ]['item_read_array'] ) )
                        {
                            /* Remove items that are older than the last marked time */
                            if ( 
$items[ $app ][ $key ]['item_global_reset'] )
                            {
                                
$this->_keyLastCleared = intval( $_data['item_global_reset'] );
                                
$items[ $app ][ $key ]['item_read_array'] = array_filter( $items[ $app ][ $key ]['item_read_array'], array( $this, 'arrayFilterRemoveAlreadyClearedItems' ) );
                            }
                        }
                        else
                        {
                            
$items[ $app ][ $key ]['item_read_array'] = array();
                        }
                    }
                }
            }
        }
        else
        {
            return array();
        }

        return 
$items;
    }
    
    /**
     * Array sort Used to remove out of date topic marking entries
     *
     * @access    public
     * @param    mixed
     * @return    mixed
     * @since    2.0
     */
    public function arrayFilterRemoveAlreadyClearedItems( 
$var )
    {
        return 
$var > $this->_keyLastCleared;
    }
    
    /**
     * Array sort Used to remove out of date topic marking entries
     *
     * @access    public
     * @param    mixed
     * @return    mixed
     * @since    2.0
     */
    public function arrayFilterCleanReadItems( 
$var )
    {
        return 
$var > $this->_dbCutOff;
    }
        
    /**
     * Array sort Used to make sure there are no more than 50 last read items
     *
     * @access    public
     * @param    mixed
     * @return    mixed
     * @since    2.0
     */
    public function arrayFilterCookieItems( 
$var )
    {
        
$this->_cookieCounter++;
        
        return ( 
$this->_cookieCounter <= 50 ) ? TRUE : FALSE;
    }

    /** 
    * Save my markers to DB 
    * 
    * Saves the current values in 
$this->_itemMarkers back to the DB 
    * 
    * @access  public 
    * @return  int    Number of rows saved 
    * @deprecated 3.3.0  Really depricated now!
    */ 
   public function writeMyMarkersToDB()
   {
       
   }

}
Онлайн: 0
Реклама