function OnLoadPageData()
 {
     require_once "data/process-manager.class.php";
     $this->process = new ProcessManager();
     if ($this->process->ReadyToDeleteAll()) {
         $stats = $this->GetSettings()->GetTable("PlayerMatch");
         $sql = "TRUNCATE TABLE {$stats}";
         $this->GetDataConnection()->query($sql);
     }
     $matches = $this->GetSettings()->GetTable("MatchTeam");
     $mt = $this->GetSettings()->GetTable('MatchTeam');
     $sql = "SELECT match_id, match_team_id FROM {$matches} ORDER BY match_team_id " . $this->process->GetQueryLimit();
     $result = $this->GetDataConnection()->query($sql);
     require_once "stoolball/player-manager.class.php";
     $player_manager = new PlayerManager($this->GetSettings(), $this->GetDataConnection());
     require_once 'stoolball/statistics/statistics-manager.class.php';
     $statistics_manager = new StatisticsManager($this->GetSettings(), $this->GetDataConnection());
     while ($row = $result->fetch()) {
         $affected_players = $player_manager->ReadPlayersInMatch(array($row->match_id));
         # generate player statistics from the data entered
         if (count($affected_players)) {
             $statistics_manager->UpdateBattingStatistics($affected_players, array($row->match_team_id));
             # get the match_team_id for the bowling that goes with this batting
             $sql = "SELECT match_team_id FROM {$mt}\n\t\t\t\t\t\tWHERE match_id = (SELECT match_id FROM {$mt} WHERE match_team_id = {$row->match_team_id})\n\t\t\t\t\t\tAND match_team_id != {$row->match_team_id}\n\t\t\t\t\t\tAND team_role IN (" . TeamRole::Home() . ", " . TeamRole::Away() . ")";
             $result2 = $this->GetDataConnection()->query($sql);
             $row2 = $result2->fetch();
             $bowling_match_team_id = $row2->match_team_id;
             $statistics_manager->UpdateFieldingStatistics($affected_players, array($bowling_match_team_id));
             $statistics_manager->UpdateBowlingStatistics($affected_players, array($bowling_match_team_id));
             $statistics_manager->UpdatePlayerOfTheMatchStatistics($row->match_id);
             $statistics_manager->DeleteObsoleteStatistics($row->match_id);
         }
         $this->process->OneMoreDone();
     }
 }
 /**
  * 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);
 }
 /**
  * @return void
  * @param Match $match
  * @param bool $is_first_innings
  * @desc Saves the batting and bowling scorecards for one innings
  */
 public function SaveScorecard(Match $match, $is_first_innings, ISearchIndexProvider $search)
 {
     # To add a scorecard there must always already be a match to update
     if (!$match->GetId()) {
         return;
     }
     # This isn't for tournaments
     if ($match->GetMatchType() == MatchType::TOURNAMENT) {
         return;
     }
     # Get tables
     $batting_table = $this->GetSettings()->GetTable("Batting");
     $bowling_table = $this->GetSettings()->GetTable("Bowling");
     $match_table = $this->GetSettings()->GetTable('Match');
     $mt = $this->GetSettings()->GetTable('MatchTeam');
     # Is this scorecard for the home or the away innings?
     $sql = "SELECT home_bat_first FROM {$match_table} WHERE match_id = " . Sql::ProtectNumeric($match->GetId());
     $result = $this->GetDataConnection()->query($sql);
     $row = $result->fetch();
     if (is_null($row->home_bat_first) or (bool) $row->home_bat_first === true) {
         $is_home_innings = $is_first_innings;
     } else {
         $is_home_innings = !$is_first_innings;
     }
     $result->closeCursor();
     # Prepare data for query
     if ($is_home_innings) {
         $bowling_team_id = $match->GetAwayTeamId();
         $batting_team_id = $match->GetHomeTeamId();
         $team_bowling = $match->Result()->AwayOvers();
         $team_batting = $match->Result()->HomeBatting();
     } else {
         $bowling_team_id = $match->GetHomeTeamId();
         $batting_team_id = $match->GetAwayTeamId();
         $team_bowling = $match->Result()->HomeOvers();
         $team_batting = $match->Result()->AwayBatting();
     }
     # Find the match_team_id for the bowling
     $sql = "SELECT match_team_id FROM {$mt}\r\n\t\t\t\tWHERE match_id " . Sql::ProtectNumeric($match->GetId(), false, true) . "\r\n\t\t\t\tAND team_id " . Sql::ProtectNumeric($bowling_team_id, false, true) . "\r\n\t\t\t\tAND team_role = " . ($is_home_innings ? TeamRole::Away() : TeamRole::Home());
     $result = $this->GetDataConnection()->query($sql);
     $row = $result->fetch();
     $bowling_match_team_id = $row->match_team_id;
     $result->closeCursor();
     # Find the match_team_id for the batting
     $sql = "SELECT match_team_id FROM {$mt}\r\n\t\t\t\tWHERE match_id " . Sql::ProtectNumeric($match->GetId(), false, true) . "\r\n\t\t\t\tAND team_id " . Sql::ProtectNumeric($batting_team_id, false, true) . "\r\n\t\t\t\tAND team_role = " . ($is_home_innings ? TeamRole::Home() : TeamRole::Away());
     $result = $this->GetDataConnection()->query($sql);
     $row = $result->fetch();
     $batting_match_team_id = $row->match_team_id;
     $result->closeCursor();
     $affected_players = $this->SaveBattingScorecard($match, $is_home_innings, $batting_match_team_id, $team_batting);
     $affected_bowlers = $this->SaveBowlingScorecard($match, $is_home_innings, $batting_match_team_id, $bowling_match_team_id, $team_bowling);
     $affected_players = array_merge($affected_players, $affected_bowlers);
     $affected_players = array_unique($affected_players);
     if (count($affected_players)) {
         require_once 'stoolball/statistics/statistics-manager.class.php';
         $statistics_manager = new StatisticsManager($this->GetSettings(), $this->GetDataConnection());
         # generate player statistics from the data entered
         $statistics_manager->UpdateBattingStatistics($affected_players, array($batting_match_team_id));
         $statistics_manager->UpdateFieldingStatistics($affected_players, array($bowling_match_team_id));
         $statistics_manager->UpdateBowlingStatistics($affected_players, array($bowling_match_team_id));
         $statistics_manager->DeleteObsoleteStatistics($match->GetId());
         # update overall stats for players
         $statistics_manager->UpdatePlayerStatistics($affected_players);
         unset($statistics_manager);
         # update search engine
         require_once "stoolball/player-manager.class.php";
         require_once "search/player-search-adapter.class.php";
         $player_manager = new PlayerManager($this->GetSettings(), $this->GetDataConnection());
         foreach ($affected_players as $player_id) {
             $player_manager->ReadPlayerById($player_id);
             $player = $player_manager->GetFirst();
             $search->DeleteFromIndexById("player" . $player_id);
             if ($player instanceof Player) {
                 $adapter = new PlayerSearchAdapter($player);
                 $search->Index($adapter->GetSearchableItem());
             }
         }
         $search->CommitChanges();
         unset($player_manager);
     }
 }