Gereksinimler ve Ön Hazırlık
Bu projeyi hayata geçirmek için Laravel 11 veya üzeri bir sürümün kurulu olduğu bir çalışma ortamına ihtiyacınız vardır. Dosya işleme süreçlerinde yüksek performans almak adına Laravel Excel (Maatwebsite) paketini kullanacağız. Ayrıca arka plan işlemlerini yönetmek için Redis veya veritabanı sürücüsü yapılandırılmış bir kuyruk sisteminizin olması zorunludur.
- PHP 8.3 veya üzeri bir sürüm.
- Composer paket yöneticisi.
- Redis veya veritabanı tabanlı kuyruk sürücüsü.
- Maatwebsite/Laravel-Excel paketi.
Kurulum için terminalinizde şu komutu çalıştırarak gerekli bağımlılıkları projenize dahil edebilirsiniz:
composer require maatwebsite/excel
Bu komut, Excel ve CSV dosyalarını Laravel içerisinde nesne yönelimli bir şekilde okumanıza ve işlemenize olanak tanıyan güçlü bir kütüphaneyi projenize ekler.
Adım 1: Dosya Yükleme ve Geçici Depolama Yapısı
Çok adımlı import sistemlerinde ilk adım, dosyanın güvenli bir şekilde alınması ve doğrulanmasıdır. Kullanıcı dosyayı yüklediğinde, veriyi hemen işlemek yerine geçici bir alana (storage/app/imports) kaydederek bir "Import Job" oluşturmalıyız. Bu, kullanıcıyı bekletmeden işlemin arka plana atılmasını sağlar.
public function store(Request $request)
{
$request->validate([
'import_file' => 'required|file|mimes:xlsx,csv|max:10240',
]);
$path = $request->file('import_file')->store('imports');
// Import işlemini başlatacak olan Job'ı kuyruğa gönderiyoruz
ProcessImportJob::dispatch($path, auth()->id());
return response()->json(['message' => 'Dosya işlenmek üzere kuyruğa alındı.']);
}
Yukarıdaki kod, dosyanın boyutunu ve türünü kontrol eder. 10MB sınırı, sunucunun aşırı yüklenmesini engellemek için kritik bir güvenlik önlemidir.
Adım 2: Dinamik Veri Okuma ve İşleme Mantığı
Veriyi okurken tüm dosyanın belleğe yüklenmesini engellemek için "Chunking" (parçalara bölme) yöntemini kullanmalıyız. Laravel Excel paketi, ToCollection veya ToModel arayüzleri ile bu süreci kolaylaştırır. Dinamik bir yapı için veriyi bir DTO (Data Transfer Object) yapısına dönüştürmek, kodunuzu daha sürdürülebilir kılar.
namespace App\Imports;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithChunkReading;
class DynamicImport implements ToModel, WithChunkReading
{
public function model(array $row)
{
return new User([
'name' => $row[0],
'email' => $row[1],
]);
}
public function chunkSize(): int
{
return 1000;
}
}
chunkSize metodu, her adımda 1000 satırın işlenmesini sağlar. Bu, belleğin (RAM) korunması için hayati bir öneme sahiptir.
Adım 3: Çok Adımlı Süreç Yönetimi (Batching)
Import işleminin hangi aşamada olduğunu takip etmek için Laravel'in Bus::batch özelliğini kullanırız. Bu özellik, birden fazla işi (job) tek bir grup altında toplamanıza ve bu grubun ilerlemesini izlemenize olanak tanır.
use Illuminate\Support\Facades\Bus;
$batch = Bus::batch([
new ImportChunkJob($dataPart1),
new ImportChunkJob($dataPart2),
])->dispatch();
return $batch->id;
Bu yapı sayesinde, kullanıcıya "İşlemin %40'ı tamamlandı" gibi dinamik geri bildirimler sunabilirsiniz.
Adım 4: Veri Doğrulama ve Hata Yönetimi
Import edilen verilerin veritabanı şemasına uygunluğu kritik bir güvenlik konusudur. SQL Injection riskini önlemek için her zaman Eloquent veya Query Builder'ın sunduğu "binding" yöntemlerini kullanın. Hatalı satırları bir log dosyasında veya veritabanında "failed_imports" tablosunda tutmak, kullanıcıya detaylı hata raporu sunmanızı sağlar.
public function validateRow(array $row)
{
$validator = Validator::make($row, [
'0' => 'required|string',
'1' => 'required|email|unique:users,email',
]);
if ($validator->fails()) {
throw new \Exception('Satır doğrulama hatası: ' . implode(', ', $validator->errors()->all()));
}
}
Kritik Uyarı: Kullanıcıdan gelen her veriyi mutlaka doğrulayın. Asla doğrudan ham veriyi veritabanı sorgularına dahil etmeyin. Dosya yükleme dizinlerini "public" erişime kapatın ve dosyaları her zaman benzersiz isimlerle kaydedin.
Adım 5: Kullanıcıya Geri Bildirim ve İlerleme Takibi
Kullanıcı, işlemin durumunu öğrenmek için bir API endpoint'ine istek atabilir. Batch ID üzerinden işlemin durumunu sorgulayarak, arayüzde bir ilerleme çubuğu (progress bar) güncelleyebilirsiniz.
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Senkron (Anlık) | Basit yapı | Sunucu zaman aşımı riski |
| Queue (Kuyruk) | Yüksek performans | Karmaşık kurulum |
| Batching | Detaylı takip | Redis bağımlılığı |
Sıkça Sorulan Sorular
Import işlemi sırasında bellek hatası (Memory Limit) alıyorum, ne yapmalıyım?
Bu durum, dosyanın tamamının belleğe yüklenmeye çalışıldığını gösterir. WithChunkReading özelliğini kullandığınızdan ve chunk boyutunu 500-1000 aralığında tuttuğunuzdan emin olun.
Import edilen verilerde SQL Injection riskini nasıl engellerim?
Laravel'in Eloquent ORM yapısını veya Query Builder'ı kullanarak verileri her zaman "binding" (bağlama) yöntemiyle kaydedin. Ham SQL sorguları yazmaktan kaçının.
Büyük dosyaları işlerken işlem çok uzun sürüyor, nasıl hızlandırırım?
Kuyruk çalışanlarınızın (worker) sayısını artırın. php artisan queue:work --processes=4 komutu ile birden fazla worker'ın aynı anda farklı chunk'ları işlemesini sağlayabilirsiniz.
Hatalı satırları nasıl raporlayabilirim?
Her bir chunk işlenirken, hata alan satırları bir veritabanı tablosuna veya JSON dosyasına "satır numarası" ve "hata mesajı" ile kaydederek kullanıcıya bir "Hata Raporu İndir" butonu sunabilirsiniz.
Batch (Grup) işlemleri için mutlaka Redis mi kullanmalıyım?
Laravel Batching özelliği veritabanı tabanlı kuyruklarda da çalışır ancak yüksek trafikli sistemlerde performans ve atomik işlemler için Redis önerilir.
Sorumluluk Reddi: Bu rehberdeki kod örnekleri genel eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka kendi güvenlik testlerinizi yapın ve veritabanı işlemlerinde transaction (işlem yönetimi) kullanarak veri bütünlüğünü sağlayın.
Import Süreçlerinde Veri Bütünlüğü ve Transaction Yönetimi
Büyük veri setlerini veritabanına aktarırken, işlemin yarısında oluşabilecek bir hata tüm veritabanının tutarsız hale gelmesine neden olabilir. Laravel'in sunduğu DB::transaction yapısı, import işleminin "ya hep ya hiç" prensibiyle çalışmasını sağlar. Özellikle chunk işlemleri sırasında her bir grup için ayrı bir transaction bloğu kullanmak, sistemin kararlılığını artırır.
use Illuminate\Support\Facades\DB;
public function importChunk($data)
{
DB::transaction(function () use ($data) {
foreach ($data as $row) {
User::updateOrCreate(
['email' => $row['email']],
['name' => $row['name'], 'status' => 'active']
);
}
});
}
Bu yaklaşım, bir bloktaki herhangi bir satır hata verdiğinde, o bloğun tamamının geri alınmasını (rollback) sağlar. Böylece veritabanında "yarı işlenmiş" kayıtlar oluşmaz.
İleri Seviye Performans Optimizasyonu: Upsert Kullanımı
Veri import işlemlerinde en büyük darboğaz, her satır için ayrı ayrı yapılan SELECT ve INSERT sorgularıdır. Laravel 8 ve sonrası ile gelen upsert metodu, veritabanı üzerindeki yükü ciddi oranda azaltır. Bu yöntem, veritabanına tek bir sorgu göndererek mevcut kayıtları güncellemeyi veya yeni kayıt eklemeyi sağlar.
public function bulkUpsert(array $data)
{
// Verileri 1000'lik parçalar halinde upsert ediyoruz
$chunks = array_chunk($data, 1000);
foreach ($chunks as $chunk) {
User::upsert(
$chunk,
['email'], // Benzersiz anahtar (unique key)
['name', 'updated_at'] // Güncellenecek sütunlar
);
}
}
Performans İpuçları:
- Index Kullanımı:
upsertişleminde kullanılan sütunların (örneğinemail) veritabanında mutlakaUNIQUEindex'e sahip olduğundan emin olun. Aksi takdirde sorgu süresi logaritmik olarak artacaktır. - Model Event'lerini Devre Dışı Bırakın: Çoklu import işlemlerinde
Model::withoutEvents()kullanarakcreatedveyaupdatedevent'lerinin tetiklenmesini engelleyin. Bu, her satır için ayrı bir observer çalışmasını durdurarak işlem süresini %40'a kadar hızlandırır. - Log Seviyesini Yönetin: Import işlemi sırasında
dailylog dosyalarınızın aşırı büyümemesi için, sadece kritik hataları loglayan özel bir kanal oluşturun.
Import Süreçleri İçin Otomatik Test Stratejileri
Dinamik import sistemlerinde hata payını düşürmek için "Unit" ve "Feature" testleri yazmak zorunludur. Özellikle dosya yükleme ve işleme mantığını test etmek için Laravel'in Storage::fake() özelliğini kullanmalısınız.
public function test_csv_import_processes_data_correctly()
{
Storage::fake('local');
$file = UploadedFile::fake()->create('users.csv', 100);
$this->post('/import', ['file' => $file])
->assertStatus(200);
$this->assertDatabaseHas('users', ['email' => 'test@example.com']);
}
Bu test senaryosu, dosyanın sisteme yüklendiğini, işlendiğini ve veritabanına doğru şekilde kaydedildiğini doğrular. Import sisteminizi yayına almadan önce, özellikle "bozuk CSV formatı" ve "eksik sütun" gibi uç durumları (edge cases) kapsayan testler eklemeyi unutmayın.
Sonuç
Laravel ile çok adımlı dinamik veri import sistemi kurmak, başlangıçta karmaşık görünse de, kuyruk yönetimi ve chunking teknikleri ile yönetilebilir bir süreç haline gelir. Bu mimari, uygulamanızın ölçeklenebilirliğini artırır ve kullanıcılarınıza kesintisiz bir deneyim sunar. Bir sonraki adım olarak, import edilen verilerin doğruluğunu kontrol etmek için bir "Önizleme (Preview)" ekranı tasarlamayı ve kullanıcıya verileri onaylatmayı deneyebilirsiniz.


Yorumlar (0)
Yorum Yaz