diff --git a/app/Http/Controllers/PublicWikiController.php b/app/Http/Controllers/PublicWikiController.php index ca4d3e7da..c4f8fc155 100644 --- a/app/Http/Controllers/PublicWikiController.php +++ b/app/Http/Controllers/PublicWikiController.php @@ -29,7 +29,7 @@ public function index(Request $request) { ]); $params = array_merge(self::$defaultParams, $request->input()); - $query = Wiki::query(); + $query = Wiki::query()->with('wikiLatestProfile'); if (array_key_exists('is_featured', $params)) { $query = $query->where([ diff --git a/app/Http/Resources/PublicWikiResource.php b/app/Http/Resources/PublicWikiResource.php index 37e1e92ef..c01e34f58 100644 --- a/app/Http/Resources/PublicWikiResource.php +++ b/app/Http/Resources/PublicWikiResource.php @@ -16,6 +16,16 @@ public function toArray($request): array { 'sitename' => $this->sitename, 'wiki_site_stats' => $this->wikiSiteStats, 'logo_url' => $logoSetting ? $logoSetting->value : null, + + // Checking relation load state before reading it to avoid N+1 query + // This relies on the controller to eager load `wikiLatestProfile` relationship + 'reuse_prototype' => $this->relationLoaded('wikiLatestProfile') + ? ($this->wikiLatestProfile + ? $this->wikiLatestProfile->purpose === 'data_hub' + && $this->wikiLatestProfile->temporality === 'permanent' + && $this->wikiLatestProfile->audience === 'wide' + : null) + : null, ]; } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 38f07d753..99eb8956d 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ use App\Http\Curl\CurlRequest; use App\Http\Curl\HttpRequest; +use Illuminate\Database\Events\QueryExecuted; use Illuminate\Queue\Events\JobFailed; use Illuminate\Support\Facades\Queue; use Illuminate\Support\ServiceProvider; @@ -25,5 +26,16 @@ public function boot(): void { $wrappedException = new \Exception("Executing Job '$name' failed.", 1, $event->exception); report($wrappedException); }); + + // TODO: delete this listener before merging or is it useful to keep in the local environment? + if ($this->app->environment('local')) { + \Event::listen(QueryExecuted::class, function (QueryExecuted $query) { + \Log::debug('Query Executed: ', [ + 'sql' => $query->sql, + 'bindings' => $query->bindings, + 'connection' => $query->connectionName, + ]); + }); + } } } diff --git a/tests/Routes/Wiki/PublicWikiTest.php b/tests/Routes/Wiki/PublicWikiTest.php index c7ed46fbb..90d830c79 100644 --- a/tests/Routes/Wiki/PublicWikiTest.php +++ b/tests/Routes/Wiki/PublicWikiTest.php @@ -3,6 +3,7 @@ namespace Tests\Routes\Wiki; use App\Wiki; +use App\WikiProfile; use App\WikiSetting; use App\WikiSiteStats; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -18,12 +19,14 @@ class PublicWikiTest extends TestCase { protected function setUp(): void { parent::setUp(); Wiki::query()->delete(); + WikiProfile::query()->delete(); WikiSiteStats::query()->delete(); WikiSetting::query()->delete(); } protected function tearDown(): void { Wiki::query()->delete(); + WikiProfile::query()->delete(); WikiSiteStats::query()->delete(); WikiSetting::query()->delete(); parent::tearDown(); @@ -279,4 +282,48 @@ public function testLogoUrl() { ) ->assertJsonPath('data.1.logo_url', null); } + + public function testReusePrototype() { + $reusableWiki = Wiki::factory()->create([ + 'domain' => 'reusable.wikibase.cloud', 'sitename' => 'asite', + ]); + WikiSiteStats::factory()->create([ + 'wiki_id' => $reusableWiki->id, + ]); + WikiProfile::create([ + 'wiki_id' => $reusableWiki->id, + 'purpose' => 'data_hub', + 'temporality' => 'permanent', + 'audience' => 'wide', + ]); + + $nonReusableWiki = Wiki::factory()->create([ + 'domain' => 'non-reusable.wikibase.cloud', 'sitename' => 'bsite', + ]); + WikiSiteStats::factory()->create([ + 'wiki_id' => $nonReusableWiki->id, + ]); + WikiProfile::create([ + 'wiki_id' => $nonReusableWiki->id, + 'purpose' => 'other', + 'temporality' => 'other', + 'audience' => 'other', + ]); + + $noProfileWiki = Wiki::factory()->create([ + 'domain' => 'no-profile.wikibase.cloud', 'sitename' => 'csite', + ]); + WikiSiteStats::factory()->create([ + 'wiki_id' => $noProfileWiki->id, + ]); + + $this->json('GET', $this->route) + ->assertStatus(200) + ->assertJsonPath('data.0.domain', 'reusable.wikibase.cloud') + ->assertJsonPath('data.0.reuse_prototype', true) + ->assertJsonPath('data.1.domain', 'non-reusable.wikibase.cloud') + ->assertJsonPath('data.1.reuse_prototype', false) + ->assertJsonPath('data.2.domain', 'no-profile.wikibase.cloud') + ->assertJsonPath('data.2.reuse_prototype', null); + } }