Boost-Buchung invalidiert gecachte Start- und Branchenseiten sofort
Statt bis zu 300 s Cache-TTL zu warten, verwirft der BoostService nach der Buchung die Home-/Kategorie-Caches der betroffenen Ausgaben (inkl. Eltern-Rubrik) — die bezahlte Platzierung ist direkt sichtbar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
cc61bf21d9
commit
6be387c9fb
2 changed files with 65 additions and 1 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Services\PressRelease;
|
namespace App\Services\PressRelease;
|
||||||
|
|
||||||
|
use App\Enums\Portal;
|
||||||
use App\Enums\PressReleaseClassification;
|
use App\Enums\PressReleaseClassification;
|
||||||
use App\Enums\PressReleaseStatus;
|
use App\Enums\PressReleaseStatus;
|
||||||
use App\Exceptions\BoostNotAllowedException;
|
use App\Exceptions\BoostNotAllowedException;
|
||||||
|
|
@ -11,6 +12,7 @@ use App\Models\User;
|
||||||
use App\Services\Billing\CreditPricingService;
|
use App\Services\Billing\CreditPricingService;
|
||||||
use App\Services\Billing\CreditWalletService;
|
use App\Services\Billing\CreditWalletService;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -63,7 +65,7 @@ class BoostService
|
||||||
|
|
||||||
$credits = $this->pricing->boostCredits($days);
|
$credits = $this->pricing->boostCredits($days);
|
||||||
|
|
||||||
return DB::transaction(function () use ($user, $pressRelease, $days, $credits): Boost {
|
$boost = DB::transaction(function () use ($user, $pressRelease, $days, $credits): Boost {
|
||||||
$startsAt = $this->activeUntil($pressRelease) ?? now();
|
$startsAt = $this->activeUntil($pressRelease) ?? now();
|
||||||
|
|
||||||
$boost = $pressRelease->boosts()->create([
|
$boost = $pressRelease->boosts()->create([
|
||||||
|
|
@ -83,5 +85,39 @@ class BoostService
|
||||||
|
|
||||||
return $boost;
|
return $boost;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->forgetPlacementCaches($pressRelease);
|
||||||
|
|
||||||
|
return $boost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gecachte Start-/Branchenseiten der betroffenen Ausgaben verwerfen,
|
||||||
|
* damit die bezahlte Platzierung sofort sichtbar wird statt erst nach
|
||||||
|
* Ablauf der Cache-TTL (HomePageData/CategoryPageData, 300 s).
|
||||||
|
*/
|
||||||
|
private function forgetPlacementCaches(PressRelease $pressRelease): void
|
||||||
|
{
|
||||||
|
$portals = $pressRelease->portal === Portal::Both
|
||||||
|
? [Portal::Presseecho->value, Portal::Businessportal24->value]
|
||||||
|
: [$pressRelease->portal->value];
|
||||||
|
|
||||||
|
// Branchenseite der eigenen Rubrik plus Eltern-Rubrik (deren Seite
|
||||||
|
// schließt Unterkategorien mit ein), je hinterlegter Sprache.
|
||||||
|
$category = $pressRelease->category()
|
||||||
|
->with(['translations', 'parent.translations'])
|
||||||
|
->first();
|
||||||
|
$translations = collect($category?->translations ?? [])
|
||||||
|
->merge($category?->parent?->translations ?? []);
|
||||||
|
|
||||||
|
foreach ($portals as $portal) {
|
||||||
|
Cache::forget(sprintf('web.home.%s.%s', $portal, $pressRelease->language));
|
||||||
|
|
||||||
|
foreach ($translations as $translation) {
|
||||||
|
if (filled($translation->slug)) {
|
||||||
|
Cache::forget(sprintf('web.category.%s.%s.%s', $portal, $translation->locale, $translation->slug));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Enums\Portal;
|
use App\Enums\Portal;
|
||||||
|
use App\Enums\PressReleaseClassification;
|
||||||
use App\Models\Boost;
|
use App\Models\Boost;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\PressRelease;
|
use App\Models\PressRelease;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\Billing\CreditWalletService;
|
||||||
|
use App\Services\PressRelease\BoostService;
|
||||||
use App\Services\Web\HomePageData;
|
use App\Services\Web\HomePageData;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
|
@ -44,6 +48,8 @@ function boostPlacementFixture(): array
|
||||||
'title' => 'Geboostete aeltere Meldung',
|
'title' => 'Geboostete aeltere Meldung',
|
||||||
'slug' => 'geboostete-aeltere-meldung',
|
'slug' => 'geboostete-aeltere-meldung',
|
||||||
'published_at' => now()->subDays(5),
|
'published_at' => now()->subDays(5),
|
||||||
|
// Grün klassifiziert: Voraussetzung fürs Boost-Gate im BoostService.
|
||||||
|
'classification' => PressReleaseClassification::Green->value,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return compact('category', 'company', 'newest', 'boosted');
|
return compact('category', 'company', 'newest', 'boosted');
|
||||||
|
|
@ -82,6 +88,28 @@ test('an expired boost does not influence the homepage placement', function () {
|
||||||
->assertDontSeeText('Top-Platzierung');
|
->assertDontSeeText('Top-Platzierung');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('booking a boost invalidates the cached start and category pages immediately', function () {
|
||||||
|
/** @var TestCase $this */
|
||||||
|
['boosted' => $boosted, 'newest' => $newest] = boostPlacementFixture();
|
||||||
|
|
||||||
|
$owner = User::factory()->create(['is_active' => true]);
|
||||||
|
app(CreditWalletService::class)->credit($owner, 40);
|
||||||
|
|
||||||
|
// Beide Seiten in den Cache legen — noch ohne Boost.
|
||||||
|
expect(app(HomePageData::class)->build(Portal::Presseecho)['leadRelease']->id)->toBe($newest->id);
|
||||||
|
$this->get('https://presseecho.test/de/category/energie-klima')
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertDontSeeText('Top-Platzierung');
|
||||||
|
|
||||||
|
app(BoostService::class)->boost($owner, $boosted, 7);
|
||||||
|
|
||||||
|
// Kein Warten auf die TTL: die Buchung verwirft die gecachten Seiten.
|
||||||
|
expect(app(HomePageData::class)->build(Portal::Presseecho)['leadRelease']->id)->toBe($boosted->id);
|
||||||
|
$this->get('https://presseecho.test/de/category/energie-klima')
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertSeeText('Top-Platzierung');
|
||||||
|
});
|
||||||
|
|
||||||
test('a boosted release leads its category page and is labelled', function () {
|
test('a boosted release leads its category page and is labelled', function () {
|
||||||
/** @var TestCase $this */
|
/** @var TestCase $this */
|
||||||
['boosted' => $boosted] = boostPlacementFixture();
|
['boosted' => $boosted] = boostPlacementFixture();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue