Retour au blog
Design Pattern avec Laravel : Template Method

Design Pattern avec Laravel : Template Method

Sommaire

  1. Présentation
  2. Tutoriel vidéo
  3. Synthèse
  4. Conclusion

Présentation

Dans cet article, nous allons découvrir le Template Method Pattern avec Laravel. Ce pattern comportemental permet de définir la structure d’un algorithme dans une classe parent tout en laissant les sous-classes personnaliser certaines étapes.

Ce tutoriel s’appuie sur un exemple de refactoring.guru.

Introduction à au Template Method

Le Template Method est particulièrement utile lorsque plusieurs classes partagent une logique commune, mais nécessitent des comportements spécifiques pour certaines étapes. Dans notre exemple, nous allons montrer comment utiliser ce pattern pour le minage de données provenant de différents formats de fichiers (Doc, CSV, PDF).

Tutoriel vidéo

Synthèse de la vidéo

Dans la vidéo, nous avons utilisé le Template Method Pattern pour refactorer une application Laravel qui extrait des données de fichiers au format Doc, CSV et PDF. Nous avons remarqué que les méthodes d’ouverture, de parsing, d’analyse et de fermeture des fichiers étaient similaires pour chaque type de fichier, ce qui nous conduisait à du code dupliqué.

Pour éviter cela, nous avons utilisé le Template Method en créant une classe parent DataMiner qui contient la logique commune (ouvrir, fermer le fichier, envoyer le rapport) et des méthodes abstraites pour la partie spécifique (extraction et parsing des données), que les sous-classes DocDataMiner, CsvDataMiner et PdfDataMiner doivent implémenter.

namespace App\Services\DataMiner;

use Exception;
use Illuminate\Http\UploadedFile;
use Symfony\Component\HttpFoundation\File\UploadedFile as BaseUploadedFile;

abstract class DataMiner
{
    public function mineData(string $path)
    {
        $file = $this->openFile($path);

        $rawData = $this->extractData($file);
        $data = $this->parseData($rawData);

        $analysis = $this->analyzeData($data);

        $this->sendReport($analysis);

        $this->closeFile($file);
    }

    abstract protected function extractData(UploadedFile $file): array;

    abstract protected function parseData(array $rawData): string;

    protected function openFile(string $path): UploadedFile
    {
        if (! file_exists($path)) {
            throw new Exception("File does not exist at path: {$path}");
        }

        $originalName = basename($path);

        $mimeType = mime_content_type($path);

        $uploadedFile = new BaseUploadedFile(
            $path,
            $originalName,
            $mimeType,
            null,
            true,
        );

        return UploadedFile::createFromBase($uploadedFile);
    }

    protected function analyzeData(string $data): string
    {
        echo "Analyzing data...\n";

        return 'analysis';
    }

    protected function sendReport(string $analysis)
    {
        echo "Generating report...\n";
        echo "Report sent...\n";
    }

    protected function closeFile(string $file)
    {
        echo "Closing file...\n";
    }
}
namespace App\Services\DataMiner;

use Illuminate\Support\Str;
use Illuminate\Http\UploadedFile;

class DocDataMiner extends DataMiner
{
    protected function extractData(UploadedFile $file): array
    {
        echo "Extracting data from Doc file...\n";

        return [
            'data-1' => Str::random(),
            'data-2' => Str::random(),
        ];
    }

    protected function parseData(array $rawData): string
    {
        echo "Extracting data from Doc file...\n";

        return json_encode($rawData);
    }
}
namespace App\Http\Controllers;

use App\Services\DataMiner\DocDataMiner;
use App\Services\DataMiner\PdfDataMiner;
use App\Services\DataMiner\CsvDataMiner;

class DataMiningController extends Controller
{
    public function processDocFile()
    {
        $docMiner = new DocDataMiner();

        $docMiner->mineData(storage_path('blank.docx'));
    }

    public function processPdfFile()
    {
        $pdfMiner = new PdfDataMiner();

        $pdfMiner->mineData(storage_path('blank.pdf'));
    }

    public function processCsvFile()
    {
        $csvMiner = new CsvDataMiner();

        $csvMiner->mineData(storage_path('blank.csv'));
    }
}

Conclusion

Le Template Method Pattern nous permet de capturer la logique commune dans une classe parent tout en permettant aux sous-classes de personnaliser certaines étapes. En éliminant les redondances, ce pattern améliore la maintenance et la lisibilité du code, tout en respectant le principe Open/Closed.

Ce design pattern est un excellent moyen de structurer vos applications Laravel de manière plus propre et évolutive.

N’hésitez pas à me suivre et à vous abonner à Laravel Jutsu pour plus de contenu !