/** * Merges the records for two players, retaining the id of the destination player * @param int $source_player_id * @param int $destination_player_id * @return void */ public function MergePlayers(Player $source_player, Player $destination_player) { if (!$source_player->GetId()) { throw new Exception("source_player must have an Id"); } if (!$destination_player->GetId()) { throw new Exception("destination_player must have an Id"); } if ($source_player->GetPlayerRole() != PLAYER::PLAYER) { throw new Exception("Cannot merge source player because it's an extras player"); } if ($destination_player->GetPlayerRole() != PLAYER::PLAYER) { throw new Exception("Cannot merge destination player because it's an extras player"); } $players = $this->GetSettings()->GetTable("Player"); $batting = $this->GetSettings()->GetTable("Batting"); $bowling = $this->GetSettings()->GetTable("Bowling"); $matches = $this->GetSettings()->GetTable("Match"); $statistics = $this->GetSettings()->GetTable("PlayerMatch"); # Make a note of matches where source player was involved $sql = "SELECT DISTINCT match_team_id FROM {$batting} WHERE player_id = " . $source_player->GetId(); $result = $this->GetDataConnection()->query($sql); $source_batted = array(); while ($row = $result->fetch()) { $source_batted[] = $row->match_team_id; } $sql = "SELECT match_team_id FROM {$statistics}\n\t\t\t\tWHERE player_id = " . $source_player->GetId() . " AND (run_outs > 0 OR catches > 0)"; $result = $this->GetDataConnection()->query($sql); $source_fielded = array(); while ($row = $result->fetch()) { $source_fielded[] = $row->match_team_id; } $sql = "SELECT match_team_id FROM {$statistics}\n\t\t\t\tWHERE player_id = " . $source_player->GetId() . " AND wickets IS NOT NULL"; $result = $this->GetDataConnection()->query($sql); $source_bowled = array(); while ($row = $result->fetch()) { $source_bowled[] = $row->match_team_id; } $sql = "SELECT match_id FROM {$statistics}\n\t\t\t\tWHERE player_id = " . $source_player->GetId() . " AND player_of_match = 1"; $result = $this->GetDataConnection()->query($sql); $source_player_of_match = array(); while ($row = $result->fetch()) { $source_player_of_match[] = $row->match_id; } # Transfer batting and bowling $this->LoggedQuery("UPDATE {$batting} SET player_id = " . Sql::ProtectNumeric($destination_player->GetId()) . "\n\t\tWHERE player_id = " . Sql::ProtectNumeric($source_player->GetId())); $this->LoggedQuery("UPDATE {$batting} SET dismissed_by_id = " . Sql::ProtectNumeric($destination_player->GetId()) . "\n\t\tWHERE dismissed_by_id = " . Sql::ProtectNumeric($source_player->GetId())); $this->LoggedQuery("UPDATE {$batting} SET bowler_id = " . Sql::ProtectNumeric($destination_player->GetId()) . "\n\t\tWHERE bowler_id = " . Sql::ProtectNumeric($source_player->GetId())); $this->LoggedQuery("UPDATE {$bowling} SET player_id = " . Sql::ProtectNumeric($destination_player->GetId()) . "\n\t\tWHERE player_id = " . Sql::ProtectNumeric($source_player->GetId())); # Update dismissals in stats table too, because then fielding statistics will update correctly below. # Normally dismissals are updated with the batting, but here it's quite possible we are only updating the fielding. $this->LoggedQuery("UPDATE {$statistics} SET caught_by = " . Sql::ProtectNumeric($destination_player->GetId()) . "\n\t\tWHERE caught_by = " . Sql::ProtectNumeric($source_player->GetId())); $this->LoggedQuery("UPDATE {$statistics} SET run_out_by = " . Sql::ProtectNumeric($destination_player->GetId()) . "\n\t\tWHERE run_out_by = " . Sql::ProtectNumeric($source_player->GetId())); if (!$this->is_internal_delete) { # Doing an internal delete the destination player will be Unknown. Transfer batting and bowling # because that preserves the position for other bowlers and batters as well as related statistics # such as number of runs. But set player of the match to null because there's not much value in # setting it unknown. # Transfer player of the match award $this->LoggedQuery("UPDATE {$matches} SET player_of_match_id = " . Sql::ProtectNumeric($destination_player->GetId()) . ",\n\t\t\tdate_changed = " . gmdate('U') . "\n\t\t\tWHERE player_of_match_id = " . Sql::ProtectNumeric($source_player->GetId())); $this->LoggedQuery("UPDATE {$matches} SET player_of_match_home_id = " . Sql::ProtectNumeric($destination_player->GetId()) . ",\n\t\t\tdate_changed = " . gmdate('U') . "\n\t\t\tWHERE player_of_match_home_id = " . Sql::ProtectNumeric($source_player->GetId())); $this->LoggedQuery("UPDATE {$matches} SET player_of_match_away_id = " . Sql::ProtectNumeric($destination_player->GetId()) . ",\n\t\t\tdate_changed = " . gmdate('U') . "\n\t\t\tWHERE player_of_match_away_id = " . Sql::ProtectNumeric($source_player->GetId())); # If a user has claimed either player, remember that. If two different claimants, prefer the destination one. if ($source_player->GetUser() instanceof User and $source_player->GetUser()->GetId()) { $this->LoggedQuery("UPDATE {$players}\n\t\t\t\tSET user_id = " . Sql::ProtectNumeric($source_player->GetUser()->GetId()) . ",\n\t\t\t\tdate_changed = " . gmdate('U') . "\n\t\t\t\tWHERE player_id = " . Sql::ProtectNumeric($destination_player->GetId()) . " AND user_id = NULL"); } # Now that the source player's data has been moved, delete the source player $this->Delete(array($source_player->GetId())); } # Recalculate all the derived data # Note: this method is tightly integrated with the Delete() method. They call each other. When the source player # is deleted, above, it will call back into this method before all the derived statistics for the source player # have gone. Therefore the queries at the top of this method will find the source player still exists. That in turn # leads to these methods being called for a player which has only derived statistics, and no actual data. It is # important therefore to call DeleteObsoleteStatistics() to clear out the redundant records as soon as they created. require_once 'stoolball/statistics/statistics-manager.class.php'; $statistics_manager = new StatisticsManager($this->GetSettings(), $this->GetDataConnection()); if (count($source_batted)) { $statistics_manager->UpdateBattingStatistics(array($destination_player->GetId()), $source_batted); } if (count($source_fielded)) { $statistics_manager->UpdateFieldingStatistics(array($destination_player->GetId()), $source_fielded); } if (count($source_bowled)) { $statistics_manager->UpdateBowlingStatistics(array($destination_player->GetId()), $source_bowled); } foreach ($source_player_of_match as $match_id) { $statistics_manager->UpdatePlayerOfTheMatchStatistics($match_id); $statistics_manager->DeleteObsoleteStatistics($match_id); } $statistics_manager->UpdatePlayerStatistics(array($destination_player->GetId())); unset($statistics_manager); }
/** * @access public * @return void * @param int[] $a_ids * @desc Delete from the db the Matches matching the supplied ids. */ public function DeleteMatch($a_ids) { # check parameter if (!is_array($a_ids)) { die('No matches to delete'); } # build query $delete_sql = array(); $s_match = $this->GetSettings()->GetTable('Match'); $s_season_match = $this->GetSettings()->GetTable('SeasonMatch'); $s_mt = $this->GetSettings()->GetTable('MatchTeam'); $batting = $this->GetSettings()->GetTable('Batting'); $bowling = $this->GetSettings()->GetTable('Bowling'); $stats = $this->GetSettings()->GetTable('PlayerMatch'); $s_ids = join(', ', $a_ids); # delete batting and bowling $match_team_ids = array(); $result = $this->GetDataConnection()->query("SELECT match_team_id FROM {$s_mt} WHERE match_id IN ({$s_ids})"); while ($row = $result->fetch()) { $match_team_ids[] = $row->match_team_id; } $result->closeCursor(); if (count($match_team_ids)) { $match_team_ids = join(",", $match_team_ids); $delete_sql[] = "DELETE FROM {$batting} WHERE match_team_id IN ({$match_team_ids})"; $delete_sql[] = "DELETE FROM {$bowling} WHERE match_team_id IN ({$match_team_ids})"; } $this->GetDataConnection()->query("DELETE FROM {$stats} WHERE match_id IN ({$s_ids})"); # delete teams $delete_sql[] = "DELETE FROM {$s_mt} WHERE match_id IN ({$s_ids})"; # delete seasons $delete_sql[] = "DELETE FROM {$s_season_match} WHERE match_id IN ({$s_ids})"; # if this is a tournament, delete the matches $tournament_match_ids = array(); $s_sql = 'SELECT match_id FROM ' . $s_match . ' WHERE tournament_match_id IN (' . $s_ids . ') '; $result = $this->GetDataConnection()->query($s_sql); while ($row = $result->fetch()) { $tournament_match_ids[] = $row->match_id; } $result->closeCursor(); if (count($tournament_match_ids)) { $this->DeleteMatch($tournament_match_ids); } # delete comments thread $delete_sql[] = "DELETE FROM nsa_forum_message WHERE item_id IN ({$s_ids}) AND item_type = " . ContentType::STOOLBALL_MATCH; # delete match(es) $delete_sql[] = "DELETE FROM {$s_match} WHERE match_id IN ({$s_ids});"; # delete from short URL cache require_once 'http/short-url-manager.class.php'; $o_url_manager = new ShortUrlManager($this->GetSettings(), $this->GetDataConnection()); $s_sql = "SELECT short_url FROM {$s_match} WHERE match_id IN ({$s_ids})"; $result = $this->GetDataConnection()->query($s_sql); while ($row = $result->fetch()) { $o_url_manager->Delete($row->short_url); } $result->closeCursor(); unset($o_url_manager); # get players involved in the match before it's deleted, so that player statistics can be updated require_once 'stoolball/player-manager.class.php'; $player_manager = new PlayerManager($this->GetSettings(), $this->GetDataConnection()); $player_ids = $player_manager->ReadPlayersInMatch($a_ids); unset($player_manager); # Run the collected delete commands foreach ($delete_sql as $sql) { $this->LoggedQuery($sql); } # update player stats, removing this match and any players who featured only in this match require_once 'stoolball/statistics/statistics-manager.class.php'; $statistics_manager = new StatisticsManager($this->GetSettings(), $this->GetDataConnection()); if (count($player_ids)) { $statistics_manager->UpdatePlayerStatistics($player_ids); } unset($statistics_manager); return $this->GetDataConnection()->GetAffectedRows(); }