PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Laravel vs Symfony – DI, Doctrine vs Eloquent, kiedy który framework

by Henryk Tews / wtorek, 14 marca 2023 / Opublikowano w Laravel, PHP, Symfony

Pracując na co dzień z Magento 2 (opartym na komponentach Symfony) rzadko masz okazję spojrzeć szerzej na ekosystem PHP frameworków. Klient prosi o mikroserwis, API, panel administracyjny – i nagle pojawia się pytanie: Laravel czy Symfony? Pokazuję oba z perspektywy doświadczonego developera PHP który zna Magento, ale chce świadomie wybrać narzędzie do nowego projektu.

Filozofia – skąd różnica w podejściu

Symfony i Laravel wyrosły z różnych priorytetów. Symfony (2011) jest inspirowane Javą i Springiem – modularność, konwencja nad konfiguracją w warstwie DI, komponenty jako niezależne biblioteki. Laravel (2011, Taylor Otwell) postawił na developer experience – mniej ceremonii, więcej magii, szybkość od pierwszego uruchomienia do działającego CRUD.

Magento 2 developer czuje się w Symfony jak w domu – DI przez XML/YAML, EventDispatcher, Console, HttpFoundation to te same komponenty które Magento używa. Laravel będzie wymagał przestawienia myślenia w kilku miejscach.

Struktura projektu – pierwsza różnica

# Symfony - nowy projekt
composer create-project symfony/skeleton my-project
cd my-project
composer require symfony/webapp-pack  # dodaj to czego potrzebujesz

# Laravel - nowy projekt
composer create-project laravel/laravel my-project
# Lub przez Laravel Installer
laravel new my-project
# Symfony - minimalna struktura, dodajesz co potrzebujesz
my-project/
  config/
    services.yaml      <- DI container
    routes.yaml        <- routing
    packages/          <- konfiguracja bundli
  src/
    Controller/
    Entity/
    Repository/
    Service/
  templates/           <- Twig
  tests/

# Laravel - pełna struktura od razu
my-project/
  app/
    Http/
      Controllers/
      Middleware/
    Models/
    Providers/
  config/              <- PHP arrays zamiast YAML
  database/
    migrations/
    seeders/
  resources/
    views/             <- Blade templates
  routes/
    web.php
    api.php

Dependency Injection – to co znasz z Magento

<?php

// Symfony - DI przez autowiring + services.yaml (jak Magento di.xml)
// config/services.yaml:
// App\Service\OrderService:
//     arguments:
//         $repository: '@App\Repository\OrderRepository'

class OrderController extends AbstractController
{
    public function __construct(
        private OrderService $orderService  // autowired automatycznie
    ) {}

    #[Route('/orders/{id}', methods: ['GET'])]
    public function show(int $id): JsonResponse
    {
        $order = $this->orderService->getById($id);
        return $this->json($order);
    }
}

// Laravel - DI przez Service Container (uproszczone, mniej XML)
class OrderController extends Controller
{
    public function __construct(
        private OrderService $orderService  // też autowired, zero konfiguracji
    ) {}

    public function show(int $id): JsonResponse
    {
        $order = $this->orderService->getById($id);
        return response()->json($order);
    }
}

W praktyce oba frameworki obsługują autowiring – wstrzykujesz przez konstruktor i działa. Symfony daje więcej kontroli przez YAML/XML konfigurację (znajome z Magento), Laravel polega bardziej na automatycznym wykrywaniu.

ORM – Doctrine (Symfony) vs Eloquent (Laravel)

<?php

// Doctrine (Symfony) - Data Mapper pattern
// Encja nie wie nic o bazie danych
#[ORM\Entity(repositoryClass: ProductRepository::class)]
#[ORM\Table(name: 'products')]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 64)]
    private string $sku;

    #[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
    private float $price;

    // Gettery i settery - brak metod DB w encji
    public function getSku(): string { return $this->sku; }
    public function setSku(string $sku): static { $this->sku = $sku; return $this; }
}

// Repository w Doctrine - osobna klasa
class ProductRepository extends ServiceEntityRepository
{
    public function findActiveBySku(string $sku): ?Product
    {
        return $this->createQueryBuilder('p')
            ->where('p.sku = :sku')
            ->andWhere('p.isActive = :active')
            ->setParameters(['sku' => $sku, 'active' => true])
            ->getQuery()
            ->getOneOrNullResult();
    }
}
<?php

// Eloquent (Laravel) - Active Record pattern
// Model wie o bazie - prostszy, ale więcej sprzężenia
class Product extends Model
{
    protected $fillable = ['sku', 'name', 'price', 'is_active'];

    protected $casts = [
        'price'     => 'float',
        'is_active' => 'boolean',
    ];

    // Relacje bezpośrednio w modelu
    public function categories(): BelongsToMany
    {
        return $this->belongsToMany(Category::class);
    }

    // Scope - warunkowe filtry wielokrotnego użytku
    public function scopeActive(Builder $query): void
    {
        $query->where('is_active', true);
    }
}

// Użycie - bardzo czytelne, mało kodu
$products = Product::active()
    ->where('price', '>', 50)
    ->with('categories')  // eager loading relacji
    ->paginate(20);

// Zapis
$product = Product::create(['sku' => 'NEW-001', 'name' => 'Nowy', 'price' => 29.99]);

Doctrine jest bliższe wzorcowi Repository który znasz z Magento 2 Service Contracts. Eloquent jest prostszy do szybkiego startu, ale Active Record miesza logikę domenową z dostępem do bazy.

Routing i middleware

<?php

// Symfony - routing przez atrybuty PHP 8 (lub YAML/XML)
#[Route('/api/products', name: 'api_products')]
class ProductApiController extends AbstractController
{
    #[Route('', methods: ['GET'])]
    public function list(Request $request): JsonResponse { /* ... */ }

    #[Route('/{id}', methods: ['GET'])]
    public function show(int $id): JsonResponse { /* ... */ }

    #[Route('', methods: ['POST'])]
    #[IsGranted('ROLE_ADMIN')]  // autoryzacja przez atrybuty
    public function create(Request $request): JsonResponse { /* ... */ }
}

// Symfony EventListener jako middleware (przez kernel events)
class AuthTokenListener
{
    #[AsEventListener(event: KernelEvents::REQUEST)]
    public function onKernelRequest(RequestEvent $event): void
    {
        $token = $event->getRequest()->headers->get('Authorization');
        // walidacja tokenu
    }
}
<?php

// Laravel - routing w routes/api.php
Route::prefix('products')->group(function () {
    Route::get('/', [ProductController::class, 'index']);
    Route::get('/{id}', [ProductController::class, 'show']);
    Route::post('/', [ProductController::class, 'store'])
         ->middleware('auth:sanctum');  // middleware inline
});

// Middleware Laravel
class EnsureApiKey
{
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->header('X-API-Key') !== config('app.api_key')) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $next($request); // Chain of Responsibility!
    }
}

Kiedy wybrać Symfony?

  • Projekt wymaga wysokiej modularności i długiego utrzymania
  • Zespół zna już Symfony lub Magento (znane konwencje DI)
  • Mikroserwisy gdzie potrzebujesz tylko wybranych komponentów
  • Projekt enterprise gdzie separacja warstw ma duże znaczenie
  • Potrzebujesz Doctrine z zaawansowanym mapowaniem encji

Kiedy wybrać Laravel?

  • Szybkie MVP lub prototyp – mniej boilerplate, szybszy start
  • Mniejszy zespół lub solo developer
  • CRUD-heavy aplikacje gdzie Active Record Eloquent przyspiesza pracę
  • Bogaty ekosystem pakietów (Cashier, Sanctum, Horizon, Nova)
  • Projekt który nie potrzebuje pełnej architektury DDD

Porównanie kluczowych cech

Aspekt Symfony Laravel
Krzywa uczenia Stroma Łagodna
Zbliżony do Magento 2 Tak (te same komponenty) Nie
ORM Doctrine (Data Mapper) Eloquent (Active Record)
DI Container Rozbudowany, YAML/XML Prosty, PHP array
Szablony Twig Blade
Ekosystem Komponenty niezależne Zintegrowane pakiety Laravel
Popularność (2023) Duża (enterprise) Bardzo duża (ogólnie)
Testowanie Doskonałe Bardzo dobre

Podsumowanie

Dla developera Magento 2 Symfony to mniejszy przeskok myślowy – konwencje DI, EventDispatcher i struktura projektu są znajome. Laravel wymaga resetowania nawyków, ale wynagradza szybkością budowania. Nie ma złego wyboru – oba frameworki są dojrzałe, dobrze utrzymane i mają świetną dokumentację. Wybierz na podstawie wymagań projektu i doświadczenia zespołu, nie na podstawie marketingu.

About Henryk Tews

Co możesz przeczytać następne

Blackfire – instalacja w DDEV, profilowanie HTTP i CLI, asercje w CI/CD
PHP 8.4 ostatnie RC – Lazy Objects, BcMath\Number, Dom\HTMLDocument
Drupal 10 – Entity Types, hooks, DI, headless przez JSON:API, porównanie z WP i Magento
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}