Implementing some services to reduce queries

This commit is contained in:
Matt Young 2024-07-11 16:17:39 -05:00
parent ee8003fd45
commit d803b7fd09
11 changed files with 78 additions and 46 deletions

View File

@ -9,14 +9,20 @@ use App\Models\Entry;
use App\Models\ScoreSheet; use App\Models\ScoreSheet;
use App\Models\User; use App\Models\User;
use App\Services\AuditionService; use App\Services\AuditionService;
use App\Services\EntryService;
use App\Services\UserService;
class CalculateScoreSheetTotal class CalculateScoreSheetTotal
{ {
protected AuditionService $auditionService; protected AuditionService $auditionService;
protected EntryService $entryService;
protected UserService $userService;
public function __construct(AuditionService $auditionService) public function __construct(AuditionService $auditionService, EntryService $entryService, UserService $userService)
{ {
$this->auditionService = $auditionService; $this->auditionService = $auditionService;
$this->entryService = $entryService;
$this->userService = $userService;
} }
public function __invoke(string $mode, Entry $entry, User $judge): array public function __invoke(string $mode, Entry $entry, User $judge): array
@ -49,10 +55,10 @@ class CalculateScoreSheetTotal
if ($mode !== 'seating' and $mode !== 'advancement') { if ($mode !== 'seating' and $mode !== 'advancement') {
throw new TabulationException('Invalid mode requested. Mode must be seating or advancement'); throw new TabulationException('Invalid mode requested. Mode must be seating or advancement');
} }
if (! $entry->exists()) { if (! $this->entryService->entryExists($entry)) {
throw new TabulationException('Invalid entry provided'); throw new TabulationException('Invalid entry provided');
} }
if (! $judge->exists()) { if (! $this->userService->userExists($judge)) {
throw new TabulationException('Invalid judge provided'); throw new TabulationException('Invalid judge provided');
} }
} }

View File

@ -26,11 +26,12 @@ class RankAuditionEntries
{ {
$this->basicValidation($mode, $audition); $this->basicValidation($mode, $audition);
$entries = match ($mode) { $entries = match ($mode) {
'seating' => $audition->entries()->forSeating()->get(), 'seating' => $audition->entries()->forSeating()->with('scoreSheets')->get(),
'advancement' => $audition->entries()->forAdvancement()->get(), 'advancement' => $audition->entries()->forAdvancement()->with('scoreSheets')->get(),
}; };
foreach ($entries as $entry) { foreach ($entries as $entry) {
$entry->setRelation('audition', $audition);
try { try {
$entry->score_totals = $this->calculator->calculate($mode, $entry); $entry->score_totals = $this->calculator->calculate($mode, $entry);
} catch (TabulationException $ex) { } catch (TabulationException $ex) {

View File

@ -25,7 +25,7 @@ class DrawController extends Controller
public function index(Request $request) public function index(Request $request)
{ {
$events = Event::with('auditions')->get(); $events = Event::with('auditions.flags')->get();
// $drawnAuditionsExist is true if any audition->hasFlag('drawn') is true // $drawnAuditionsExist is true if any audition->hasFlag('drawn') is true
$drawnAuditionsExist = Audition::whereHas('flags', function ($query) { $drawnAuditionsExist = Audition::whereHas('flags', function ($query) {
$query->where('flag_name', 'drawn'); $query->where('flag_name', 'drawn');

View File

@ -17,7 +17,7 @@ class RoomController extends Controller
if (! Auth::user()->is_admin) { if (! Auth::user()->is_admin) {
abort(403); abort(403);
} }
$rooms = Room::with('auditions.entries')->orderBy('name')->get(); $rooms = Room::with('auditions.entries','entries')->orderBy('name')->get();
return view('admin.rooms.index', ['rooms' => $rooms]); return view('admin.rooms.index', ['rooms' => $rooms]);
} }

View File

@ -21,6 +21,7 @@ class EntryController extends Controller
}); });
$auditions = Audition::open()->get(); $auditions = Audition::open()->get();
$students = Auth::user()->students; $students = Auth::user()->students;
$students->load('school');
return view('entries.index', ['entries' => $entries, 'students' => $students, 'auditions' => $auditions]); return view('entries.index', ['entries' => $entries, 'students' => $students, 'auditions' => $auditions]);
} }

View File

@ -5,11 +5,11 @@ namespace App\Http\Controllers;
use App\Models\Audition; use App\Models\Audition;
use App\Models\Entry; use App\Models\Entry;
use App\Models\JudgeAdvancementVote; use App\Models\JudgeAdvancementVote;
use App\Models\ScoreSheet;
use Exception; use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Gate;
use App\Models\ScoreSheet;
use function compact; use function compact;
use function redirect; use function redirect;
@ -20,6 +20,7 @@ class JudgingController extends Controller
public function index() public function index()
{ {
$rooms = Auth::user()->judgingAssignments; $rooms = Auth::user()->judgingAssignments;
$rooms->load('auditions');
return view('judging.index', compact('rooms')); return view('judging.index', compact('rooms'));
} }
@ -150,6 +151,7 @@ class JudgingController extends Controller
return redirect(url()->previous())->with('error', 'Error saving advancement vote'); return redirect(url()->previous())->with('error', 'Error saving advancement vote');
} }
} }
return null; return null;
} }
} }

View File

@ -2,6 +2,9 @@
namespace App\Providers; namespace App\Providers;
use App\Actions\Tabulation\AllJudgesCount;
use App\Actions\Tabulation\CalculateEntryScore;
use App\Actions\Tabulation\CalculateScoreSheetTotal;
use App\Models\Audition; use App\Models\Audition;
use App\Models\Entry; use App\Models\Entry;
use App\Models\Room; use App\Models\Room;
@ -25,12 +28,11 @@ use App\Observers\StudentObserver;
use App\Observers\SubscoreDefinitionObserver; use App\Observers\SubscoreDefinitionObserver;
use App\Observers\UserObserver; use App\Observers\UserObserver;
use App\Services\AuditionService; use App\Services\AuditionService;
use App\Services\DoublerService;
use App\Services\DrawService; use App\Services\DrawService;
use App\Services\EntryService; use App\Services\EntryService;
use App\Services\ScoreService; use App\Services\ScoreService;
use App\Services\SeatingService; use App\Services\UserService;
use App\Services\TabulationService; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
@ -40,36 +42,13 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function register(): void public function register(): void
{ {
$this->app->singleton(DrawService::class, function () { $this->app->singleton(CalculateScoreSheetTotal::class, CalculateScoreSheetTotal::class);
return new DrawService(); $this->app->singleton(CalculateEntryScore::class, AllJudgesCount::class);
}); $this->app->singleton(DrawService::class, DrawService::class);
// $this->app->singleton(AuditionService::class, AuditionService::class);
$this->app->singleton(AuditionService::class, function () { $this->app->singleton(EntryService::class, EntryService::class);
return new AuditionService(); $this->app->singleton(ScoreService::class, ScoreService::class);
}); $this->app->singleton(UserService::class, UserService::class);
//
// $this->app->singleton(SeatingService::class, function ($app) {
// return new SeatingService($app->make(TabulationService::class));
// });
//
$this->app->singleton(EntryService::class, function () {
return new EntryService();
});
$this->app->singleton(ScoreService::class, function () {
return new ScoreService();
});
//
// $this->app->singleton(TabulationService::class, function ($app) {
// return new TabulationService(
// $app->make(AuditionService::class),
// $app->make(ScoreService::class),
// $app->make(EntryService::class));
// });
//
// $this->app->singleton(DoublerService::class, function ($app) {
// return new DoublerService($app->make(AuditionService::class), $app->make(TabulationService::class), $app->make(SeatingService::class));
// });
} }
/** /**
@ -90,5 +69,6 @@ class AppServiceProvider extends ServiceProvider
User::observe(UserObserver::class); User::observe(UserObserver::class);
SeatingLimit::observe(SeatingLimitObserver::class); SeatingLimit::observe(SeatingLimitObserver::class);
Model::preventLazyLoading(! app()->isProduction());
} }
} }

View File

@ -4,6 +4,7 @@ namespace App\Services;
use App\Exceptions\AuditionServiceException; use App\Exceptions\AuditionServiceException;
use App\Models\Audition; use App\Models\Audition;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
class AuditionService class AuditionService
@ -11,9 +12,11 @@ class AuditionService
/** /**
* Create a new class instance. * Create a new class instance.
*/ */
public static Collection $allAuditionIds;
public function __construct() public function __construct()
{ {
// self::$allAuditionIds = Audition::pluck('id');
} }
/** /**
@ -44,6 +47,7 @@ class AuditionService
public function getJudges(Audition $audition) public function getJudges(Audition $audition)
{ {
$cacheKey = 'auditionJudges-'.$audition->id; $cacheKey = 'auditionJudges-'.$audition->id;
return Cache::remember($cacheKey, 10, function () use ($audition) { return Cache::remember($cacheKey, 10, function () use ($audition) {
$this->validateAudition($audition); $this->validateAudition($audition);
@ -71,4 +75,9 @@ class AuditionService
throw new AuditionServiceException('Invalid sort requested. Sort must be tiebreak or weight'); throw new AuditionServiceException('Invalid sort requested. Sort must be tiebreak or weight');
} }
} }
public function auditionExists($audition)
{
return self::$allAuditionIds->contains($audition->id);
}
} }

View File

@ -3,18 +3,15 @@
namespace App\Services; namespace App\Services;
use App\Models\Entry; use App\Models\Entry;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
class EntryService class EntryService
{ {
/** /**
* Create a new class instance. * Create a new class instance.
*/ */
public function __construct() public function __construct()
{ {
//
} }
public function isEntryLate(Entry $entry): bool public function isEntryLate(Entry $entry): bool
@ -25,4 +22,15 @@ class EntryService
return $entry->created_at > $entry->audition->entry_deadline; return $entry->created_at > $entry->audition->entry_deadline;
} }
public function entryExists(Entry $entry): bool
{
static $allEntryIds = null;
if ($allEntryIds === null) {
$allEntryIds = Entry::pluck('id');
}
return $allEntryIds->contains($entry->id);
}
} }

View File

@ -0,0 +1,23 @@
<?php
namespace App\Services;
use App\Models\User;
class UserService
{
public function __construct()
{
}
public function userExists(User $user): bool
{
static $allUserIds = null;
if ($allUserIds === null) {
$allUserIds = User::pluck('id');
}
return $allUserIds->contains($user->id);
}
}

View File

@ -8,6 +8,7 @@ use App\Models\Entry;
use App\Models\Room; use App\Models\Room;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
uses(RefreshDatabase::class); uses(RefreshDatabase::class);
@ -52,6 +53,7 @@ it('places entries in the proper order', function () {
enterScore($judge, $entries[2], $scoreArray3); enterScore($judge, $entries[2], $scoreArray3);
enterScore($judge, $entries[3], $scoreArray4); enterScore($judge, $entries[3], $scoreArray4);
enterScore($judge, $entries[4], $scoreArray5); enterScore($judge, $entries[4], $scoreArray5);
Artisan::call('cache:clear');
$ranker = new RankAuditionEntries(new AllJudgesCount()); $ranker = new RankAuditionEntries(new AllJudgesCount());
$expectedOrder = [4, 1, 3, 5, 2]; $expectedOrder = [4, 1, 3, 5, 2];
// Act // Act