Symfony Component'leri ile Laravel Entegrasyonu
Laravel, temelinde birçok Symfony component'ini kullanır. HTTP katmanından konsol komutlarına, event dispatcher'dan Finder'a kadar pek çok yapı taşı doğrudan Symfony ekosisteminden gelir. Bu rehber, orta seviye bir Laravel geliştiricisinin mevcut bir Laravel uygulamasına bağımsız bir Symfony component'ini nasıl ekleyeceğini, servis container'ına nasıl bağlayacağını ve yaygın hatalardan nasıl kaçınacağını anlatır.
Önkoşullar
- Composer ile çalışan bir Laravel uygulaması.
- Laravel'in servis container, service provider ve facade mekanizmalarına aşinalık.
- PHP 8.x çalıştıran bir ortam.
Laravel sürümüne özel davranışlar bu rehberde varsayılmamıştır; anlatılan yöntem, Laravel'in servis container'ı ve service provider yapısını kullanan tüm modern sürümlerde geçerlidir. Kullanacağınız Symfony component'inin kendi minimum PHP sürümünü ayrıca kontrol edin.
Laravel Zaten Hangi Symfony Parçalarını Kullanıyor?
Laravel'in composer.json dosyasını incelediğinizde symfony/console, symfony/http-foundation, symfony/http-kernel, symfony/finder, symfony/process gibi paketleri bağımlılık olarak görürsünüz. Bu, iki önemli sonuç doğurur:
- Bu paketler zaten yüklü olduğundan, aynı component'i ayrıca kurmanız gerekmez.
- Laravel'in kullandığı sürüm aralığı, sizin doğrudan kullanacağınız sürümü de sınırlar.
composer requireile farklı bir major sürüm çekmeye çalışırsanız bağımlılık çakışması yaşarsınız.
Bu yüzden entegrasyona başlamadan önce composer show symfony/<component> komutuyla yüklü sürümü doğrulayın.
Bağımsız Bir Component Ekleme
Laravel'in hâlihazırda kullanmadığı bir component (örneğin symfony/serializer veya symfony/workflow) eklemek istediğinizi varsayalım:
composer require symfony/serializer
Composer, Laravel'in diğer Symfony bağımlılıklarıyla uyumlu bir sürümü çözmeye çalışır. Çakışma bildirirse, Laravel'in kilitlediği sürüm aralığına uyan bir sürüm belirtmeniz gerekir.
Service Provider ile Container'a Bağlama
Symfony component'lerinin çoğu framework'ten bağımsızdır; yani kendi başlarına bir servis container'ı bilmezler. Laravel tarafında bunları container'a kaydetmek sizin sorumluluğunuzdadır. Tipik yaklaşım bir service provider içinde singleton veya bind kullanmaktır.
Örnek olarak Symfony Serializer'ı yapılandıralım:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
class SerializerServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(Serializer::class, function () {
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
return new Serializer($normalizers, $encoders);
});
}
}
Provider'ı bootstrap/providers.php (veya sürümünüze göre config/app.php) içine ekleyin. Artık Serializer sınıfını constructor üzerinden enjekte edebilir veya app(Serializer::class) ile çözebilirsiniz.
Beklenen Davranış
singleton kaydı sayesinde Serializer örneği uygulama yaşam döngüsü boyunca bir kez oluşturulur ve aynı örnek paylaşılır. Eğer her çözümlemede yeni bir örnek istiyorsanız singleton yerine bind kullanın. Bu ayrım özellikle durum tutan (stateful) component'lerde önemlidir; yanlış seçim, istekler arası beklenmeyen veri sızıntısına yol açabilir.
Facade ile Erişim (İsteğe Bağlı)
Container kaydını kısa yoldan çağırmak isterseniz bir facade tanımlayabilirsiniz:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Serializer extends Facade
{
protected static function getFacadeAccessor(): string
{
return \Symfony\Component\Serializer\Serializer::class;
}
}
Facade'ler yalnızca container'daki bir anahtarı temsil eder; ek bir sihir içermez. Test edilebilirlik açısından constructor injection genellikle daha açık bir tercihtir.
Yaygın Hatalar
Sürüm çakışması. Laravel'in kilitlediği bir Symfony paketinin farklı major sürümünü kurmaya çalışmak. Çözüm: composer why-not symfony/<paket> <sürüm> ile engeli tespit edin.
Config'i görmezden gelmek. Bazı component'ler (örneğin Serializer normalizer'ları) yapılandırma gerektirir. Varsayılan kurulumla beklediğiniz çıktıyı alamazsanız, önce normalizer/encoder listesini kontrol edin.
Component'i Laravel'e özgü sanmak. Symfony component'leri framework bağımsızdır; config/ dosyalarından otomatik okumazlar. Yapılandırmayı provider içinde elle yapmanız gerekir.
Container'da yanlış yaşam döngüsü. Durum tutan bir servisi singleton yapmak, uzun ömürlü worker ortamlarında (queue worker, Octane) istekler arası durum taşınmasına neden olabilir.
Güvenlik Notları
- Deserialization. Serializer veya benzeri component'lerle dış kaynaktan gelen veriyi çözerken
unserializetabanlı yapılardan kaçının. JSON gibi metin tabanlı formatları tercih edin; nesne enjeksiyonuna açıkallowed_classesgibi ayarları bilinçli yapılandırın. - Dosya sistemi component'leri.
symfony/finderveyasymfony/filesystemile kullanıcı girdisinden türetilen yollar üzerinde işlem yapıyorsanız path traversal riskini hesaba katın ve yolları doğrulayın. - Process component'i.
symfony/processile dış komut çalıştırırken kullanıcı girdisini doğrudan komut dizisine eklemeyin; argümanları ayrı dizi elemanları olarak geçirin.
Ne Zaman Symfony Component'i, Ne Zaman Laravel Yapısı?
Laravel'in sunduğu bir çözüm (örneğin Illuminate\Support\Facades\Http, Illuminate\Support\Str) ihtiyacınızı karşılıyorsa önce onu değerlendirin; framework ile uyum ve dokümantasyon açısından daha az sürtünme yaratır. Symfony component'i tercih etmenin anlamlı olduğu durumlar:
- İhtiyacınız Laravel'in kapsamadığı bir alandaysa (örneğin karmaşık iş akışları için
symfony/workflow). - Framework'ten bağımsız, taşınabilir bir kod parçası yazıyorsanız.
- Component'in olgun ekosistemi ve dokümantasyonu projeniz için belirgin avantaj sağlıyorsa.
Sonuç
Laravel ile Symfony component'lerini birleştirmek, framework'ün zaten kurduğu altyapıyı genişletmekten ibarettir: paketi doğru sürümle kurun, service provider içinde container'a bağlayın, yaşam döngüsünü bilinçli seçin ve güvenlik sınırlarını (deserialization, dosya yolları, dış komutlar) net çizin. Bu dört adım, çoğu entegrasyonun ortak çerçevesidir.