Location: PHPKode > scripts > Football Pool > football-pool/classes/class-football-pool-matches.php
<?php
class Football_Pool_Matches {
	private $joker_blocked;
	private $teams;
	private $matches_are_editable;
	public $joker_value;
	private $force_lock_time = false;
	private $lock;
	public $matches;
	public $always_show_predictions = 0;
	private $use_spin_controls = true;
	public $has_matches = false;
	private $time_format;
	
	public function __construct() {
		$this->joker_blocked = false;
		$this->enable_edits();
		
		$datetime = Football_Pool_Utils::get_fp_option( 'matches_locktime', '' );
		$this->force_lock_time = 
			( Football_Pool_Utils::get_fp_option( 'stop_time_method_matches', 0, 'int' ) == 1 )
			&& ( $datetime != '' );
		if ( $this->force_lock_time ) {
			//$date = DateTime::createFromFormat( 'Y-m-d H:i', $datetime );
			$date = new DateTime( Football_Pool_Utils::date_from_gmt( $datetime ) );
			$this->lock = $date->format( 'U' );
		} else {
			$this->lock = Football_Pool_Utils::get_fp_option( 'maxperiod', FOOTBALLPOOL_MAXPERIOD, 'int' );
		}
		// override hiding of predictions for editable matches?
		$this->always_show_predictions = (int) Football_Pool_Utils::get_fp_option( 'always_show_predictions' );
		// HTML5 number inputs?
		$this->use_spin_controls = ( Football_Pool_Utils::get_fp_option( 'use_spin_controls', 'int', 1 ) == 1 );
		
		// cache match info
		$this->matches = $this->match_info();
		$this->has_matches = ( count( $this->matches ) > 0 );
		
		$this->time_format = get_option( 'time_format', FOOTBALLPOOL_TIME_FORMAT );
	}
	
	public function disable_edits() {
		$this->matches_are_editable = false;
		$this->joker_blocked = true;
	}
	
	private function enable_edits() {
		$this->matches_are_editable = true;
	}
	
	public function get_next_match( $ts = -1 ) {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		
		if ( $ts == -1 ) $ts = time();
		
		$next_match = null;
		foreach ( $this->matches as $match ) {
			if ( $match['match_timestamp'] > $ts ) {
				$next_match = $match;
				break;
			}
		}
		
		return $next_match; // null if no match is found
	}
	
	public function get_last_matches ( $num_games = 4 ) {
		return $this->get_last_games( $num_games );
	}
	public function get_last_games( $num_games = 4 ) {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		$sql = $wpdb->prepare( "SELECT nr, homeTeamId, awayTeamId, homeScore, awayScore 
								FROM {$prefix}matches 
								WHERE playDate <= now() AND homeScore IS NOT NULL AND awayScore IS NOT NULL 
								ORDER BY playDate DESC, nr DESC 
								LIMIT %d", $num_games
					);
		return $wpdb->get_results( $sql, ARRAY_A );
	}
	
	public function get_match_sorting_method() {
		$order = Football_Pool_Utils::get_fp_option( 'match_sort_method', FOOTBALLPOOL_MATCH_SORT, 'int' );
		switch ( $order ) {
			case 1:
				$order = 'm.playDate DESC, m.nr DESC';
				break;
			case 0:
			default:
				$order = 'm.playDate ASC, m.nr ASC';
		}
		
		return $order;
	}
	
	private function matches_query( $where_clause = '' ) {
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		$sorting = self::get_match_sorting_method();
		
		return "SELECT 
					m.nr, 
					UNIX_TIMESTAMP(m.playDate) AS match_timestamp, m.playDate,
					m.homeTeamId, m.awayTeamId, 
					m.homeScore, m.awayScore, 
					s.name AS stadiumName, s.id AS stadiumId,
					t.name AS matchtype, t.id AS typeId
				FROM {$prefix}matches m, {$prefix}stadiums s, {$prefix}matchtypes t 
				WHERE m.stadiumId = s.id AND m.matchtypeId = t.id AND t.visibility = 1 {$where_clause}
				ORDER BY {$sorting}";
	}
	
	public function get_first_match_info() {
		return array_shift( $this->matches );
	}
	
	public function get_info( $type = null ) {
		global $wpdb;
		if ( is_array( $type ) && count( $type ) > 0 ) {
			$sql = $this->matches_query( ' AND t.id IN ( ' . implode( ',', $type ) . ' ) ' );
		} else {
			$sql = $this->matches_query();
		}
		return $wpdb->get_results( $sql, ARRAY_A );
	}
	
	private function match_info() {
		$cache_key = 'fp_match_info';
		$match_info = wp_cache_get( $cache_key );
		
		if ( $match_info === false ) {
			global $wpdb;
			$match_info = array();
			$teams = new Football_Pool_Teams;
			
			$rows = $wpdb->get_results( $this->matches_query(), ARRAY_A );
			foreach ( $rows as $row ) {
				$i = $row['nr'];
				$matchdate = new DateTime( $row['playDate'] );
				$ts = $matchdate->format( 'U' );
				
				$match_info[$i] = array();
				$match_info[$i]['match_datetime'] = $matchdate->format( 'd M Y H:i' );
				$match_info[$i]['match_timestamp'] = $ts;
				$match_info[$i]['playDate'] = $row['playDate'];
				$match_info[$i]['date'] = $row['playDate'];
				$match_info[$i]['home_score'] = $row['homeScore'];
				$match_info[$i]['away_score'] = $row['awayScore'];
				$match_info[$i]['home_team'] = ( 
						isset( $teams->team_names[(integer) $row['homeTeamId'] ] ) ? 
							$teams->team_names[(integer) $row['homeTeamId'] ] : 
							'' 
						);
				$match_info[$i]['away_team'] = ( 
						isset( $teams->team_names[(integer) $row['awayTeamId'] ] ) ? 
							$teams->team_names[(integer) $row['awayTeamId'] ] : 
							'' 
						);
				$match_info[$i]['home_team_id'] = $row['homeTeamId'];
				$match_info[$i]['away_team_id'] = $row['awayTeamId'];
				$match_info[$i]['match_is_editable'] = $this->match_is_editable( $ts );
				$match_info[$i]['nr'] = $row['nr'];
				$match_info[$i]['stadium_id'] = $row['stadiumId'];
				$match_info[$i]['stadium_name'] = $row['stadiumName'];
				$match_info[$i]['match_type_id'] = $row['typeId'];
				$match_info[$i]['match_type'] = $row['matchtype'];
			}
			
			wp_cache_set( $cache_key, $match_info );
		}
		
		return $match_info;
	}
	
	public function get_match_info( $match ) {
		if ( is_integer( $match ) && array_key_exists( $match, $this->matches ) ) 
			return $this->matches[$match];
		else
			return array();
	}
	
	public function get_match_info_for_user( $user, $match_ids = array() ) {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		$order = self::get_match_sorting_method();
		
		$ids = '';
		if ( is_array( $match_ids ) && count( $match_ids ) > 0 ) {
			$ids = ' AND m.nr IN ( ' . implode( ',', $match_ids ) . ' ) ';
		}
		
		$sql = $wpdb->prepare( "SELECT 
									m.homeTeamId, m.awayTeamId, 
									p.homeScore, p.awayScore, 
									p.hasJoker, t.name AS matchtype, 
									m.nr, m.playDate
								FROM {$prefix}matches m 
								JOIN {$prefix}matchtypes t 
									ON ( m.matchtypeId = t.id {$ids})
								LEFT OUTER JOIN {$prefix}predictions p 
									ON ( p.matchNr = m.nr AND p.userId = %d )
								WHERE t.visibility = 1
								ORDER BY {$order}",
								$user
							);
		
		return $wpdb->get_results( $sql, ARRAY_A );
	}
	
	public function get_joker_value_for_user( $user ) {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		
		$sql = $wpdb->prepare( "SELECT matchNr FROM {$prefix}predictions WHERE userId = %d AND hasJoker = 1"
								, $user );
		$joker = $wpdb->get_var( $sql );
		
		return $joker;
	}
	
	public function first_empty_match_for_user( $user ) {
		if ( ! is_integer( $user ) ) return 0;

		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		$sql = $wpdb->prepare( "SELECT m.nr FROM {$prefix}matches m 
								LEFT OUTER JOIN {$prefix}predictions p 
									ON ( p.matchNr = m.nr AND p.userId = %d )
								WHERE p.userId IS NULL
								ORDER BY m.playDate ASC, nr ASC LIMIT 1",
								$user
							);
		$row = $wpdb->get_row( $sql, ARRAY_A );
		
		return ( $row ) ? $row['nr'] : 0;
	}
	
	public function get_match_info_for_teams( $a, $b ) {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		$sql = $wpdb->prepare( "SELECT homeTeamId, awayTeamId, homeScore, awayScore 
								FROM {$prefix}matches 
								WHERE ( homeTeamId = %d AND awayTeamId = %d ) 
									OR ( homeTeamId = %d AND awayTeamId = %d )",
								$a, $b,
								$b, $a
							);
		
		$row = $wpdb->get_row( $sql, ARRAY_A );
		
		if ( $row ) {
			return array(
						$row['homeTeamId'] => $row['homeScore'], 
						$row['awayTeamId'] => $row['awayScore']
					);
		} else {
			return 0;
		}
	}
	
	/**
	 * Shows pool input for games that are still editable. For games where the edit period has expired 
	 * only the value is shown.
	 * The property matches_are_editable is used for the users page. It prevents the display of inputs
	 * and it prevents the display of games that are still editable. The latter to make sure users do 
	 * not copy results from each other. This may be overridden with the always_show_predictions option.
	 */
	public function show_pool_input( $name, $value, $ts ) {
		if ( $this->match_is_editable( $ts ) ) {
			if ( $this->matches_are_editable ) {
				if ( $this->use_spin_controls ) {
					$control = 'type="number" min="0" max="999"';
				} else {
					$control = 'type="text" maxlength="3"';
				}
				return sprintf( '<input %s name="%s" value="%s" class="prediction" />'
								, $control, $name, $value
						);
			} else {
				return ( $this->always_show_predictions == 1 ? $value : '' );
			}
		} else {
			return $value;
		}
	}
	
	public function print_matches( $matches ) {
		$matchtype = '';
		$date_title = '';
		
		$teams = new Football_Pool_Teams;
		$teamspage = Football_Pool::get_page_link( 'teams' );
		$statisticspage = Football_Pool::get_page_link( 'statistics' );
		
		$output = '<table class="matchinfo">';
		foreach ( $matches as $row ) {
			if ( $matchtype != $row['matchtype'] ) {
				$matchtype = $row['matchtype'];
				$output .= sprintf( '<tr><td class="matchtype" colspan="6">%s</td></tr>', __( $matchtype, FOOTBALLPOOL_TEXT_DOMAIN ) );
			}
			
			$matchdate = new DateTime( $row['playDate'] );
			$localdate = new DateTime( $this->format_match_time( $matchdate, 'Y-m-d H:i' ) );
			// Translators: this is a date format string (see http://php.net/date)
			$localdate_formatted = date_i18n( __( 'M d, Y', FOOTBALLPOOL_TEXT_DOMAIN )
											, $localdate->format( 'U' ) );
			if ( $date_title != $localdate_formatted ) {
				$date_title = $localdate_formatted;
				// Translators: this is a date format string (see http://php.net/date)
				$output .= sprintf( '<tr><td class="matchdate" colspan="6" title="%s">%s</td></tr>'
									, date_i18n( __( 'l', FOOTBALLPOOL_TEXT_DOMAIN )
												, $localdate->format( 'U' ) )
									, $date_title );
			}
			
			$team_name = ( isset( $teams->team_names[ (int) $row['homeTeamId'] ] ) ?
								$teams->team_names[ (int) $row['homeTeamId'] ] : '' );
			if ( $teams->show_team_links ) {
				$team_name = sprintf( '<a href="%s">%s</a>'
										, esc_url( add_query_arg( array( 'team' => $row['homeTeamId'] ), $teamspage ) )
										, $team_name
								);
			}
			$output .= sprintf( '<tr title="%s %s">
									<td class="time">%s</td>
									<td class="home">%s</td>
									<td class="flag">%s</td>',
							__( 'match', FOOTBALLPOOL_TEXT_DOMAIN ),
							$row['nr'],
							$localdate->format( $this->time_format ),
							$team_name,
							$teams->flag_image( (integer) $row['homeTeamId'] )
						);
			$output .= sprintf( '<td class="score"><a href="%s">%s - %s</a></td>',
							esc_url( 
								add_query_arg(
									array( 'view' => 'matchpredictions', 'match' => $row['nr'] ), 
									$statisticspage 
								)
							),
							$row['homeScore'],
							$row['awayScore']
						);
			$team_name = ( isset( $teams->team_names[ (int) $row['awayTeamId'] ] ) ?
								$teams->team_names[ (int) $row['awayTeamId'] ] : '' );
			if ( $teams->show_team_links ) {
				$team_name = sprintf( '<a href="%s">%s</a>'
										, esc_url( add_query_arg( array( 'team' => $row['awayTeamId'] ), $teamspage ) )
										, $team_name
								);
			}
			$output .= sprintf( '<td class="flag">%s</td>
								<td class="away">%s</td>
								</tr>',
							$teams->flag_image( (integer) $row['awayTeamId'] ),
							$team_name
						);
		}
		$output .= '</table>';
		
		return $output;
	}
	
	public function print_matches_for_input( $matches, $form_id ) {
		$teams = new Football_Pool_Teams;
		$date_title = '';
		$matchtype = '';
		$joker = '';
		
		$output = sprintf( '<table id="matchinfo-%d" class="matchinfo input" border="1">', $form_id );
		foreach ( $matches as $row ) {
			if ( $matchtype != $row['matchtype'] ) {
				$matchtype = $row['matchtype'];
				$output .= sprintf( '<tr><td class="matchtype" colspan="11">%s</td></tr>'
									, __( $matchtype, FOOTBALLPOOL_TEXT_DOMAIN ) 
							);
			}
			
			$matchdate = new DateTime( $row['playDate'] );
			$localdate = new DateTime( $this->format_match_time( $matchdate, 'Y-m-d H:i' ) );
			$localdate_formatted = date_i18n( __( 'M d, Y', FOOTBALLPOOL_TEXT_DOMAIN )
											, $localdate->format( 'U' ) );
			if ( $date_title != $localdate_formatted ) {
				$date_title = $localdate_formatted;
				$output .= sprintf( '<tr><td class="matchdate" colspan="11">%s</td></tr>', $date_title );
			}
			
			if ( (int) $row['hasJoker'] == 1 ) {
				$joker = (int) $row['nr'];
			}
			
			$info = $this->get_match_info( (int) $row['nr'] );
			
			$home_team = isset( $teams->team_names[ (int) $info['home_team_id'] ] ) ?
							htmlentities( $teams->team_names[ (int) $info['home_team_id'] ], null, 'UTF-8' ) :
							'';
			$away_team = isset( $teams->team_names[ (int) $info['away_team_id'] ] ) ?
							htmlentities( $teams->team_names[ (int) $info['away_team_id'] ], null, 'UTF-8' ) :
							'';
			$output .= sprintf( '<tr id="match-%d-%d">
								<td class="time">%s</td>
								<td class="home">%s</td>
								<td class="flag">%s</td>
								<td class="score">%s</td>
								<td>-</td>
								<td class="score">%s</td>
								<td class="flag">%s</td>
								<td class="away">%s</td>
								%s
								<td title="%s" class="numeric">%s</td>
								<td>%s</td>
								</tr>',
							$info['nr'],
							$form_id,
							$localdate->format( $this->time_format ),
							$home_team,
							$teams->flag_image( (int) $info['home_team_id'] ),
							$this->show_pool_input( '_home_' . $info['nr'], $row['homeScore'], $info['match_timestamp'] ),
							$this->show_pool_input( '_away_' . $info['nr'], $row['awayScore'], $info['match_timestamp'] ),
							$teams->flag_image( (int) $info['away_team_id'] ),
							$away_team,
							$this->show_pool_joker( $joker, (int) $info['nr'], $info['match_timestamp']
													, $form_id ),
							__( 'score', FOOTBALLPOOL_TEXT_DOMAIN ),
							$this->show_score( $info['home_score'], $info['away_score'], $row['homeScore'], $row['awayScore'], $row['hasJoker'], $info['match_timestamp'] ),
							$this->show_users_link( $info['nr'], $info['match_timestamp'] )
						);
		}
		$output .= '</table>';
		
		$this->joker_value = $joker;
		return $output;
	}
	
	public function format_match_time( $datetime, $format = false ) {
		if ( $format === false ) $format = $this->time_format;
		
		$display = Football_Pool_Utils::get_fp_option( 'match_time_display' );
		if ( $display == 0 ) { // WordPress setting
			$datetime = new DateTime( Football_Pool_Utils::date_from_gmt( $datetime->format( 'Y-m-d H:i' ) ) );
		} elseif ( $display == 2 ) { // custom setting
			$offset = 60 * 60 * (float) Football_Pool_Utils::get_fp_option( 'match_time_offset' );
			if ( $offset >= 0 ) $offset = '+' . $offset;
			$datetime->modify( $offset . ' seconds' );
		} // else UTC
		
		return $datetime->format( $format );
	}
	
	public function get_match_types() {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		
		$sql = "SELECT id, name, visibility FROM {$prefix}matchtypes ORDER BY id ASC";
		return $wpdb->get_results( $sql );
	}
	
	public function get_match_type_by_id( $id ) {
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		
		$sql = $wpdb->prepare( "SELECT id, name, visibility FROM {$prefix}matchtypes WHERE id = %d", $id );
		return $wpdb->get_row( $sql );
	}
	
	public function get_match_type_by_name( $name, $addnew = 'no' ) {
		if ( $name == '' ) return 0;
		
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		
		$sql = $wpdb->prepare( "SELECT id, name, visibility FROM {$prefix}matchtypes WHERE name = %s", $name );
		$result = $wpdb->get_row( $sql );
		
		if ( $addnew == 'addnew' && $result == null ) {
			$sql = $wpdb->prepare( "INSERT INTO {$prefix}matchtypes ( name ) VALUES ( %s )", $name );
			$wpdb->query( $sql );
			$id = $wpdb->insert_id;
			$result = (object) array( 
									'id' => $id, 
									'name' => $name, 
									'visibility' => 1, 
									'inserted' => true 
									);
		}
		
		return $result;
	}
	
	public function get_matches_for_match_type( $ids = array() ) {
		if ( count( $ids ) == 0 ) return array();
		
		global $wpdb;
		$prefix = FOOTBALLPOOL_DB_PREFIX;
		
		$matchtype_ids = implode( ',', $ids );
		$sql = "SELECT nr FROM {$prefix}matches WHERE matchtypeId IN ( {$matchtype_ids} )";
		$results = $wpdb->get_results( $sql );
		$matches = array();
		foreach ( $results as $row ) {
			$matches[] = $row->nr;
		}
		return $matches;
	}
	
	private function show_score( $home, $away, $user_home, $user_away, $joker, $ts ) {
		if ( ! $this->match_is_editable( $ts ) ) {
			$pool = new Football_Pool_Pool;
			return $pool->calc_score( $home, $away, $user_home, $user_away, $joker );
		}
	}
	
	private function show_users_link( $match, $ts ) {
		$output = '';
		if ( $this->always_show_predictions || ! $this->match_is_editable( $ts ) ) {
			$title = __( 'view other users predictions', FOOTBALLPOOL_TEXT_DOMAIN );
			$output .= sprintf( '<a href="%s" title="%s">'
							, esc_url(
								add_query_arg( 
										array( 'view' => 'matchpredictions', 'match' => $match ), 
										Football_Pool::get_page_link( 'statistics' ) )
								)
							, $title
						);
			$output .= sprintf( '<img src="%sassets/images/site/charts.png" alt="%s" title="%s" /></a>',
							FOOTBALLPOOL_PLUGIN_URL,
							$title,
							$title
						);
		}
		return $output;
	}
	
	public function match_is_editable( $ts ) {
		if ( $this->force_lock_time ) {
			$editable = ( current_time( 'timestamp' ) < $this->lock );
		} else {
			$diff = $ts - time();
			$editable = ( $diff > $this->lock );
		}
		
		return $editable;
	}
	
	private function block_joker() {
		$this->joker_blocked = true;
	}
	
	private function show_pool_joker( $joker, $match, $ts, $form_id = 1 ) {
		$add_joker = '';
		$style = '';
		
		$class = ( $joker == $match && $joker > 0 && $match > 0 ) ? 'fp-joker' : 'fp-nojoker';
		/*
		Make sure joker is not shown for matches that are editable in case 
		the matches_are_editable property is set to false. Unless we have the new 
		'always display predictions' set, in that case we can ignore this.
		*/
		if ( ! $this->always_show_predictions ) {
			if ( ! $this->matches_are_editable && $this->match_is_editable( $ts ) ) {
				$class = 'fp-nojoker';
			}
		}
		
		if ( $class == 'fp-joker' && ! $this->match_is_editable( $ts ) ) {
			$this->block_joker();
		}
		
		if ( ! $this->joker_blocked ) {
			if ( $this->match_is_editable( $ts ) ) {
				$add_joker = ' onclick="footballpool_change_joker( this.id )" title="' . __( 'use your joker?', FOOTBALLPOOL_TEXT_DOMAIN ) . '"';
			}
		} else {
			$class .= ' readonly';
		}
		return sprintf( '<td class="%s"%s id="match_%d_%d"></td>', $class, $add_joker, $match, $form_id );
	}

}
?>
Return current item: Football Pool