From 3f2a24db272ece1f19618e360246e09f21d9a18b Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 11:13:17 -0400 Subject: [PATCH 1/7] Remove n+1 query on conferences page --- app/Http/Livewire/ConferenceList.php | 1 + app/Models/Conference.php | 7 ++++++- tests/Feature/ConferenceTest.php | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/Http/Livewire/ConferenceList.php b/app/Http/Livewire/ConferenceList.php index 337319bd..02821ce5 100644 --- a/app/Http/Livewire/ConferenceList.php +++ b/app/Http/Livewire/ConferenceList.php @@ -69,6 +69,7 @@ public function getConferencesProperty() ->sortByCfpOpening($this->sort) ->sortByCfpClosing($this->sort); }) + ->with('openIssues') ->get() ->groupByMonth($this->dateColumn()) ->sortKeys() diff --git a/app/Models/Conference.php b/app/Models/Conference.php index 219a1faf..872d4190 100644 --- a/app/Models/Conference.php +++ b/app/Models/Conference.php @@ -128,6 +128,11 @@ public function issues() return $this->hasMany(ConferenceIssue::class); } + public function openIssues() + { + return $this->issues()->whereOpen(); + } + // @todo: Deprecate? public static function closingSoonest() { @@ -332,7 +337,7 @@ public function isFavoritedBy(User $user) public function isFlagged() { - return $this->issues()->whereOpen()->exists(); + return $this->openIssues->isNotEmpty(); } public function isRejected() diff --git a/tests/Feature/ConferenceTest.php b/tests/Feature/ConferenceTest.php index 9a8f16ec..274440f6 100644 --- a/tests/Feature/ConferenceTest.php +++ b/tests/Feature/ConferenceTest.php @@ -1170,6 +1170,7 @@ function conferences_with_reported_issues_are_flagged() $conference->reportIssue('spam', 'Conference has spam', $user); + $conference->load('openIssues'); $this->assertTrue($conference->isFlagged()); } @@ -1178,6 +1179,7 @@ function conferences_with_closed_issues_are_not_flagged() { $conference = Conference::factory()->withClosedIssue()->create(); + $conference->load('openIssues'); $this->assertFalse($conference->isFlagged()); } From f10b59111bce3905bb2060c48551b68b92575412 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 12:00:03 -0400 Subject: [PATCH 2/7] Load the conference issue count instead of the whole relationship --- .../Controllers/ConferencesController.php | 3 ++ app/Http/Livewire/ConferenceList.php | 2 +- app/Models/Conference.php | 2 +- database/factories/ConferenceFactory.php | 11 ++++++ database/factories/ConferenceIssueFactory.php | 9 +++++ tests/Feature/ConferenceTest.php | 38 ++++++++++++++++++- 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/ConferencesController.php b/app/Http/Controllers/ConferencesController.php index 289efe74..6fa0151b 100644 --- a/app/Http/Controllers/ConferencesController.php +++ b/app/Http/Controllers/ConferencesController.php @@ -52,6 +52,8 @@ public function show($id) return TalkTransformer::transform($talk, $conference); }); + $conference->loadCount('openIssues'); + return view('conferences.show', [ 'conference' => $conference, 'talks' => $talks, @@ -119,6 +121,7 @@ public function destroy($id) private function showPublic($id) { $conference = Conference::approved()->findOrFail($id); + $conference->loadCount('openIssues'); return view('conferences.showPublic', [ 'conference' => $conference, diff --git a/app/Http/Livewire/ConferenceList.php b/app/Http/Livewire/ConferenceList.php index 02821ce5..b8fdc4e6 100644 --- a/app/Http/Livewire/ConferenceList.php +++ b/app/Http/Livewire/ConferenceList.php @@ -69,7 +69,7 @@ public function getConferencesProperty() ->sortByCfpOpening($this->sort) ->sortByCfpClosing($this->sort); }) - ->with('openIssues') + ->withCount('openIssues') ->get() ->groupByMonth($this->dateColumn()) ->sortKeys() diff --git a/app/Models/Conference.php b/app/Models/Conference.php index 872d4190..86702f68 100644 --- a/app/Models/Conference.php +++ b/app/Models/Conference.php @@ -337,7 +337,7 @@ public function isFavoritedBy(User $user) public function isFlagged() { - return $this->openIssues->isNotEmpty(); + return $this->open_issues_count > 0; } public function isRejected() diff --git a/database/factories/ConferenceFactory.php b/database/factories/ConferenceFactory.php index 1f7e1fb3..cf90f11b 100644 --- a/database/factories/ConferenceFactory.php +++ b/database/factories/ConferenceFactory.php @@ -138,6 +138,17 @@ public function withSpeakerPackage() ]); } + public function withOpenIssue() + { + return $this->afterCreating(function ($conference) { + ConferenceIssue::factory() + ->open() + ->create([ + 'conference_id' => $conference->id, + ]); + }); + } + public function withClosedIssue() { return $this->afterCreating(function ($conference) { diff --git a/database/factories/ConferenceIssueFactory.php b/database/factories/ConferenceIssueFactory.php index b65d5d7a..5935b11a 100644 --- a/database/factories/ConferenceIssueFactory.php +++ b/database/factories/ConferenceIssueFactory.php @@ -20,6 +20,15 @@ public function definition() ]; } + public function open() + { + return $this->state(function () { + return [ + 'closed_at' => null, + ]; + }); + } + public function closed() { return $this->state(function () { diff --git a/tests/Feature/ConferenceTest.php b/tests/Feature/ConferenceTest.php index 274440f6..c3ad3c19 100644 --- a/tests/Feature/ConferenceTest.php +++ b/tests/Feature/ConferenceTest.php @@ -1170,7 +1170,7 @@ function conferences_with_reported_issues_are_flagged() $conference->reportIssue('spam', 'Conference has spam', $user); - $conference->load('openIssues'); + $conference->loadCount('openIssues'); $this->assertTrue($conference->isFlagged()); } @@ -1179,7 +1179,7 @@ function conferences_with_closed_issues_are_not_flagged() { $conference = Conference::factory()->withClosedIssue()->create(); - $conference->load('openIssues'); + $conference->loadCount('openIssues'); $this->assertFalse($conference->isFlagged()); } @@ -1268,4 +1268,38 @@ public function rejected_conferences_are_not_searchable(): void $this->assertFalse($conferenceA->shouldBeSearchable()); $this->assertTrue($conferenceB->shouldBeSearchable()); } + + /** @test */ + public function conferences_with_open_issues_are_flagged_on_the_index_page(): void + { + $conference = Conference::factory()->withOpenIssue()->create(); + + $response = Livewire::test(ConferenceList::class); + + tap($response->conferences->flatten(), function ($conferences) { + $this->assertEquals(1, $conferences->count()); + $this->assertTrue($conferences->first()->isFlagged()); + }); + } + + /** @test */ + public function conferences_with_open_issues_are_flagged_on_the_show_page(): void + { + $conference = Conference::factory()->withOpenIssue()->create(); + + $response = $this->actingAs(User::factory()->create()) + ->get(route('conferences.show', $conference)); + + $response->assertSee('An issue has been reported for this conference.'); + } + + /** @test */ + public function conferences_with_open_issues_are_flagged_on_the_public_show_page(): void + { + $conference = Conference::factory()->withOpenIssue()->create(); + + $response = $this->get(route('conferences.show', $conference)); + + $response->assertSee('An issue has been reported for this conference.'); + } } From 936f1930132797d36ecfbb297927b4d8ad0d5331 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 12:17:27 -0400 Subject: [PATCH 3/7] Remove n+1 query on authenticated conferences page --- app/Http/Livewire/ConferenceList.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Livewire/ConferenceList.php b/app/Http/Livewire/ConferenceList.php index b8fdc4e6..ab227e5c 100644 --- a/app/Http/Livewire/ConferenceList.php +++ b/app/Http/Livewire/ConferenceList.php @@ -69,6 +69,7 @@ public function getConferencesProperty() ->sortByCfpOpening($this->sort) ->sortByCfpClosing($this->sort); }) + ->when(auth()->user(), fn ($query) => $query->with('submissions')) ->withCount('openIssues') ->get() ->groupByMonth($this->dateColumn()) From af093363cc387e1786a0e6fc1b26b2f2cb5eca04 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 12:49:27 -0400 Subject: [PATCH 4/7] Rename Talk::current relationship to currentRevision --- app/ApiResources/Talk.php | 18 +++++++++--------- app/Collections/TalksCollection.php | 2 +- app/Http/Controllers/SubmissionsController.php | 2 +- app/Http/Controllers/TalksController.php | 6 +++--- app/Models/Talk.php | 2 +- .../TalkForConferenceTransformer.php | 2 +- database/factories/TalkFactory.php | 2 +- .../account/public-profile/show.blade.php | 4 ++-- resources/views/talks/listing.blade.php | 4 ++-- resources/views/talks/show-public.blade.php | 6 +++--- resources/views/talks/show.blade.php | 2 +- tests/Feature/PublicSpeakerProfileTest.php | 2 +- tests/Feature/TalkTest.php | 12 ++++++------ tests/Feature/UserTest.php | 4 ++-- 14 files changed, 34 insertions(+), 34 deletions(-) diff --git a/app/ApiResources/Talk.php b/app/ApiResources/Talk.php index 85e8aa47..0e786f26 100644 --- a/app/ApiResources/Talk.php +++ b/app/ApiResources/Talk.php @@ -27,16 +27,16 @@ public function getType() public function attributes() { return [ - 'title' => $this->talk->current()->title, - 'description' => $this->talk->current()->description, - 'type' => $this->talk->current()->type, - 'length' => $this->talk->current()->length, - 'level' => $this->talk->current()->level, - 'slides' => $this->talk->current()->slides, + 'title' => $this->talk->currentRevision()->title, + 'description' => $this->talk->currentRevision()->description, + 'type' => $this->talk->currentRevision()->type, + 'length' => $this->talk->currentRevision()->length, + 'level' => $this->talk->currentRevision()->level, + 'slides' => $this->talk->currentRevision()->slides, 'public' => $this->talk->public, - 'organizer_notes' => $this->talk->current()->organizer_notes, - 'created_at' => (string) $this->talk->current()->created_at, - 'updated_at' => (string) $this->talk->current()->updated_at, + 'organizer_notes' => $this->talk->currentRevision()->organizer_notes, + 'created_at' => (string) $this->talk->currentRevision()->created_at, + 'updated_at' => (string) $this->talk->currentRevision()->updated_at, ]; } diff --git a/app/Collections/TalksCollection.php b/app/Collections/TalksCollection.php index 88bcec6c..4769b9e6 100644 --- a/app/Collections/TalksCollection.php +++ b/app/Collections/TalksCollection.php @@ -10,7 +10,7 @@ class TalksCollection extends Collection public function sortByTitle() { return $this->sortBy(function (Talk $talk) { - return strtolower($talk->current()->title); + return strtolower($talk->currentRevision()->title); })->values(); } } diff --git a/app/Http/Controllers/SubmissionsController.php b/app/Http/Controllers/SubmissionsController.php index 8c9084cf..ca8084f8 100644 --- a/app/Http/Controllers/SubmissionsController.php +++ b/app/Http/Controllers/SubmissionsController.php @@ -19,7 +19,7 @@ public function store(Request $request) } $conference = Conference::findOrFail($request->input('conferenceId')); - $talkRevision = $talk->current(); + $talkRevision = $talk->currentRevision(); $submission = $conference->submissions()->create(['talk_revision_id' => $talkRevision->id]); return response()->json([ diff --git a/app/Http/Controllers/TalksController.php b/app/Http/Controllers/TalksController.php index a492fa85..2c117dd7 100644 --- a/app/Http/Controllers/TalksController.php +++ b/app/Http/Controllers/TalksController.php @@ -74,7 +74,7 @@ public function edit($id) return view('talks.edit', [ 'talk' => $talk, - 'current' => $talk->current(), + 'current' => $talk->currentRevision(), ]); } @@ -103,7 +103,7 @@ public function show($id, Request $request) { $talk = auth()->user()->talks()->findOrFail($id); - $current = $request->filled('revision') ? $talk->revisions()->findOrFail($request->input('revision')) : $talk->current(); + $current = $request->filled('revision') ? $talk->revisions()->findOrFail($request->input('revision')) : $talk->currentRevision(); $submissions = Submission::where('talk_revision_id', $current->id) ->with(['conference', 'acceptance', 'rejection']) @@ -186,7 +186,7 @@ private function sortTalks($talks, $sort) $this->sorted_by = 'alpha'; return $talks->sortBy(function ($talk) { - return strtolower($talk->current()->title); + return strtolower($talk->currentRevision()->title); }); break; } diff --git a/app/Models/Talk.php b/app/Models/Talk.php index 04934c13..574f23f7 100644 --- a/app/Models/Talk.php +++ b/app/Models/Talk.php @@ -59,7 +59,7 @@ public function acceptances() return $this->hasManyThrough(Acceptance::class, TalkRevision::class); } - public function current() + public function currentRevision() { return $this->revisions()->orderBy('created_at', 'DESC')->first(); } diff --git a/app/Transformers/TalkForConferenceTransformer.php b/app/Transformers/TalkForConferenceTransformer.php index 29d3a175..9116d1d4 100644 --- a/app/Transformers/TalkForConferenceTransformer.php +++ b/app/Transformers/TalkForConferenceTransformer.php @@ -9,7 +9,7 @@ class TalkForConferenceTransformer { public static function transform(Talk $talk, Conference $conference) { - $currentTalk = $talk->current(); + $currentTalk = $talk->currentRevision(); $submission = $talk->getMySubmissionForConference($conference); $acceptance = $submission ? $submission->acceptance : null; diff --git a/database/factories/TalkFactory.php b/database/factories/TalkFactory.php index 65ecacf3..c0968d44 100644 --- a/database/factories/TalkFactory.php +++ b/database/factories/TalkFactory.php @@ -40,7 +40,7 @@ public function author(User $user) public function submitted() { return $this->afterCreating(function (Talk $talk) { - Conference::factory()->received($talk->current())->create(); + Conference::factory()->received($talk->currentRevision())->create(); }); } diff --git a/resources/views/account/public-profile/show.blade.php b/resources/views/account/public-profile/show.blade.php index 1a048015..6e504ea0 100755 --- a/resources/views/account/public-profile/show.blade.php +++ b/resources/views/account/public-profile/show.blade.php @@ -34,11 +34,11 @@ class="no-underline block mt-8 text-indigo" @forelse ($talks as $talk)

- {{ $talk->current()->title }} + {{ $talk->currentRevision()->title }}

- {{ $talk->current()->length }}-minute {{ $talk->current()->type }} talk at {{ $talk->current()->level }} level + {{ $talk->currentRevision()->length }}-minute {{ $talk->currentRevision()->type }} talk at {{ $talk->currentRevision()->level }} level @empty This speaker has not made any of their talks public yet. diff --git a/resources/views/talks/listing.blade.php b/resources/views/talks/listing.blade.php index c8b71264..252d7e9d 100644 --- a/resources/views/talks/listing.blade.php +++ b/resources/views/talks/listing.blade.php @@ -1,4 +1,4 @@ - + @svg('compose', 'w-5 fill-current inline') @@ -22,7 +22,7 @@
{{ $talk->created_at->toFormattedDateString() }}
-
{{ $talk->current()->length }}-minute {{ $talk->current()->level }} {{ $talk->current()->type }}
+
{{ $talk->currentRevision()->length }}-minute {{ $talk->currentRevision()->level }} {{ $talk->currentRevision()->type }}
diff --git a/resources/views/talks/show-public.blade.php b/resources/views/talks/show-public.blade.php index c93df81e..8412c076 100644 --- a/resources/views/talks/show-public.blade.php +++ b/resources/views/talks/show-public.blade.php @@ -11,15 +11,15 @@ class="inline-block" Return to profile for {{ $user->name }} -

{{ $talk->current()->title }}

+

{{ $talk->currentRevision()->title }}

- {{ $talk->current()->length }} minute {{ $talk->current()->level }} {{ $talk->current()->type }} + {{ $talk->currentRevision()->length }} minute {{ $talk->currentRevision()->level }} {{ $talk->currentRevision()->type }}

Description/Proposal

- {!! markdown($talk->current()->getDescription()) !!} + {!! markdown($talk->currentRevision()->getDescription()) !!} @endsection diff --git a/resources/views/talks/show.blade.php b/resources/views/talks/show.blade.php index f7fb859c..740e9762 100644 --- a/resources/views/talks/show.blade.php +++ b/resources/views/talks/show.blade.php @@ -9,7 +9,7 @@ @foreach ($talk->revisions as $revision) - @if ($talk->current()->id == $revision->id) + @if ($talk->currentRevision()->id == $revision->id)
revisions()->save($talkRevision); $this->get(route('speakers-public.show', [$user->profile_slug])) - ->assertDontSee($talk->current()->title); + ->assertDontSee($talk->currentRevision()->title); } /** @test */ diff --git a/tests/Feature/TalkTest.php b/tests/Feature/TalkTest.php index 05bb6cbd..e85f3302 100644 --- a/tests/Feature/TalkTest.php +++ b/tests/Feature/TalkTest.php @@ -79,8 +79,8 @@ public function user_talks_are_sorted_alphabetically() $talk1 = Talk::factory()->author($user)->revised(['title' => 'zyxwv'])->create(); $talk2 = Talk::factory()->author($user)->revised(['title' => 'abcde'])->create(); - $this->assertEquals('abcde', $user->talks->sortByTitle()->first()->current()->title); - $this->assertEquals('zyxwv', $user->talks->sortByTitle()->last()->current()->title); + $this->assertEquals('abcde', $user->talks->sortByTitle()->first()->currentRevision()->title); + $this->assertEquals('zyxwv', $user->talks->sortByTitle()->last()->currentRevision()->title); } /** @test */ @@ -224,7 +224,7 @@ public function user_can_save_a_new_revision_of_a_talk() ]); $this->actingAs($user) - ->put("/talks/{$talk->id}", array_merge($talk->current()->toArray(), [ + ->put("/talks/{$talk->id}", array_merge($talk->currentRevision()->toArray(), [ 'title' => 'New', 'public' => '1', ])); @@ -232,7 +232,7 @@ public function user_can_save_a_new_revision_of_a_talk() $talk = Talk::first(); $this->assertTrue($talk->public); - $this->assertEquals('New', $talk->current()->title); + $this->assertEquals('New', $talk->currentRevision()->title); $this->assertEquals('old title', $talk->revisions->last()->title); } @@ -262,7 +262,7 @@ function revised_talks_must_include_a_valid_length() $talk = Talk::factory()->author($user)->create(); $response = $this->actingAs($user) - ->put("/talks/{$talk->id}", array_merge($talk->current()->toArray(), [ + ->put("/talks/{$talk->id}", array_merge($talk->currentRevision()->toArray(), [ 'length' => 'invalid', ])); @@ -276,7 +276,7 @@ function revised_talks_with_slides_must_include_a_valid_slides_url() $talk = Talk::factory()->author($user)->create(); $response = $this->actingAs($user) - ->put("/talks/{$talk->id}", array_merge($talk->current()->toArray(), [ + ->put("/talks/{$talk->id}", array_merge($talk->currentRevision()->toArray(), [ 'slides' => 'invalid url', ])); diff --git a/tests/Feature/UserTest.php b/tests/Feature/UserTest.php index fd8032f7..c86c02cd 100644 --- a/tests/Feature/UserTest.php +++ b/tests/Feature/UserTest.php @@ -60,13 +60,13 @@ function getting_conference_submissions() $conference = Conference::factory()->create(); $conference->submissions()->create([ - 'talk_revision_id' => $talk->current()->id, + 'talk_revision_id' => $talk->currentRevision()->id, ]); $this->assertEquals(1, $user->talkRevisions()->count()); $this->assertEquals(1, $user->submissions()->count()); $this->assertEquals( - $talk->current()->id, + $talk->currentRevision()->id, $user->submissions->first()->talk_revision_id, ); } From d5d9b40b3fe6f2b0b2e89aef1c9f9b49cbc56dd5 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 14:59:31 -0400 Subject: [PATCH 5/7] Remove n+1 query for current talk revision --- app/ApiResources/Talk.php | 18 ++++++++-------- app/Collections/TalksCollection.php | 2 +- app/Http/Controllers/Api/TalksController.php | 2 +- .../Controllers/Api/UserTalksController.php | 1 + .../Controllers/ConferencesController.php | 2 +- .../Controllers/PublicProfileController.php | 2 +- .../Controllers/SubmissionsController.php | 2 +- app/Http/Controllers/TalksController.php | 14 ++++++------- app/Models/Talk.php | 21 ++++++++++++++++++- .../TalkForConferenceTransformer.php | 2 +- database/factories/TalkFactory.php | 4 +++- .../account/public-profile/show.blade.php | 4 ++-- resources/views/talks/listing.blade.php | 4 ++-- resources/views/talks/show-public.blade.php | 6 +++--- resources/views/talks/show.blade.php | 2 +- tests/Feature/PublicSpeakerProfileTest.php | 4 +++- tests/Feature/TalkTest.php | 14 +++++++------ tests/Feature/UserTest.php | 4 ++-- 18 files changed, 67 insertions(+), 41 deletions(-) diff --git a/app/ApiResources/Talk.php b/app/ApiResources/Talk.php index 0e786f26..2f993d57 100644 --- a/app/ApiResources/Talk.php +++ b/app/ApiResources/Talk.php @@ -27,16 +27,16 @@ public function getType() public function attributes() { return [ - 'title' => $this->talk->currentRevision()->title, - 'description' => $this->talk->currentRevision()->description, - 'type' => $this->talk->currentRevision()->type, - 'length' => $this->talk->currentRevision()->length, - 'level' => $this->talk->currentRevision()->level, - 'slides' => $this->talk->currentRevision()->slides, + 'title' => $this->talk->currentRevision->title, + 'description' => $this->talk->currentRevision->description, + 'type' => $this->talk->currentRevision->type, + 'length' => $this->talk->currentRevision->length, + 'level' => $this->talk->currentRevision->level, + 'slides' => $this->talk->currentRevision->slides, 'public' => $this->talk->public, - 'organizer_notes' => $this->talk->currentRevision()->organizer_notes, - 'created_at' => (string) $this->talk->currentRevision()->created_at, - 'updated_at' => (string) $this->talk->currentRevision()->updated_at, + 'organizer_notes' => $this->talk->currentRevision->organizer_notes, + 'created_at' => (string) $this->talk->currentRevision->created_at, + 'updated_at' => (string) $this->talk->currentRevision->updated_at, ]; } diff --git a/app/Collections/TalksCollection.php b/app/Collections/TalksCollection.php index 4769b9e6..d6f133ad 100644 --- a/app/Collections/TalksCollection.php +++ b/app/Collections/TalksCollection.php @@ -10,7 +10,7 @@ class TalksCollection extends Collection public function sortByTitle() { return $this->sortBy(function (Talk $talk) { - return strtolower($talk->currentRevision()->title); + return strtolower($talk->currentRevision->title); })->values(); } } diff --git a/app/Http/Controllers/Api/TalksController.php b/app/Http/Controllers/Api/TalksController.php index ed3c3870..f2387d9d 100644 --- a/app/Http/Controllers/Api/TalksController.php +++ b/app/Http/Controllers/Api/TalksController.php @@ -12,7 +12,7 @@ class TalksController extends Controller public function show($id) { try { - $talk = auth()->guard('api')->user()->talks()->findOrFail($id); + $talk = auth()->guard('api')->user()->talks()->withCurrentRevision()->findOrFail($id); } catch (Exception $e) { App::abort(404); } diff --git a/app/Http/Controllers/Api/UserTalksController.php b/app/Http/Controllers/Api/UserTalksController.php index 9e864b1f..72c37347 100644 --- a/app/Http/Controllers/Api/UserTalksController.php +++ b/app/Http/Controllers/Api/UserTalksController.php @@ -22,6 +22,7 @@ public function index($userId) $talks = auth()->guard('api') ->user() ->talks() + ->withCurrentRevision() ->when((bool) request()->query('include-archived'), function ($query) { $query->withoutGlobalScope('active'); }) diff --git a/app/Http/Controllers/ConferencesController.php b/app/Http/Controllers/ConferencesController.php index 6fa0151b..de7de6b7 100644 --- a/app/Http/Controllers/ConferencesController.php +++ b/app/Http/Controllers/ConferencesController.php @@ -48,7 +48,7 @@ public function show($id) return redirect('/'); } - $talks = auth()->user()->talks->sortByTitle()->map(function ($talk) use ($conference) { + $talks = auth()->user()->talks()->withCurrentRevision()->get()->sortByTitle()->map(function ($talk) use ($conference) { return TalkTransformer::transform($talk, $conference); }); diff --git a/app/Http/Controllers/PublicProfileController.php b/app/Http/Controllers/PublicProfileController.php index cc230dac..dfed21f4 100644 --- a/app/Http/Controllers/PublicProfileController.php +++ b/app/Http/Controllers/PublicProfileController.php @@ -28,7 +28,7 @@ public function index(SpeakerSearchRequest $request) public function show($profile_slug) { $user = $this->getPublicUserByProfileSlug($profile_slug); - $talks = $user->talks()->public()->get()->sortByTitle(); + $talks = $user->talks()->withCurrentRevision()->public()->get()->sortByTitle(); $bios = $user->bios()->public()->get(); return view('account.public-profile.show', [ diff --git a/app/Http/Controllers/SubmissionsController.php b/app/Http/Controllers/SubmissionsController.php index ca8084f8..6f41f894 100644 --- a/app/Http/Controllers/SubmissionsController.php +++ b/app/Http/Controllers/SubmissionsController.php @@ -19,7 +19,7 @@ public function store(Request $request) } $conference = Conference::findOrFail($request->input('conferenceId')); - $talkRevision = $talk->currentRevision(); + $talkRevision = $talk->loadCurrentRevision()->currentRevision; $submission = $conference->submissions()->create(['talk_revision_id' => $talkRevision->id]); return response()->json([ diff --git a/app/Http/Controllers/TalksController.php b/app/Http/Controllers/TalksController.php index 2c117dd7..529f1096 100644 --- a/app/Http/Controllers/TalksController.php +++ b/app/Http/Controllers/TalksController.php @@ -74,7 +74,7 @@ public function edit($id) return view('talks.edit', [ 'talk' => $talk, - 'current' => $talk->currentRevision(), + 'current' => $talk->currentRevision, ]); } @@ -103,7 +103,7 @@ public function show($id, Request $request) { $talk = auth()->user()->talks()->findOrFail($id); - $current = $request->filled('revision') ? $talk->revisions()->findOrFail($request->input('revision')) : $talk->currentRevision(); + $current = $request->filled('revision') ? $talk->revisions()->findOrFail($request->input('revision')) : $talk->loadCurrentRevision()->currentRevision; $submissions = Submission::where('talk_revision_id', $current->id) ->with(['conference', 'acceptance', 'rejection']) @@ -129,7 +129,7 @@ public function destroy($id) public function archiveIndex(Request $request) { $talks = $this->sortTalks( - auth()->user()->archivedTalks()->get(), + auth()->user()->archivedTalks()->withCurrentRevision()->get(), $request->input('sort') ); @@ -161,13 +161,13 @@ private function filterTalks($filter) { switch ($filter) { case 'submitted': - return auth()->user()->talks()->submitted()->get(); + return auth()->user()->talks()->withCurrentRevision()->submitted()->get(); break; case 'accepted': - return auth()->user()->talks()->accepted()->get(); + return auth()->user()->talks()->withCurrentRevision()->accepted()->get(); break; default: - return auth()->user()->talks()->get(); + return auth()->user()->talks()->withCurrentRevision()->get(); break; } } @@ -186,7 +186,7 @@ private function sortTalks($talks, $sort) $this->sorted_by = 'alpha'; return $talks->sortBy(function ($talk) { - return strtolower($talk->currentRevision()->title); + return strtolower($talk->currentRevision->title); }); break; } diff --git a/app/Models/Talk.php b/app/Models/Talk.php index 574f23f7..c7b79eea 100644 --- a/app/Models/Talk.php +++ b/app/Models/Talk.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Collections\TalksCollection; +use App\Models\TalkRevision; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -61,7 +62,7 @@ public function acceptances() public function currentRevision() { - return $this->revisions()->orderBy('created_at', 'DESC')->first(); + return $this->belongsTo(TalkRevision::class); } public function revisions() @@ -111,6 +112,24 @@ public function scopeAccepted($query) $query->has('acceptances'); } + public function scopeWithCurrentRevision($query) + { + $query->addSelect([ + 'current_revision_id' => TalkRevision::select('id') + ->whereColumn('talk_id', 'talks.id') + ->latest() + ->take(1) + ])->with('currentRevision'); + } + + public function loadCurrentRevision() + { + return $this->setRelation( + 'currentRevision', + TalkRevision::where('talk_id', $this->id)->latest()->take(1)->first(), + ); + } + public function getMySubmissionForConference(Conference $conference) { return $conference->mySubmissions()->filter(function ($item) { diff --git a/app/Transformers/TalkForConferenceTransformer.php b/app/Transformers/TalkForConferenceTransformer.php index 9116d1d4..3d372d76 100644 --- a/app/Transformers/TalkForConferenceTransformer.php +++ b/app/Transformers/TalkForConferenceTransformer.php @@ -9,7 +9,7 @@ class TalkForConferenceTransformer { public static function transform(Talk $talk, Conference $conference) { - $currentTalk = $talk->currentRevision(); + $currentTalk = $talk->currentRevision; $submission = $talk->getMySubmissionForConference($conference); $acceptance = $submission ? $submission->acceptance : null; diff --git a/database/factories/TalkFactory.php b/database/factories/TalkFactory.php index c0968d44..66123472 100644 --- a/database/factories/TalkFactory.php +++ b/database/factories/TalkFactory.php @@ -40,7 +40,9 @@ public function author(User $user) public function submitted() { return $this->afterCreating(function (Talk $talk) { - Conference::factory()->received($talk->currentRevision())->create(); + Conference::factory() + ->received($talk->loadCurrentRevision()->currentRevision) + ->create(); }); } diff --git a/resources/views/account/public-profile/show.blade.php b/resources/views/account/public-profile/show.blade.php index 6e504ea0..bf2f0d91 100755 --- a/resources/views/account/public-profile/show.blade.php +++ b/resources/views/account/public-profile/show.blade.php @@ -34,11 +34,11 @@ class="no-underline block mt-8 text-indigo" @forelse ($talks as $talk)

- {{ $talk->currentRevision()->title }} + {{ $talk->currentRevision->title }}

- {{ $talk->currentRevision()->length }}-minute {{ $talk->currentRevision()->type }} talk at {{ $talk->currentRevision()->level }} level + {{ $talk->currentRevision->length }}-minute {{ $talk->currentRevision->type }} talk at {{ $talk->currentRevision->level }} level @empty This speaker has not made any of their talks public yet. diff --git a/resources/views/talks/listing.blade.php b/resources/views/talks/listing.blade.php index 252d7e9d..4a053934 100644 --- a/resources/views/talks/listing.blade.php +++ b/resources/views/talks/listing.blade.php @@ -1,4 +1,4 @@ - + @svg('compose', 'w-5 fill-current inline') @@ -22,7 +22,7 @@
{{ $talk->created_at->toFormattedDateString() }}
-
{{ $talk->currentRevision()->length }}-minute {{ $talk->currentRevision()->level }} {{ $talk->currentRevision()->type }}
+
{{ $talk->currentRevision->length }}-minute {{ $talk->currentRevision->level }} {{ $talk->currentRevision->type }}
diff --git a/resources/views/talks/show-public.blade.php b/resources/views/talks/show-public.blade.php index 8412c076..35aa3006 100644 --- a/resources/views/talks/show-public.blade.php +++ b/resources/views/talks/show-public.blade.php @@ -11,15 +11,15 @@ class="inline-block" Return to profile for {{ $user->name }} -

{{ $talk->currentRevision()->title }}

+

{{ $talk->currentRevision->title }}

- {{ $talk->currentRevision()->length }} minute {{ $talk->currentRevision()->level }} {{ $talk->currentRevision()->type }} + {{ $talk->currentRevision->length }} minute {{ $talk->currentRevision->level }} {{ $talk->currentRevision->type }}

Description/Proposal

- {!! markdown($talk->currentRevision()->getDescription()) !!} + {!! markdown($talk->currentRevision->getDescription()) !!} @endsection diff --git a/resources/views/talks/show.blade.php b/resources/views/talks/show.blade.php index 740e9762..1811e4e6 100644 --- a/resources/views/talks/show.blade.php +++ b/resources/views/talks/show.blade.php @@ -9,7 +9,7 @@ @foreach ($talk->revisions as $revision) - @if ($talk->currentRevision()->id == $revision->id) + @if ($talk->currentRevision->id == $revision->id)
create(); $talk->revisions()->save($talkRevision); + $talk->loadCurrentRevision(); + $this->get(route('speakers-public.show', [$user->profile_slug])) - ->assertDontSee($talk->currentRevision()->title); + ->assertDontSee($talk->currentRevision->title); } /** @test */ diff --git a/tests/Feature/TalkTest.php b/tests/Feature/TalkTest.php index e85f3302..53b0a89e 100644 --- a/tests/Feature/TalkTest.php +++ b/tests/Feature/TalkTest.php @@ -79,8 +79,10 @@ public function user_talks_are_sorted_alphabetically() $talk1 = Talk::factory()->author($user)->revised(['title' => 'zyxwv'])->create(); $talk2 = Talk::factory()->author($user)->revised(['title' => 'abcde'])->create(); - $this->assertEquals('abcde', $user->talks->sortByTitle()->first()->currentRevision()->title); - $this->assertEquals('zyxwv', $user->talks->sortByTitle()->last()->currentRevision()->title); + $talks = $user->talks()->withCurrentRevision()->get(); + + $this->assertEquals('abcde', $talks->sortByTitle()->first()->currentRevision->title); + $this->assertEquals('zyxwv', $talks->sortByTitle()->last()->currentRevision->title); } /** @test */ @@ -224,7 +226,7 @@ public function user_can_save_a_new_revision_of_a_talk() ]); $this->actingAs($user) - ->put("/talks/{$talk->id}", array_merge($talk->currentRevision()->toArray(), [ + ->put("/talks/{$talk->id}", array_merge($talk->loadCurrentRevision()->currentRevision->toArray(), [ 'title' => 'New', 'public' => '1', ])); @@ -232,7 +234,7 @@ public function user_can_save_a_new_revision_of_a_talk() $talk = Talk::first(); $this->assertTrue($talk->public); - $this->assertEquals('New', $talk->currentRevision()->title); + $this->assertEquals('New', $talk->loadCurrentRevision()->currentRevision->title); $this->assertEquals('old title', $talk->revisions->last()->title); } @@ -262,7 +264,7 @@ function revised_talks_must_include_a_valid_length() $talk = Talk::factory()->author($user)->create(); $response = $this->actingAs($user) - ->put("/talks/{$talk->id}", array_merge($talk->currentRevision()->toArray(), [ + ->put("/talks/{$talk->id}", array_merge($talk->loadCurrentRevision()->currentRevision->toArray(), [ 'length' => 'invalid', ])); @@ -276,7 +278,7 @@ function revised_talks_with_slides_must_include_a_valid_slides_url() $talk = Talk::factory()->author($user)->create(); $response = $this->actingAs($user) - ->put("/talks/{$talk->id}", array_merge($talk->currentRevision()->toArray(), [ + ->put("/talks/{$talk->id}", array_merge($talk->loadCurrentRevision()->currentRevision->toArray(), [ 'slides' => 'invalid url', ])); diff --git a/tests/Feature/UserTest.php b/tests/Feature/UserTest.php index c86c02cd..5fa6d30b 100644 --- a/tests/Feature/UserTest.php +++ b/tests/Feature/UserTest.php @@ -60,13 +60,13 @@ function getting_conference_submissions() $conference = Conference::factory()->create(); $conference->submissions()->create([ - 'talk_revision_id' => $talk->currentRevision()->id, + 'talk_revision_id' => $talk->loadCurrentRevision()->currentRevision->id, ]); $this->assertEquals(1, $user->talkRevisions()->count()); $this->assertEquals(1, $user->submissions()->count()); $this->assertEquals( - $talk->currentRevision()->id, + $talk->currentRevision->id, $user->submissions->first()->talk_revision_id, ); } From efd977def56a23cdba30bed82d9bd75cbec7e623 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 15:32:40 -0400 Subject: [PATCH 6/7] Remove n+1 query for the talk of the talk revision --- app/Transformers/TalkForConferenceTransformer.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Transformers/TalkForConferenceTransformer.php b/app/Transformers/TalkForConferenceTransformer.php index 3d372d76..f20f1efa 100644 --- a/app/Transformers/TalkForConferenceTransformer.php +++ b/app/Transformers/TalkForConferenceTransformer.php @@ -9,7 +9,8 @@ class TalkForConferenceTransformer { public static function transform(Talk $talk, Conference $conference) { - $currentTalk = $talk->currentRevision; + $currentRevision = $talk->currentRevision; + $currentRevision->setRelation('talk', $talk); $submission = $talk->getMySubmissionForConference($conference); $acceptance = $submission ? $submission->acceptance : null; @@ -17,8 +18,8 @@ public static function transform(Talk $talk, Conference $conference) return [ 'id' => $talk->id, - 'title' => $currentTalk->title, - 'url' => $currentTalk->getUrl(), + 'title' => $currentRevision->title, + 'url' => $currentRevision->getUrl(), 'submitted' => (bool) $submission, 'submissionId' => $submission ? $submission->id : null, 'accepted' => (bool) $acceptance, From 21087be0bc8cbd39434b0ed5025654bfdfd96ac6 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Apr 2024 15:51:19 -0400 Subject: [PATCH 7/7] Add trailing comma --- app/Models/Talk.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Talk.php b/app/Models/Talk.php index c7b79eea..773d8b0e 100644 --- a/app/Models/Talk.php +++ b/app/Models/Talk.php @@ -118,7 +118,7 @@ public function scopeWithCurrentRevision($query) 'current_revision_id' => TalkRevision::select('id') ->whereColumn('talk_id', 'talks.id') ->latest() - ->take(1) + ->take(1), ])->with('currentRevision'); }