Theme
Integration: Laravel
Status: Produktiv seit 2026-05-20. Funktioniert mit Laravel 11+. Nutzt das eingebaute Laravel-Http-Facade — keine zusätzliche Composer-Dependency notwendig.
60-Sekunden-Setup
bash
# In deinem Laravel-Projekt:
npx @peacock/cli init laravelWas passiert:
- Erkennung:
artisan-Datei oderlaravel/frameworkincomposer.json. .env: Idempotente Erweiterung umPEACOCK_API_BASE_URL,PEACOCK_SPACE,PEACOCK_TOKEN.config/peacock.phpwird angelegt — liest dieenv()-Werte ein.routes/peacock.phpwird angelegt — Catch-All-Route, die unbekannte URLs als Peacock-Stories interpretiert.
bootstrap/app.php
Die generierte Route-Datei wird nicht automatisch in bootstrap/app.php eingebunden — das CLI darf in dieser sensiblen Datei nicht herumeditieren. Füge eine Zeile manuell ein:
php
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
then: function () {
Route::middleware('web')->group(base_path('routes/peacock.php'));
},
)
// ...then: läuft nach den Standard-Routes — so haben deine eigenen Routes (/login, /dashboard) Vorrang vor dem Peacock-Catch-All.
Generierte Dateien
config/peacock.php
php
return [
'api_base_url' => env('PEACOCK_API_BASE_URL'),
'space' => env('PEACOCK_SPACE'),
'token' => env('PEACOCK_TOKEN'),
];Greife in jeder Klasse mit config('peacock.api_base_url') darauf zu.
routes/peacock.php
php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Http;
Route::get('/{path?}', function (string $path = '') {
$base = rtrim((string) config('peacock.api_base_url'), '/');
$space = (string) config('peacock.space');
$token = (string) config('peacock.token');
$response = Http::withToken($token)
->acceptJson()
->timeout(5)
->get(sprintf('%s/cdn/spaces/%s/stories/by-path', $base, $space), [
'path' => '/' . ltrim($path, '/'),
]);
if ($response->status() === 404) {
abort(404);
}
if (!$response->successful()) {
abort(500, "Peacock fetch failed: " . $response->status());
}
$story = $response->json('data');
return response()
->view('welcome', ['story' => $story])
->header('X-Peacock-Story', $story['uuid'] ?? '');
})->where('path', '.*');Blade-Render-Beispiel
resources/views/welcome.blade.php:
blade
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>{{ $story['content']['headline'] ?? config('app.name') }}</title>
</head>
<body>
@foreach ($story['content']['body'] ?? [] as $block)
@switch ($block['_component'])
@case ('hero')
<section class="hero">
<h1>{{ $block['headline'] }}</h1>
<p>{{ $block['lead'] ?? '' }}</p>
@if (!empty($block['cta_url']))
<a href="{{ $block['cta_url'] }}">{{ $block['cta_label'] ?? 'Mehr' }}</a>
@endif
</section>
@break
@case ('faq')
<section class="faq">
@foreach ($block['items'] ?? [] as $item)
<details>
<summary>{{ $item['question'] }}</summary>
<p>{{ $item['answer'] }}</p>
</details>
@endforeach
</section>
@break
@endswitch
@endforeach
</body>
</html>Caching mit Laravel Cache
Der CDN-Endpoint setzt zwar ETag-Header, aber Laravel's Http-Client cached nicht out-of-the-box. Für hochfrequentierte Routes wickle den Fetch in Cache::remember():
php
$story = Cache::remember(
"peacock:story:{$path}",
60, // Sekunden
fn () => $response->json('data'),
);Webhook-Invalidierung: Konfiguriere in Peacock-Admin einen Webhook auf story.published, der einen Endpoint hier hittet und Cache::forget("peacock:story:{$path}") ausführt.
Was noch fehlt
- Dedicated
webhoch-com/peacock-laravelComposer-Paket: Phase-9-Polish — wird Service-Provider, Blade-Component (<x-peacock-block :data="$block" />), und Artisan-Commands für Webhook-Setup mitbringen. Heute funktioniert das oben gezeigte Pattern vollständig ohne externes Paket.