5 Min. Lesezeit

Laravel Pipelines – Wie ein Küchenteam deine Daten perfekt zubereitet

Laravel Pipelines – Dein Code wird zum Küchenteam Stell dir vor, du bist in einem Sternerestaurant: Ein Koch bereitet die Zutaten vor, der nächste brät das Fleisch, ein anderer verfeinert die Sauce. Jeder macht seinen Job perfekt und gibt dann weiter – genau so funktionieren Laravel Pipelines! Das Grundprinzip Laravel Pipelines teilen komplexe Aufgaben in kleine, spezialisierte Schritte auf. Statt einer riesigen, unübersichtlichen Funktion hast du eine saubere Kette von Operationen. Wie am Fließband: Jeder Schritt nimmt das Ergebnis des vorherigen, macht seinen Job und gibt es weiter.

Stell dir vor, du bist in einem Sternerestaurant und beobachtest, wie ein Gericht entsteht. Der Sous-Chef bereitet die Zutaten vor, der Grillmeister brät das Fleisch, der Saucier perfektioniert die Sauce, und schließlich richtet der Chef de Partie alles elegant an. Jeder Schritt baut auf dem vorherigen auf – genau so funktionieren Laravel Pipelines!

Was sind Laravel Pipelines?

Laravel Pipelines sind ein mächtiges Pattern, das es dir ermöglicht, Daten durch eine Kette von Klassen zu schleusen. Jede Klasse führt eine spezifische Aufgabe aus und gibt das Ergebnis an die nächste weiter. Das Schöne daran: Dein Code wird dadurch extrem lesbar und wartbar.

use Illuminate\Pipeline\Pipeline;

$processedOrder = app(Pipeline::class)
    ->send($rawOrderData)
    ->through([
        ValidateOrderData::class,
        CheckInventory::class,
        CalculatePrice::class,
        ApplyDiscounts::class,
        ProcessPayment::class,
    ])
    ->thenReturn();

Die Anatomie einer Pipeline-Klasse Jede Pipeline-Klasse benötigt eine handle Methode mit zwei Parametern: den zu verarbeitenden Daten und einem Closure für den nächsten Schritt.

namespace App\Pipelines\OrderProcessing;

class ValidateOrderData
{
    public function handle($orderData, $next)
    {
        // Validierung der Bestelldaten
        if (empty($orderData['customer_email'])) {
            throw new \Exception('E-Mail-Adresse ist erforderlich');
        }
        
        if (empty($orderData['items']) || count($orderData['items']) === 0) {
            throw new \Exception('Mindestens ein Artikel muss bestellt werden');
        }
        
        // Daten bereinigen
        $orderData['customer_email'] = trim(strtolower($orderData['customer_email']));
        
        return $next($orderData);
    }
}

Ein praxisnahes Beispiel: Blog-Artikel-Pipeline Nehmen wir an, du entwickelst ein CMS und möchtest Blog-Artikel vor der Veröffentlichung durch verschiedene Schritte schleusen:

namespace App\Services;

use Illuminate\Pipeline\Pipeline;
use App\Pipelines\BlogPost\{
    ValidateContent,
    CheckPlagiarism,
    OptimizeSEO,
    GenerateThumbnail,
    SchedulePublication
};

class BlogPostProcessor
{
    public function processForPublication($articleData)
    {
        return app(Pipeline::class)
            ->send($articleData)
            ->through([
                ValidateContent::class,
                CheckPlagiarism::class,
                OptimizeSEO::class,
                GenerateThumbnail::class,
                SchedulePublication::class,
            ])
            ->then(function ($processedArticle) {
                // Finaler Schritt: Artikel in Datenbank speichern
                return Article::create($processedArticle);
            });
    }
}

Die einzelnen Pipeline-Schritte:

namespace App\Pipelines\BlogPost;

class ValidateContent
{
    public function handle($article, $next)
    {
        if (str_word_count($article['content']) < 300) {
            throw new \Exception('Artikel muss mindestens 300 Wörter haben');
        }
        
        if (strlen($article['title']) > 60) {
            $article['title'] = substr($article['title'], 0, 57) . '...';
        }
        
        return $next($article);
    }
}

class CheckPlagiarism
{
    public function handle($article, $next)
    {
        // Simulation einer Plagiatsprüfung
        $plagiarismScore = $this->checkWithExternalService($article['content']);
        
        if ($plagiarismScore > 0.8) {
            throw new \Exception('Verdacht auf Plagiat erkannt');
        }
        
        $article['plagiarism_score'] = $plagiarismScore;
        
        return $next($article);
    }
    
    private function checkWithExternalService($content)
    {
        // Hier würde die echte API-Anfrage stehen
        return rand(0, 100) / 100;
    }
}

class OptimizeSEO
{
    public function handle($article, $next)
    {
        // Meta-Description generieren falls nicht vorhanden
        if (empty($article['meta_description'])) {
            $article['meta_description'] = $this->generateMetaDescription($article['content']);
        }
        
        // Keywords extrahieren
        $article['keywords'] = $this->extractKeywords($article['content']);
        
        return $next($article);
    }
    
    private function generateMetaDescription($content)
    {
        return substr(strip_tags($content), 0, 155) . '...';
    }
    
    private function extractKeywords($content)
    {
        // Vereinfachte Keyword-Extraktion
        $words = str_word_count(strtolower($content), 1);
        $commonWords = ['der', 'die', 'das', 'und', 'oder', 'aber', 'ist', 'sind'];
        
        return array_slice(
            array_keys(
                array_diff(
                    array_count_values($words), 
                    array_flip($commonWords)
                )
            ), 
            0, 10
        );
    }
}

Pipelines mit Bedingungen Manchmal sollen bestimmte Schritte nur unter bestimmten Bedingungen ausgeführt werden. Dafür kannst du dynamische Pipeline-Arrays erstellen:

public function processUserRegistration($userData)
{
    $steps = [
        ValidateRegistrationData::class,
        CheckEmailUniqueness::class,
    ];
    
    // Nur bei Premium-Registrierung
    if ($userData['plan'] === 'premium') {
        $steps[] = ValidatePaymentMethod::class;
        $steps[] = ProcessPayment::class;
    }
    
    // Immer am Ende
    $steps[] = CreateUserAccount::class;
    $steps[] = SendWelcomeEmail::class;
    
    return app(Pipeline::class)
        ->send($userData)
        ->through($steps)
        ->thenReturn();
}

Pipeline-Klassen mit Dependencies Deine Pipeline-Klassen können natürlich auch Dependencies haben:

namespace App\Pipelines\User;

use App\Services\EmailService;
use App\Services\NotificationService;

class SendWelcomeEmail
{
    protected $emailService;
    protected $notificationService;
    
    public function __construct(EmailService $emailService, NotificationService $notificationService)
    {
        $this->emailService = $emailService;
        $this->notificationService = $notificationService;
    }
    
    public function handle($userData, $next)
    {
        $this->emailService->sendWelcomeEmail($userData['email'], $userData['name']);
        $this->notificationService->notifyAdmins('Neue Registrierung: ' . $userData['email']);
        
        return $next($userData);
    }
}

Error Handling in Pipelines Du kannst auch elegantes Error Handling implementieren:

namespace App\Pipelines\Base;

abstract class BasePipeline
{
    public function handle($data, $next)
    {
        try {
            return $this->process($data, $next);
        } catch (\Exception $e) {
            \Log::error("Pipeline Error in " . get_class($this) . ": " . $e->getMessage());
            
            // Je nach Anwendungsfall: Exception weiterwerfen oder Fallback
            throw $e;
        }
    }
    
    abstract protected function process($data, $next);
}

class ValidateOrderData extends BasePipeline
{
    protected function process($orderData, $next)
    {
        // Deine Validierungslogik hier
        return $next($orderData);
    }
}

Pipeline als Service Für wiederkehrende Pipelines kannst du auch einen eigenen Service erstellen:

namespace App\Services;

use Illuminate\Pipeline\Pipeline;

class DataProcessingService
{
    public function processCustomerData($rawData)
    {
        return $this->createPipeline()
            ->send($rawData)
            ->through([
                \App\Pipelines\Customer\ValidateData::class,
                \App\Pipelines\Customer\NormalizeData::class,
                \App\Pipelines\Customer\EnrichData::class,
                \App\Pipelines\Customer\SaveToDatabase::class,
            ])
            ->thenReturn();
    }
    
    public function processProductData($rawData)
    {
        return $this->createPipeline()
            ->send($rawData)
            ->through([
                \App\Pipelines\Product\ValidateData::class,
                \App\Pipelines\Product\CheckDuplicates::class,
                \App\Pipelines\Product\OptimizeImages::class,
                \App\Pipelines\Product\GenerateSKU::class,
                \App\Pipelines\Product\SaveToDatabase::class,
            ])
            ->thenReturn();
    }
    
    private function createPipeline()
    {
        return app(Pipeline::class);
    }
}

Die Vorteile auf einen Blick 🔧 Wartbarkeit: Jeder Schritt ist isoliert und kann einzeln getestet werden 📖 Lesbarkeit: Der Code liest sich wie ein Kochrezept 🔄 Wiederverwendbarkeit: Pipeline-Klassen können in verschiedenen Kontexten genutzt werden ⚡ Flexibilität: Schritte können einfach hinzugefügt, entfernt oder umgeordnet werden 🎯 Single Responsibility: Jede Klasse hat genau eine Aufgabe

Fazit Laravel Pipelines verwandeln komplexe, verschachtelte Logik in eleganten, lesbaren Code. Sie sind wie ein gut organisiertes Küchenteam – jeder weiß genau, was zu tun ist, und das Endergebnis ist perfekt. Beim nächsten Mal, wenn du dich dabei ertappst, wie du mehrere if-Statements verschachtelst oder komplexe Datenverarbeitung in einem einzigen Controller machst, denk an Pipelines. Dein zukünftiges Ich wird dir dankbar sein!

Pro-Tipp: Starte klein mit einer einfachen Pipeline und erweitere sie nach und nach. Du wirst schnell merken, wie süchtig machend sauberer, gut strukturierter Code sein kann.

Verwandte Beiträge

10.06.2025 6 Min. Lesezeit

Laravel Service Container: Dein magischer Helfer für sauberen Code

Laravel Service Container: Kurzer Auszug Der Laravel Service Container ist dein persönlicher Assistent für Dependency I...

Weiterlesen