Skip to content

Instantly share code, notes, and snippets.

@fuelingtheweb
Created December 4, 2024 01:33
Show Gist options
  • Save fuelingtheweb/1de86958eda4950be62d443c6f92d39f to your computer and use it in GitHub Desktop.
Save fuelingtheweb/1de86958eda4950be62d443c6f92d39f to your computer and use it in GitHub Desktop.
app/Console/Commands/CreateWeek.php - Interacts with a college football API for weekly picks app
<?php
namespace App\Console\Commands;
use App\Models\Game;
use App\Models\Season;
use App\Models\Stat;
use App\Models\Team;
use App\Models\Week;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Http;
class CreateWeek extends Command
{
protected $signature = 'pickem:create-week';
protected $description = 'Create week';
private $weeks;
private $week;
private $teams;
public function handle(): void
{
$this->week = $this->upcomingWeek();
if (! $this->week) {
$this->error('No upcoming weeks found.');
return;
}
if ($this->previousWeekIsUnfinished()) {
$this->error("The previous week hasn't ended yet.");
return;
}
$this->createSeasonIfMissing();
$this->createGames($this->createWeek());
}
private function createSeasonIfMissing()
{
$season = Season::current();
if ($this->isCurrentSeason($season)) {
return;
}
$previousStats = $season?->stats ?? collect();
$season = Season::create([
'year' => $this->week['season'],
'type' => $this->week['seasonType'] == 'regular' ? 'reg' : 'pst',
]);
$previousStats->each(
fn ($stat) => Stat::create([
'user_id' => $stat->user_id,
'league_id' => $stat->league_id,
'season_id' => $season->id,
]),
);
}
private function isCurrentSeason($season)
{
if ($season?->year != $this->week['season']) {
return false;
}
return match ($this->week['seasonType']) {
'regular' => $season->type === 'reg',
'postseason' => $season->type === 'pst',
default => false,
};
}
private function createWeek()
{
return Week::create([
'name' => $this->week['seasonType'] == 'regular'
? "Week {$this->week['week']}"
: 'Bowls',
'season_id' => Season::where(['year' => $this->week['season'], 'type' => $this->typeFromApi()])->value('id'),
]);
}
private function typeFromApi()
{
return match ($this->week['seasonType']) {
'regular' => 'reg',
'postseason' => 'pst',
default => 'reg',
};
}
private function createGames(Week $week)
{
$this->teams = Team::pluck('id', 'espn_id');
$this->games()->each(fn ($game) => $this->createGame($week, $game));
}
private function createGame(Week $week, $game)
{
if ($game['home_division'] != 'fbs' || $game['away_division'] != 'fbs') {
return;
}
Game::create([
'espn_id' => $game['id'],
'week_id' => $week->id,
'home_team_id' => $this->teams->get($game['home_id']),
'away_team_id' => $this->teams->get($game['away_id']),
'name' => $game['notes'],
'kickoff' => $game['start_time_tbd']
? null
: Carbon::parse($game['start_date'], 'UTC')->tz(config('app.timezone')),
'is_neutral' => $game['neutral_site'],
'type' => str($game['notes'])->contains('CFP Semifinal')
? Game::TYPE_SEMIFINAL
: Game::TYPE_DEFAULT,
]);
}
private function upcomingWeek()
{
if (Season::latest()->value('year') < now()->year) {
return $this->weeks()->first();
}
return $this->weeks()->firstWhere(function ($week) {
return Carbon::parse($week['firstGameStart'])->isFuture();
});
}
private function previousWeekIsUnfinished()
{
$currentWeek = Week::current();
$previousWeek = $currentWeek
? $this->weeks()
->where('week', str($currentWeek->name)->remove('Week ')->toString())
->where('season', $currentWeek->season->year)
->first()
: null;
return $previousWeek && Carbon::parse($previousWeek['lastGameStart'])->isFuture();
}
private function weeks()
{
if ($this->weeks) {
return $this->weeks;
}
$response = Http::withToken(config('services.cfbd.token'))
->get('https://api.collegefootballdata.com/calendar', [
'year' => now()->year,
]);
return $this->weeks = collect($response->json());
}
private function games()
{
$response = Http::withToken(config('services.cfbd.token'))
->get('https://api.collegefootballdata.com/games', [
'year' => $this->week['season'],
'week' => $this->week['week'],
'seasonType' => $this->week['seasonType'],
'division' => 'fbs',
]);
return collect($response->json());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment