Location: PHPKode > projects > Bitweaver > recommends/LibertyRecommends.php
<?php
/**
* $Header: /cvsroot/bitweaver/_bit_recommends/LibertyRecommends.php,v 1.14 2007/10/23 14:27:33 nickpalmer Exp $
* date created 2006/02/10
* @author xing <hide@address.com>
* @version $Revision: 1.14 $ $Date: 2007/10/23 14:27:33 $
* @package recommends
*/

/**
 * Setup
 */
require_once( KERNEL_PKG_PATH.'BitBase.php' );

define('RECOMMENDS_PERIOD_SCALE', 3600); // 60 * 60
define('RECOMMENDS_TIMEOUT_CHANGE_SCALE', 60);
define('RECOMMENDS_TIMEOUT_DAYS_SCALE', 86400); // 24 * 60 * 60

/**
 * Liberty Recommends
 * 
 * @package recommends
 */
class LibertyRecommends extends LibertyContent {
	var $mContentId;

	/**
	 * Initiate Liberty Recommends
	 * 
	 * @param array $pContentId Content id of the item being recommended
	 * @access public
	 * @return void
	 */
	function LibertyRecommends( $pContentId=NULL ) {
		LibertyBase::LibertyBase();
		$this->mContentId = $pContentId;
	}

	/**
	 * Load the data from the database
	 * 
	 * @access public
	 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
	 */
	function load() {
		if( $this->isValid() ) {
			global $gBitSystem, $gBitUser;
			$query = "
				SELECT  lc.`created`, lc.`content_id`, rcms.`recommending` AS recommends_recommending, rcms.`votes` AS recommends_votes, rcm.`recommending_time` AS recommends_time, rcm.`changes` AS recommends_changes, rcm.`recommending` AS recommends_user_recommending
				FROM `".BIT_DB_PREFIX."liberty_content` lc
				LEFT JOIN `".BIT_DB_PREFIX."recommends_sum` rcms ON (lc.`content_id` = rcms.`content_id`)
				LEFT JOIN `".BIT_DB_PREFIX."recommends` rcm ON (lc.`content_id` = rcm.`content_id` AND rcm.`user_id` = ? )
				WHERE lc.`content_id`=?";
			$this->mInfo = $this->mDb->getRow( $query, array( $gBitUser->mUserId, $this->mContentId ) );
		}
		return( count( $this->mInfo ) );
	}

	/**
	 * get list of all recommended content
	 *
	 * @param $pListHash contains array of items used to limit search results
	 * @param $pListHash[sort_mode] column and orientation by which search results are sorted
	 * @param $pListHash[find] search for a pigeonhole title - case insensitive
	 * @param $pListHash[max_records] maximum number of rows to return
	 * @param $pListHash[offset] number of results data is offset by
	 * @access public
	 * @return array of recommended content
	 **/
	function getList( &$pListHash ) {
		global $gBitSystem, $gBitUser, $gLibertySystem;

		$ret = $bindVars = array();
		$where = $join = $select = '';

		// set custom sorting before we call prepGetList()
		if( !empty( $pListHash['sort_mode'] )) {
			$order = " ORDER BY ".$this->mDb->convertSortmode( $pListHash['sort_mode'] )." ";
		} else {
			// set a default sort_mode
			$order = " ORDER BY rcm.`qualified_time` DESC";
		}

		LibertyContent::prepGetList( $pListHash );

		if( !empty( $pListHash['user_id'] )) {
			$where      .= empty( $where ) ? ' WHERE ' : ' AND ';
			$where      .= " rcmh.`user_id`=? ";
			$bindVars[]  = $pListHash['user_id'];
			$select     .= ", rcmh.`recommending` AS `user_recommending`";
			$join       .= " LEFT JOIN `".BIT_DB_PREFIX."recommends` rcmh ON( rcm.`content_id` = rcmh.`content_id` AND rcmh.`recommending` != 0) ";
			$order       = " ORDER BY rcmh.`recommending` DESC";
		}

		if( !empty( $pListHash['timeout'] ) ) {
			$where	.= empty( $where) ? ' WHERE ' : ' AND ';
			$where	.= " rcm.`qualified_time` >= ? ";
			$bindVars[] = $pListHash['timeout'];
		}

		if( !empty( $pListHash['recommends'] ) ) {
			$where .= empty( $where ) ? ' WHERE ' : ' AND ';
			$where .= " rcm.recommending >= ? ";
			$bindVars[] = $pListHash['recommends'];
		}

		if( !empty( $pListHash['find'] )) {
			$where      .= empty( $where ) ? ' WHERE ' : ' AND ';
			$where      .= " UPPER( lc.`title` ) LIKE ? ";
			$bindVars[]  = '%'.strtoupper( $pListHash['find'] ).'%';
		}

		if ( !empty( $pListHash['content_type'] ) ) {
			if( is_array( $pListHash['content_type'] ) ) {			
				$where      .= empty( $where ) ? ' WHERE ' : ' AND ';
				$where .= " lc.`content_type_guid` IN( ".implode( ',',array_fill( 0,count( $pListHash['content_type'] ),'?' ) )." )";
				$bindVars = array_merge ( $bindVars, $pListHash['content_type_guid'] );
			}
			else {
				$where      .= empty( $where ) ? ' WHERE ' : ' AND ';
				$where .= " lc.`content_type_guid` = ? ";
				$bindVars[] = $pListHash['content_type'];
			}
		}
		
		$query = "
			SELECT rcm.*, lch.`hits`, lch.`last_hit`, lc.`event_time`, lc.`title`,
			lc.`last_modified`, lc.`content_type_guid`, lc.`ip`, lc.`created`, uu.`email`, uu.`login`, uu.`real_name` $select
			FROM `".BIT_DB_PREFIX."recommends_sum` rcm
				INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = rcm.`content_id` )
				INNER JOIN		`".BIT_DB_PREFIX."users_users`			 uu ON ( uu.`user_id`			   = lc.`user_id` )
				LEFT JOIN `".BIT_DB_PREFIX."liberty_content_hits` lch ON ( lc.`content_id` = lch.`content_id` )
			$join $where $order";
		$result = $this->mDb->query( $query, $bindVars, $pListHash['max_records'], $pListHash['offset'] );

		while( $aux = $result->fetchRow() ) {
			$type = &$gLibertySystem->mContentTypes[$aux['content_type_guid']];
			if( empty( $type['content_object'] )) {
				include_once( $gBitSystem->mPackages[$type['handler_package']]['path'].$type['handler_file'] );
				$type['content_object'] = new $type['handler_class']();
			}
			if( !empty( $gBitSystem->mPackages[$type['handler_package']] )) {
				$aux['display_link'] = $type['content_object']->getDisplayLink( $aux['title'], $aux );
				$aux['title']        = $type['content_object']->getTitle( $aux );
				$aux['display_url']  = $type['content_object']->getDisplayUrl( $aux['content_id'], $aux );
			}
			$ret[] = $aux;
		}

		$query = "
			SELECT COUNT( rcm.`content_id` )
			FROM `".BIT_DB_PREFIX."recommends_sum` rcm
				INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = rcm.`content_id` )
				LEFT JOIN `".BIT_DB_PREFIX."liberty_content_hits` lch ON ( lc.`content_id` = lch.`content_id` )
			$join $where";
		$pListHash['cant'] = $this->mDb->getOne( $query, $bindVars );

		LibertyContent::postGetList( $pListHash );
		return $ret;
	}

	/**
	 * Get the recommending history of a loaded content
	 * 
	 * @param boolean $pExtras loading the extras will get all users who have recommended in the past and their recommendings
	 * @access public
	 * @return TRUE on success, FALSE on failure
	 */
	function getRecommendingDetails( $pExtras = FALSE ) {
		if( $this->isValid() ) {
			global $gBitSystem;
			$query = "
				SELECT `recommending` AS `recommends_recommending`, votes AS `recommends_votes`, `content_id`
				FROM `".BIT_DB_PREFIX."recommends_sum`
				WHERE `content_id`=?";
			$obj = $this->getLibertyObject( $this->mContentId );
			$this->mInfo = $this->mDb->getRow( $query, array( $this->mContentId ) );
			$this->mInfo = array_merge( $this->mInfo, $obj->mInfo );
			$this->mInfo['display_url'] = $obj->getDisplayUrl();
			if( $pExtras ) {
				$query = "
					SELECT rcm.`content_id` as `hash_key`, rcm.`recommending`, uu.`login`, uu.`real_name`, uu.`user_id`
					FROM `".BIT_DB_PREFIX."recommends` rcm
						INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON rcm.`user_id`=uu.`user_id`
					WHERE rcm.`content_id`=?
					ORDER BY rcm.`recommending` ASC";
				$this->mInfo['user_recommendings'] = $this->mDb->getAll( $query, array( $this->mContentId ) );
			}
		}
		return( count( $this->mInfo ) );
	}

	/**
	 * Quick method to get a nice summary of past recommendings for a given content
	 * 
	 * @param array $pContentId 
	 * @access public
	 * @return usable hash with a summary of recommendings of a given content id
	 */
	function getRecommendingSummary( $pContentId = NULL ) {
		if( !@BitBase::verifyId( $pContentId ) && $this->isValid() ) {
			$pContentId = $this->mContentId;
		}

		$ret['sum'] = $ret['count'] = 0;
		if( @BitBase::verifyId( $pContentId ) ) {
			$query = "
				SELECT
					rcmh.`recommending`,
					COUNT( rcmh.`recommending`) AS `update_count`
				FROM `".BIT_DB_PREFIX."recommends_history` rcmh
				WHERE rcmh.`content_id`=? AND rcmh.`recommending` != 0
				GROUP BY rcmh.`recommending`";
			$result = $this->mDb->getAll( $query, array( $pContentId ) );

			foreach( $result as $set ) {
				$ret['sum']    += $set['recommending'];
				$ret['count']  += $set['update_count'];
			}
		}
		return $ret;
	}

	/**
	 * @param array pParams hash of values that will be used to store the page
	 *
	 * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why
	 * @access public
	 **/
	function store( &$pParamHash ) {
		global $gBitUser, $gBitSystem;
		if( $this->verify( $pParamHash ) ) {
			$table = BIT_DB_PREFIX."recommends";
			$table_sum = BIT_DB_PREFIX."recommends_sum";
			$this->mDb->StartTrans();			
			if( $this->getUserRecommending( $pParamHash['content_id'] )) {
				$locId = array( "content_id" => $pParamHash['recommends_store']['content_id'], "user_id" => $pParamHash['recommends_store']['user_id'] );
				unset($pParamHash['recommends_store']['recommending_time']);
				$result = $this->mDb->associateUpdate( $table, $pParamHash['recommends_store'], $locId );
				unset($locId['user_id']);
				$pParamHash['recommends_sum_store']['content_id'] = $pParamHash['recommends_store']['content_id'];
				$pParamHash['recommends_sum_store']['recommending'] = $this->mDb->getOne("SELECT SUM(`recommending`) FROM ".$table." WHERE `content_id` = ? ", array($pParamHash['recommends_sum_store']['content_id']));
				$pParamHash['recommends_sum_store']['votes'] = $this->mDb->getOne("SELECT COUNT(`recommending`) FROM ".$table." WHERE `content_id` = ? AND recommending != 0", array($pParamHash['recommends_sum_store']['content_id']));
				if ($pParamHash['recommends_sum_store']['votes'] == $gBitSystem->getConfig('recommends_minimum_recommends', 10)) {
					$pParamHash['recommends_sum_store']['qualified_time'] = $gBitSystem->getUTCTime();
				}
				$result = $this->mDb->associateUpdate( $table_sum, $pParamHash['recommends_sum_store'], $locId);
			} else {
				$result = $this->mDb->associateInsert( $table, $pParamHash['recommends_store'] );
				$pParamHash['recommends_sum_store']['content_id'] = $pParamHash['recommends_store']['content_id'];
				$pParamHash['recommends_sum_store']['recommending'] = $this->mDb->getOne("SELECT SUM(recommending) FROM ".$table." WHERE `content_id` = ? ", array($pParamHash['recommends_store']['content_id']));
				$pParamHash['recommends_sum_store']['votes'] = $this->mDb->getOne("SELECT COUNT(`recommending`) FROM ".$table." WHERE `content_id` = ? AND recommending != 0", array($pParamHash['recommends_sum_store']['content_id']));
				if ($pParamHash['recommends_sum_store']['votes'] == $gBitSystem->getConfig('recommends_minimum_recommends', 10)) {
					$pParamHash['recommends_sum_store']['qualified_time'] = $gBitSystem->getUTCTime();
				}
				
				if ($this->getRecommending( $pParamHash['content_id'] ) ) {
					$result = $this->mDb->associateUpdate( $table_sum, $pParamHash['recommends_sum_store'], array('content_id' => $pParamHash['recommends_sum_store']['content_id']));
				}
				else {
					$result = $this->mDb->associateInsert( $table_sum, $pParamHash['recommends_sum_store'] );
				}
			}
			$this->mDb->CompleteTrans();			
		}
		return( count( $this->mErrors )== 0 );
	}

	/**
	 * Make sure the data is safe to store
	 *
	 * @param array pParams reference to hash of values that will be used to store the page, they will be modified where necessary
	 * @return bool TRUE on success, FALSE if verify failed. If FALSE, $this->mErrors will have reason why
	 * @access private
	 **/
	function verify( &$pParamHash ) {
		global $gBitUser, $gBitSystem;

		if( $gBitUser->isRegistered() && $this->isValid() ) {
			$this->load();
			$timeout = $gBitSystem->getUTCTime() - ($gBitSystem->getConfig('recommends_recommend_period', 15) * RECOMMENDS_PERIOD_SCALE);
			$timeout_change = $gBitSystem->getUTCTime() - ($gBitSystem->getConfig('recommends_change_timeout', 1) * RECOMMENDS_TIMEOUT_CHANGE_SCALE);
			if( (!$gBitSystem->isFeatureActive('recommends_recommend_period') || $this->mInfo['created'] > $timeout) && (empty($this->mInfo['recommends_time']) || $this->mInfo['recommends_time'] > $timeout_change)) {
				if( empty($this->mInfo['recommends_changes']) || $this->mInfo['recommends_changes'] < $gBitSystem->getConfig('recommends_max_changes', 1) ) {
					$pParamHash['content_id'] = $this->mContentId;
					$pParamHash['recommending'] = $pParamHash['recommends_recommending'];
					if( ($pParamHash['recommending'] == 1 || $pParamHash['recommending'] == -1 || $pParamHash['recommending'] == 0) && $this->isValid() ) {			  	
						// recommends table
						$pParamHash['recommends_store']['content_id']  = $pParamHash['recommends_store']['content_id'] = ( int )$this->mContentId;
						$pParamHash['recommends_store']['recommending']      = ( int )$pParamHash['recommending'];
						$pParamHash['recommends_store']['recommending_time'] = ( int )BitDate::getUTCTime();
						$pParamHash['recommends_store']['user_id']     = ( int )$gBitUser->mUserId;
						$pParamHash['recommends_store']['changes']     = !isset($this->mInfo['recommends_changes']) ? 0 : $this->mInfo['recommends_changes'] + 1;
					} else {
						$this->mErrors['recommending_bad'] = tra("Invalid recommendation.");
					}
				} else {
					$this->mErrors['recommending_changes'] = tra('Maximum number of changes already made.');
				}
			}
			else {
				$this->mErrors['recommending_timeout'] = tra("Recommendation period has expired");
			}
		} else {
			$this->mErrors['unregistered'] = tra("You have to be registered to recommend content.");
		}
		return( count( $this->mErrors )== 0 );
	}

	/**
	 * Get the recommending of the currently active user for the specified content
	 * 
	 * @param array $pContentId 
	 * @access public
	 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
	 */
	function getUserRecommending( $pContentId = NULL ) {
		global $gBitSystem, $gBitUser;
		$ret = FALSE;
		if( !@BitBase::verifyId( $pContentId ) && $this->isValid() ) {
			$pContentId = $this->mContentId;
		}

		if( @BitBase::verifyId( $pContentId ) ) {
			$query = "
				SELECT `recommending`
				FROM `".BIT_DB_PREFIX."recommends`
				WHERE `content_id`=? AND `user_id`=?";
			$ret = $this->mDb->getRow( $query, array( $pContentId, $gBitUser->mUserId ) );
		}
		return $ret;
	}

	/**
	 * Get the recommending for the specified content
	 * 
	 * @param array $pContentId 
	 * @access public
	 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
	 */
	function getRecommending( $pContentId = NULL ) {
		global $gBitSystem, $gBitUser;
		$ret = FALSE;
		if( !@BitBase::verifyId( $pContentId ) && $this->isValid() ) {
			$pContentId = $this->mContentId;
		}

		if( @BitBase::verifyId( $pContentId ) ) {
			$query = "
				SELECT `recommending`
				FROM `".BIT_DB_PREFIX."recommends_sum`
				WHERE `content_id`=?";
			$ret = $this->mDb->getRow( $query, array( $pContentId ) );
		}
		return $ret;
	}

	/**
	 * Check if the mContentId is set and valid
	 * 
	 * @access public
	 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
	 */
	function isValid() {
		return( @BitBase::verifyId( $this->mContentId ) );
	}

	/**
	 * This function removes a recommends entry
	 * 
	 * @access public
	 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
	 */
	function expunge() {
		$ret = FALSE;
		if( $this->isValid() ) {
			$query = "DELETE FROM `".BIT_DB_PREFIX."recommends` WHERE `content_id` = ?";
			$result = $this->mDb->query( $query, array( $this->mContentId ) );
			$query = "DELETE FROM `".BIT_DB_PREFIX."recommends_sum` WHERE `content_id` = ?";
			$result = $this->mDb->query( $query, array( $this->mContentId ) );
		}
		return $ret;
	}
}

/********* SERVICE FUNCTIONS *********/

/**
 * Content list sql service function
 * 
 * @param array $pObject 
 * @access public
 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
 */
function recommends_content_list_sql( &$pObject ) {
	global $gBitSystem, $gBitUser, $gBitSmarty;

	if( !empty($pObject->mContentId) && $gBitSystem->isFeatureActive( 'recommends_recommend_'.$pObject->getContentType() ) ) {
		$ret['select_sql'] = ",
			lc.`content_id` AS `recommends_load`,
			rcms.`recommending` AS recommends_recommending,
			rcms.`votes` AS recommends_votes,
			rcm.`recommending` AS recommends_user_recommending ";
		$ret['join_sql'] = "
			LEFT JOIN `".BIT_DB_PREFIX."recommends_sum` rcms
				ON ( lc.`content_id`=rcms.`content_id` )
			LEFT JOIN `".BIT_DB_PREFIX."recommends` rcm
				ON ( lc.`content_id`=rcm.`content_id` AND rcm.`user_id`='".$gBitUser->mUserId."' )";
		return $ret;
	}
}

/**
 * Content load sql service function
 * 
 * @param array $pObject 
 * @access public
 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
 */
function recommends_content_load_sql( &$pObject ) {
	global $gBitSystem, $gBitThemes, $gBitUser, $gBitSmarty;
	if( $gBitSystem->isFeatureActive( 'recommends_recommend_'.$pObject->getContentType() ) ) {
		if( $gBitSystem->isFeatureActive( 'recommends_use_ajax' ) ) {
			$gBitThemes->loadAjax( 'mochikit' );
		}
		$ret['select_sql'] = ",
			lc.`content_id` AS `recommends_load`,
			rcms.`recommending` AS recommends_recommending,
			rcms.`votes` AS recommends_votes,
			( rcm.`recommending` ) AS recommends_user_recommending,
			( rcm.`changes` ) AS recommends_changes,
			( rcm.`recommending_time` ) AS recommends_time
";
		$ret['join_sql'] = "
			LEFT JOIN `".BIT_DB_PREFIX."recommends_sum` rcms
				ON ( lc.`content_id`=rcms.`content_id` )
			LEFT JOIN `".BIT_DB_PREFIX."recommends` rcm
				ON ( lc.`content_id`=rcm.`content_id` AND rcm.`user_id`='".$gBitUser->mUserId."' )";
		$dt = $gBitSystem->getUTCTime();
		$gBitSmarty->assign('recommends_user_timeout', $dt - ($gBitSystem->getConfig('recommends_change_timeout', 1) * RECOMMENDS_TIMEOUT_CHANGE_SCALE));

		if ( $gBitSystem->isFeatureActive('recommends_recommend_period') ) {
			$gBitSmarty->assign('recommends_timeout', $dt - ($gBitSystem->getConfig('recommends_recommend_period', 15) * RECOMMENDS_PERIOD_SCALE));
		}
		return $ret;
	}
}

/**
 * Content expunge sql service function
 * 
 * @param array $pObject 
 * @param array $pParamHash 
 * @access public
 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
 */
function recommends_content_expunge( &$pObject, &$pParamHash ) {
	$recommends = new LibertyRecommends( $pObject->mContentId );
	$recommends->expunge();
}
?>
Return current item: Bitweaver