# 2026 Yilinda En Cok Sorulan 25 Laravel ve PHP Mulakat Sorusu > Laravel mulakat sorulari: Service Container, Eloquent ORM, middleware, kuyruklar, guvenlik, test ve mimari desenler hakkinda 25 soru ve kod ornekleriyle kapsamli bir rehber. - Published: 2026-01-30 - Updated: 2026-04-12 - Author: SharpSkill - Tags: laravel, php, interview, eloquent, technical interview - Reading time: 22 min --- Laravel mulakatlari, framework hakimiyetini, PHP ekosistemi bilgisini ve olceklenebilir web uygulamalari tasarlama becerisini olcer. Bu rehber, framework temellerinden performans optimizasyonuna ve uretim ortamina dagitima kadar mulakatlarda en sik karsilasilan 25 soruyu kapsar. > **Mulakat Ipucu** > > Mulakatcilar, Laravel'in mimari kararlarini aciklayabilen adaylardan etkilenir. Framework'un neden belirli konvansiyonlari benimsedigini (Convention over Configuration, Service Container) anlamak mulakatlarda gercek bir fark yaratir. ## Laravel Temelleri ### 1. Service Container nedir ve Laravel'deki rolu nedir? Service Container, Laravel framework'unun cekirdegini olusturan guclu bir bagimlilik yonetimi ve dependency injection mekanizmasidir. Her Laravel uygulamasi, arayuzler ile somut implementasyonlari arasindaki baglantiyi kaydeden ve cozumleyen tek bir konteynere sahiptir. Bu yaklasim, koddaki bagimliliklari gevsetir ve test edilebilirligi arttirir. ```php // AppServiceProvider.php use App\Contracts\PaymentGateway; use App\Services\StripePaymentGateway; public function register(): void { // Bind interface to concrete implementation $this->app->bind(PaymentGateway::class, StripePaymentGateway::class); // Singleton: resolved once, same instance reused $this->app->singleton(PaymentGateway::class, function ($app) { return new StripePaymentGateway( config('services.stripe.secret') ); }); } ``` ```php // OrderController.php class OrderController extends Controller { // Automatic injection via type-hinting public function __construct( private readonly PaymentGateway $payment ) {} public function store(Request $request): JsonResponse { $result = $this->payment->charge( $request->validated('amount') ); return response()->json($result); } } ``` Konteyner, type-hint'lere dayali olarak bagimliliklari otomatik cozumler. Bir sinif konteynerde kayitli bir arayuze bagimli oldugunda, Laravel ek bir yapilandirma gerektirmeden uygun implementasyonu enjekte eder. ### 2. Service Provider ile Service Container arasindaki fark nedir? Service Container, bagimliliklari depolayan ve cozumleyen mekanizmadir. Service Provider ise konteynere baglantilar kaydeden ve uygulama hizmetlerini yapilandiran siniftir. Her provider iki metoda sahiptir: hizmet baglamak icin `register()` ve zaten kayitli hizmetlere ihtiyac duyan islemler icin `boot()`. ```php // AnalyticsServiceProvider.php class AnalyticsServiceProvider extends ServiceProvider { public function register(): void { // register() - only bind things into the container $this->app->singleton(AnalyticsTracker::class, function ($app) { return new AnalyticsTracker( $app->make(HttpClient::class), config('analytics.key') ); }); } public function boot(): void { // boot() - all providers are registered, safe to use them $tracker = $this->app->make(AnalyticsTracker::class); $tracker->registerDefaultEvents(); // Publish config for package users $this->publishes([ __DIR__.'/../config/analytics.php' => config_path('analytics.php'), ]); } } ``` Provider, `config/app.php` dosyasindaki `providers` dizisinde belirtilir. Laravel bunlari sirayla yukler: once tum provider'larda `register()`, ardindan `boot()` cagrilir. Bu, yapilandirma sirasinda tum hizmetlerin mevcut olmasini garanti eder. ### 3. Laravel'de bir HTTP isteginin yasam dongusu nasil isler? Laravel'deki her HTTP istegi kesin bir siralama izler. `public/index.php` dosyasi Composer autoloader'i yukler ve uygulama ornegini olusturur. Ardindan istek HTTP kernel'inden gecer; kernel global middleware'leri calistirir ve router istegi uygun rotaya yonlendirir. Controller mantigi isler ve bir yanit dondurur; yanit ters sirada middleware'lerden tekrar gecer. ```php // Simplified request lifecycle // 1. public/index.php - Entry point $app = require_once __DIR__.'/../bootstrap/app.php'; // 2. HTTP Kernel handles the request $kernel = $app->make(Kernel::class); $response = $kernel->handle( $request = Request::capture() ); // 3. Inside Kernel: middleware pipeline // Global middleware -> Route middleware -> Controller // 4. Router matches the request Route::get('/orders/{order}', [OrderController::class, 'show']) ->middleware(['auth', 'verified']); // 5. Controller returns response // 6. Response passes back through middleware // 7. Response sent to browser $response->send(); $kernel->terminate($request, $response); ``` Dongununun sonundaki `terminate()` metodu, yanit gonderildikten sonra islem yapilmasini saglar: log kaydi, baglanti kapatma gibi. ### 4. Laravel'de Facade'lar nedir ve arka planda nasil calisir? Facade'lar, Service Container'da kayitli hizmetlere statik soz dizimi ile erisim saglar. Ancak bunlar gercek statik siniflar degildir. Arka planda her facade, konteynerde cozumlenen ilgili nesneye cagrivi devreder. `getFacadeAccessor()` metodu konteynerdeki baglanti anahtarini dondurur. ```php // How facades work under the hood // Using the Cache facade Cache::put('user_123', $userData, 3600); // Is equivalent to: app('cache')->put('user_123', $userData, 3600); // The facade class: class Cache extends Facade { protected static function getFacadeAccessor(): string { return 'cache'; // Key in the service container } } // Real-time facades - any class can become a facade use Facades\App\Services\PaymentGateway; PaymentGateway::charge(1000); // Resolves from container ``` Facade'lar test surecini kolaylastirir. Laravel, `Cache::shouldReceive()` ile facade mock'lamasina olanak tanir ve birim testlerinin basit ve okunabilir kalmasini saglar. ## Eloquent ORM ### 5. hasOne, hasMany, belongsTo ve belongsToMany iliskileri arasindaki farklar nelerdir? Eloquent, iliskileri model metotlari olarak tanimlar. `hasOne` bire-bir iliskidir ve yabanci anahtar iliskili tablodadir. `hasMany` bire-cok iliskidir. `belongsTo` bunlarin tersidir; model yabanci anahtari icerir. `belongsToMany` bir pivot tablo araciligiyla coka-cok iliskileri yonetir. ```php // User.php class User extends Model { // One-to-One: users.id -> profiles.user_id public function profile(): HasOne { return $this->hasOne(Profile::class); } // One-to-Many: users.id -> posts.user_id public function posts(): HasMany { return $this->hasMany(Post::class); } // Many-to-Many: users <-> role_user <-> roles public function roles(): BelongsToMany { return $this->belongsToMany(Role::class) ->withPivot('assigned_at') ->withTimestamps(); } } // Post.php class Post extends Model { // Inverse of hasMany public function user(): BelongsTo { return $this->belongsTo(User::class); } } ``` ```php // Usage examples $user = User::find(1); // Lazy loading $profile = $user->profile; // Single query $posts = $user->posts; // Collection of posts // Eager loading to avoid N+1 $users = User::with(['posts', 'roles'])->get(); // Querying relationships $activeAuthors = User::whereHas('posts', function ($query) { $query->where('published', true) ->where('created_at', '>=', now()->subMonth()); })->get(); ``` Dogru iliski secimi sorgu performansini ve kod okunabilirligini dogrudan etkiler. `with()` ile eager loading, N+1 sorununu ortadan kaldirir. ### 6. Eloquent Scope'lar nasil calisir ve ne zaman kullanilmalidir? Scope'lar, yinelenen sorgu kosullarini model metotlarinda kapsuller. Iki turu vardir: sorgu zincirinde acikca cagrilan Local Scope'lar ve modelin her sorgusuna otomatik uygulanan Global Scope'lar. ```php // Post.php - Local Scopes class Post extends Model { // Local scope - called explicitly public function scopePublished(Builder $query): Builder { return $query->where('status', 'published') ->whereNotNull('published_at'); } public function scopeByAuthor(Builder $query, int $userId): Builder { return $query->where('user_id', $userId); } // Chainable scopes public function scopeRecent(Builder $query, int $days = 7): Builder { return $query->where('created_at', '>=', now()->subDays($days)); } } // Usage: clean, readable queries $posts = Post::published() ->recent(30) ->byAuthor($userId) ->paginate(15); ``` ```php // Global Scope - applied to ALL queries on the model class ActiveScope implements Scope { public function apply(Builder $builder, Model $model): void { $builder->where('is_active', true); } } // In the model class Subscription extends Model { protected static function booted(): void { static::addGlobalScope(new ActiveScope()); } } // All queries automatically filter active Subscription::all(); // WHERE is_active = true // Remove global scope when needed Subscription::withoutGlobalScope(ActiveScope::class)->get(); ``` Scope'lar kod okunabilirligini arttirir ve filtreleme mantigi tekrarini onler. Global Scope'lar dikkatli kullanilmalidir; otomatik filtreleme zor teshis edilen hatalara yol acabilir. ### 7. Eloquent Mutators ve Casts nedir ve model niteliklerini nasil etkiler? Mutators ve Casts, model niteliklerinin yazilma ve okunma seklini kontrol eder. Casts otomatik tip donusumu tanimlar; Mutators (accessor ve mutator) ise `Attribute` metotlari araciligiyla istege bagli deger donusumu saglar. ```php // User.php - Attribute Casting and Mutators class User extends Model { // Automatic type casting protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'preferences' => 'array', // JSON <-> array 'is_admin' => 'boolean', 'salary' => 'decimal:2', 'metadata' => AsCollection::class, 'secret' => 'encrypted', // Auto encrypt/decrypt ]; } // Modern accessor (Laravel 9+) protected function fullName(): Attribute { return Attribute::make( get: fn () => "{$this->first_name} {$this->last_name}", ); } // Accessor + Mutator combined protected function email(): Attribute { return Attribute::make( get: fn (string $value) => strtolower($value), set: fn (string $value) => strtolower(trim($value)), ); } } ``` ```php // Custom Cast class for complex transformations class MoneyCast implements CastsAttributes { public function get(Model $model, string $key, mixed $value, array $attributes): Money { return new Money( amount: $attributes[$key], currency: $attributes['{$key}_currency'] ?? 'USD' ); } public function set(Model $model, string $key, mixed $value, array $attributes): array { return [ $key => $value->amount, "{$key}_currency" => $value->currency, ]; } } // Usage in model protected function casts(): array { return [ 'price' => MoneyCast::class, ]; } ``` Casts, controller ve view katmanlarinda manuel tip donusumu gereksinimini ortadan kaldirir. Ozel Cast siniflari, tam kapsulleme ile karmasik deger tiplerini modellemeye olanak tanir. ## Middleware ve Yonlendirme ### 8. Laravel'de middleware nasil calisir ve ozel middleware nasil olusturulur? Middleware, HTTP istegini controller'a ulasmadan once veya sonra isleyen filtrelerdir. Laravel'de global middleware (her istekte calisan), rota grubu middleware'leri ve belirli rotalara atanan middleware'ler bulunur. Calisma sirasi onemlidir: middleware istegi degistirebilir, kesebilir veya yaniti modifiye edebilir. ```php // EnsureUserIsSubscribed.php class EnsureUserIsSubscribed { public function handle(Request $request, Closure $next): Response { if (!$request->user()?->isSubscribed()) { if ($request->expectsJson()) { return response()->json([ 'message' => 'Subscription required.' ], 403); } return redirect()->route('subscribe'); } return $next($request); } } // After middleware - runs after the response class AddSecurityHeaders { public function handle(Request $request, Closure $next): Response { $response = $next($request); $response->headers->set('X-Content-Type-Options', 'nosniff'); $response->headers->set('X-Frame-Options', 'DENY'); $response->headers->set('Strict-Transport-Security', 'max-age=31536000'); return $response; } } ``` ```php // bootstrap/app.php (Laravel 11+) return Application::configure(basePath: dirname(__DIR__)) ->withMiddleware(function (Middleware $middleware) { // Global middleware $middleware->append(AddSecurityHeaders::class); // Named middleware for routes $middleware->alias([ 'subscribed' => EnsureUserIsSubscribed::class, ]); // Middleware groups $middleware->appendToGroup('api', [ ThrottleRequests::class.':api', ]); }) ->create(); // Usage in routes Route::middleware('subscribed')->group(function () { Route::get('/premium', [PremiumController::class, 'index']); }); ``` Laravel 11 itibariyla middleware yapilandirmasi Kernel sinifindan `bootstrap/app.php` dosyasina tasinmistir ve uygulama yapisini sadeler. ### 9. Laravel'de rota gruplari ve RESTful kaynak yonlendirmesi nasil calisir? Rota gruplari, birden fazla rota arasinda ozellikleri (middleware, on ek, ad alani) paylasmayi saglar. Resource controller'lar, REST konvansiyonuna uygun CRUD rotalarini otomatik olusturur. ```php // routes/web.php // Route grouping with shared attributes Route::prefix('admin') ->middleware(['auth', 'admin']) ->name('admin.') ->group(function () { Route::get('/dashboard', [AdminController::class, 'dashboard']) ->name('dashboard'); // Resource controller: 7 RESTful routes Route::resource('articles', ArticleController::class); // API resource: excludes create/edit (no forms) Route::apiResource('categories', CategoryController::class); }); // Nested resources Route::resource('posts.comments', CommentController::class) ->scoped() // Auto scope bindings ->shallow(); // Shallow nesting for simplicity // Route model binding with custom resolution Route::get('/users/{user:username}', [UserController::class, 'show']); ``` ```php // ArticleController.php - Resource Controller class ArticleController extends Controller { // GET /admin/articles public function index(): View { /* list */ } // GET /admin/articles/create public function create(): View { /* form */ } // POST /admin/articles public function store(StoreArticleRequest $request): RedirectResponse { $article = Article::create($request->validated()); return redirect()->route('admin.articles.show', $article); } // GET /admin/articles/{article} public function show(Article $article): View { /* display */ } // GET /admin/articles/{article}/edit public function edit(Article $article): View { /* form */ } // PUT /admin/articles/{article} public function update(UpdateArticleRequest $request, Article $article): RedirectResponse { $article->update($request->validated()); return redirect()->route('admin.articles.show', $article); } // DELETE /admin/articles/{article} public function destroy(Article $article): RedirectResponse { $article->delete(); return redirect()->route('admin.articles.index'); } } ``` Route model binding, URL parametrelerine dayali olarak modelleri otomatik cozumler. `{user:username}` parametresi, `id` yerine `username` kolonuna gore kullaniciyi arar. ## Kuyruklar ve Gorevler (Queues & Jobs) ### 10. Laravel'de kuyruklar nasil calisir ve ne zaman kullanilmalidir? Kuyruklar, zaman alan islemleri (e-posta gonderme, dosya isleme, harici API senkronizasyonu) erteleyerek HTTP yanitinin engellenmesini onler. Laravel, Redis, Amazon SQS ve veritabani dahil birden fazla kuyruk surucusunu destekler. ```php // ProcessPodcastJob.php class ProcessPodcast implements ShouldQueue { use Queueable; public int $tries = 3; public int $backoff = 60; // seconds between retries public int $timeout = 120; public function __construct( private readonly Podcast $podcast ) {} public function handle(AudioProcessor $processor): void { $processed = $processor->process( $this->podcast->audio_path ); $this->podcast->update([ 'processed_path' => $processed->path, 'duration' => $processed->duration, 'status' => 'ready', ]); } public function failed(\Throwable $exception): void { // Notify admin of failure $this->podcast->update(['status' => 'failed']); Log::error('Podcast processing failed', [ 'podcast_id' => $this->podcast->id, 'error' => $exception->getMessage(), ]); } } ``` ```php // Dispatching jobs // Basic dispatch ProcessPodcast::dispatch($podcast); // Delayed dispatch ProcessPodcast::dispatch($podcast) ->delay(now()->addMinutes(10)); // Specific queue ProcessPodcast::dispatch($podcast) ->onQueue('audio-processing'); // Job chaining - sequential execution Bus::chain([ new ProcessPodcast($podcast), new OptimizeAudio($podcast), new PublishPodcast($podcast), ])->dispatch(); // Job batching - parallel with completion tracking Bus::batch([ new ProcessChapter($podcast, 1), new ProcessChapter($podcast, 2), new ProcessChapter($podcast, 3), ])->then(function (Batch $batch) { Log::info('All chapters processed!'); })->catch(function (Batch $batch, Throwable $e) { Log::error('Batch failed: '.$e->getMessage()); })->dispatch(); ``` Job chaining gorevlerin sirali yurutulmesini garantiler; batching ise tamamlanma ve hata olaylarini izleyerek paralel islemeyi mumkun kilar. ### 11. Kuyruk middleware'leri nedir ve gorev hiz sinirlamasi nasil yonetilir? Kuyruk middleware'leri, gorevlerin yurutulme seklini kontrol etmeye olanak tanir: sikligi sinirlandirma, tekrarlari onleme veya asiri yuk durumunda erteleme. Gorev sinifindaki `middleware()` metodunda tanimlanir. ```php // RateLimitedJob.php class CallExternalApi implements ShouldQueue { use Queueable; public function middleware(): array { return [ // Max 10 jobs per minute for this API new ThrottlesExceptions(10, 5), // Rate limiting by key (new RateLimited('external-api')) ->dontRelease(), // Don't retry if rate limited // Prevent overlapping - only one at a time new WithoutOverlapping($this->userId), ]; } public function handle(): void { // API call logic } public function retryUntil(): DateTime { return now()->addHours(1); } } ``` ```php // Define rate limiter in AppServiceProvider RateLimiter::for('external-api', function (object $job) { return Limit::perMinute(30); }); // Unique jobs - prevent duplicates in queue class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique { use Queueable; // Unique for 1 hour public int $uniqueFor = 3600; public function uniqueId(): string { return $this->product->id; } public function handle(): void { // Only one job per product in queue at a time } } ``` `WithoutOverlapping` middleware'i ayni anahtara sahip gorevlerin esanli yurutulmesini engelleyerek veri catismalarini onler. `ShouldBeUnique`, belirli bir kimlik icin kuyrukta en fazla bir gorev bulunmasini saglar. ## Guvenlik ve Kimlik Dogrulama ### 12. Laravel, CSRF, XSS ve SQL Injection saldirilarina karsi nasil koruma saglar? Laravel, en yaygin web saldirilarina karsi cok katmanli koruma sunar. CSRF token'lari formlari korur, Blade sablon motoru cikti verilerini otomatik olarak kacis karakterleriyle isler (XSS korumasi) ve Eloquent ile Query Builder hazirlanmis sorgular kullanir (SQL Injection korumasi). ```php // CSRF Protection - automatic in forms
// XSS Protection - Blade auto-escapes {{ $userInput }} {{-- Escaped: <script> --}} {!! $trustedHtml !!} {{-- Raw: use only for trusted content --}} // SQL Injection Protection // Safe - parameterized query $users = User::where('email', $request->email)->get(); $users = DB::select('SELECT * FROM users WHERE email = ?', [$email]); // DANGEROUS - raw unescaped input $users = DB::select("SELECT * FROM users WHERE email = '$email'"); // NEVER DO THIS ``` ```php // Mass Assignment Protection class User extends Model { // Only these fields can be mass-assigned protected $fillable = ['name', 'email', 'avatar']; // Or protect specific fields protected $guarded = ['is_admin', 'role']; } // Rate limiting for API protection // bootstrap/app.php $middleware->appendToGroup('api', [ ThrottleRequests::class.':60,1', // 60 requests per minute ]); ``` `$fillable` veya `$guarded` ile mass assignment korumasi, model uzerindeki hassas alanlarin yetkisiz degistirilmesini onler. Whitelist yaklasimi olarak `$fillable` kullanilmasi onerilir. ### 13. Laravel'de kimlik dogrulama sistemi nasil calisir? Laravel, birden fazla guard ve provider destegi ile kapsamli bir kimlik dogrulama sistemi sunar. Guard'lar her istekte kullanicinin nasil dogrulandigini tanimlar; provider'lar ise kullanici verisi kaynagini belirler. ```php // config/auth.php return [ 'defaults' => [ 'guard' => 'web', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'sanctum', 'provider' => 'users', ], 'admin' => [ 'driver' => 'session', 'provider' => 'admins', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'admins' => [ 'driver' => 'eloquent', 'model' => App\Models\Admin::class, ], ], ]; ``` ```php // Authentication in controllers class AuthController extends Controller { public function login(LoginRequest $request): RedirectResponse { $credentials = $request->validated(); if (Auth::attempt($credentials, $request->boolean('remember'))) { $request->session()->regenerate(); return redirect()->intended('dashboard'); } throw ValidationException::withMessages([ 'email' => __('auth.failed'), ]); } public function logout(Request $request): RedirectResponse { Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/'); } } // Multi-guard authentication Auth::guard('admin')->attempt($credentials); Auth::guard('api')->user(); ``` Giris sonrasi `session()->regenerate()` oturum sabitleme (session fixation) saldirilarina karsi korur. Cikista `session()->invalidate()` oturumu tamamen yok eder. ### 14. Laravel'de Gate ve Policy ile yetkilendirme nasil calisir? Gate'ler genel yetkileri tanimlayan closure'lardir; Policy'ler ise belirli bir modele ait yetkilendirme mantgini gruplayan siniflardir. Gate'ler basit kontroller icin, Policy'ler CRUD islemleri icin idealdir. ```php // AuthServiceProvider or AppServiceProvider boot() Gate::define('manage-settings', function (User $user): bool { return $user->is_admin; }); Gate::define('update-post', function (User $user, Post $post): bool { return $user->id === $post->user_id; }); // Using gates if (Gate::allows('manage-settings')) { /* ... */ } Gate::authorize('update-post', $post); // Throws 403 if denied ``` ```php // PostPolicy.php class PostPolicy { // Runs before all other checks public function before(User $user, string $ability): ?bool { if ($user->is_super_admin) { return true; // Bypass all checks } return null; // Fall through to specific method } public function view(User $user, Post $post): bool { return $post->published || $user->id === $post->user_id; } public function update(User $user, Post $post): bool { return $user->id === $post->user_id; } public function delete(User $user, Post $post): bool { return $user->id === $post->user_id && $post->comments_count === 0; } } // Using policies in controllers public function update(Request $request, Post $post): RedirectResponse { $this->authorize('update', $post); // Auto-resolves PostPolicy $post->update($request->validated()); return redirect()->route('posts.show', $post); } // In Blade templates @can('update', $post) Edit @endcan ``` Policy'deki `before()` metodu yoneticiler icin tum kontrollerin atlanmasini saglar. `false` yerine `null` dondurmek, standart yetkilendirme mantgina gecisi mumkun kilar. ## Dogrulama ve Formlar ### 15. Laravel'de dogrulama nasil calisir ve ozel kurallar nasil olusturulur? Laravel, onlarca yerlesik kurali iceren kapsamli bir dogrulama sistemi sunar. Form Request'ler dogrulama mantgini controller'lardan ayirir; ozel kurallar ise kendi dogrulayicilarinizi tanimlamenize olanak tanir. ```php // StoreArticleRequest.php - Form Request class StoreArticleRequest extends FormRequest { public function authorize(): bool { return $this->user()->can('create', Article::class); } public function rules(): array { return [ 'title' => ['required', 'string', 'max:255', 'unique:articles'], 'slug' => ['required', 'string', 'regex:/^[a-z0-9-]+$/'], 'body' => ['required', 'string', 'min:100'], 'category_id' => ['required', 'exists:categories,id'], 'tags' => ['array', 'max:5'], 'tags.*' => ['string', 'max:30'], 'publish_at' => ['nullable', 'date', 'after:now'], 'cover_image' => ['nullable', 'image', 'max:2048', 'dimensions:min_width=800'], ]; } public function messages(): array { return [ 'title.unique' => 'An article with this title already exists.', 'body.min' => 'Article content must be at least 100 characters.', ]; } // Transform data before validation protected function prepareForValidation(): void { $this->merge([ 'slug' => Str::slug($this->title), ]); } } ``` ```php // Custom validation rule class StrongPassword implements ValidationRule { public function validate(string $attribute, mixed $value, Closure $fail): void { if (strlen($value) < 12) { $fail('The :attribute must be at least 12 characters.'); } if (!preg_match('/[A-Z]/', $value)) { $fail('The :attribute must contain an uppercase letter.'); } if (!preg_match('/[0-9]/', $value)) { $fail('The :attribute must contain a number.'); } } } // Usage 'password' => ['required', new StrongPassword()], // Conditional validation $request->validate([ 'role' => 'required|in:user,admin', 'admin_code' => 'required_if:role,admin|string', 'company' => Rule::requiredIf($request->role === 'admin'), ]); ``` Form Request'ler profesyonel projelerde tercih edilen yaklasimdir. Dogrulama mantgini controller'dan ayirir ve yetkilendirme mantgi da icerebilir. ## Test ### 16. Laravel'de PHPUnit ve Pest ile test nasil yazilir? Laravel mukemmel bir test altyapisi saglar. Feature test'ler tam HTTP isteklerini dogrular; unit test'ler izole siniflari test eder. Framework, istekler, veritabani, kuyruklar ve daha fazlasi icin yardimci metotlar sunar. ```php // Feature test - tests/Feature/ArticleTest.php class ArticleTest extends TestCase { use RefreshDatabase; public function test_user_can_create_article(): void { $user = User::factory()->create(); $response = $this->actingAs($user) ->post('/articles', [ 'title' => 'Test Article', 'body' => str_repeat('Content ', 20), 'category_id' => Category::factory()->create()->id, ]); $response->assertRedirect(); $this->assertDatabaseHas('articles', [ 'title' => 'Test Article', 'user_id' => $user->id, ]); } public function test_guest_cannot_create_article(): void { $response = $this->post('/articles', [ 'title' => 'Test', ]); $response->assertRedirect('/login'); } } ``` ```php // Same tests with Pest syntax uses(RefreshDatabase::class); it('allows authenticated users to create articles', function () { $user = User::factory()->create(); $response = $this->actingAs($user) ->post('/articles', [ 'title' => 'Test Article', 'body' => str_repeat('Content ', 20), 'category_id' => Category::factory()->create()->id, ]); $response->assertRedirect(); expect(Article::where('title', 'Test Article')->exists())->toBeTrue(); }); it('prevents guests from creating articles', function () { $this->post('/articles', ['title' => 'Test']) ->assertRedirect('/login'); }); // Testing with mocks it('sends welcome email after registration', function () { Mail::fake(); $this->post('/register', [ 'name' => 'John', 'email' => 'john@example.com', 'password' => 'SecurePass123!', ]); Mail::assertSent(WelcomeEmail::class, function ($mail) { return $mail->hasTo('john@example.com'); }); }); ``` `RefreshDatabase` trait'i her testten sonra islemleri geri alarak izolasyon saglar. `actingAs()`, giris yapma gerekliligi olmadan kimlik dogrulamayi simule eder. ### 17. Test'lerde Model Factory'ler ve Seeder'lar nasil calisir? Factory'ler, Faker kutuphanesi ile gercekci test verileri uretir. Seeder'lar veritabanini baslangic verileriyle doldurur; hem test hem de ortam baslatma amaciyla kullanilir. ```php // database/factories/ArticleFactory.php class ArticleFactory extends Factory { protected $model = Article::class; public function definition(): array { return [ 'user_id' => User::factory(), // Auto-creates related user 'category_id' => Category::factory(), 'title' => fake()->sentence(), 'slug' => fake()->slug(), 'body' => fake()->paragraphs(5, true), 'status' => 'draft', 'published_at' => null, ]; } // State methods for variations public function published(): static { return $this->state(fn (array $attributes) => [ 'status' => 'published', 'published_at' => fake()->dateTimeBetween('-1 year'), ]); } public function withComments(int $count = 3): static { return $this->has(Comment::factory()->count($count)); } } ``` ```php // Using factories in tests // Single model $article = Article::factory()->create(); // With specific attributes $article = Article::factory()->published()->create([ 'title' => 'Specific Title', ]); // With relationships $user = User::factory() ->has(Article::factory()->count(5)->published()) ->has(Article::factory()->count(2)) // drafts ->create(); // Complex seeder class DatabaseSeeder extends Seeder { public function run(): void { // Create admin User::factory()->create([ 'email' => 'admin@example.com', 'is_admin' => true, ]); // Create users with articles User::factory(10) ->has(Article::factory()->count(rand(1, 10))->published()) ->create(); $this->call([ CategorySeeder::class, TagSeeder::class, ]); } } ``` Factory'lerdeki state metotlari, model varyantlarini okunabilir ve surdurulbilir bir sekilde olusturmayi saglar. `has()` metodu iliskili modelleri otomatik olusturur. ## Mimari ve Desenler ### 18. Repository deseni nedir ve Laravel'de ne zaman kullanilmalidir? Repository deseni, is mantigi ile veri erisim katmani arasinda bir soyutlama katmani olusturur. Eloquent kendisi Active Record deseninin bir implementasyonu olsa da, test edilebilirlik ve veri kaynagi degistirilebilirligi gerektiren buyuk uygulamalarda Repository eklenmesi gerekcelidir. ```php // Contracts/ArticleRepositoryInterface.php interface ArticleRepositoryInterface { public function findById(int $id): ?Article; public function findPublished(int $perPage = 15): LengthAwarePaginator; public function create(array $data): Article; public function update(int $id, array $data): Article; public function delete(int $id): bool; } // Repositories/EloquentArticleRepository.php class EloquentArticleRepository implements ArticleRepositoryInterface { public function __construct( private readonly Article $model ) {} public function findById(int $id): ?Article { return $this->model ->with(['author', 'category', 'tags']) ->find($id); } public function findPublished(int $perPage = 15): LengthAwarePaginator { return $this->model ->published() ->with(['author', 'category']) ->latest('published_at') ->paginate($perPage); } public function create(array $data): Article { return $this->model->create($data); } public function update(int $id, array $data): Article { $article = $this->model->findOrFail($id); $article->update($data); return $article->fresh(); } public function delete(int $id): bool { return $this->model->findOrFail($id)->delete(); } } ``` ```php // Bind in ServiceProvider $this->app->bind( ArticleRepositoryInterface::class, EloquentArticleRepository::class ); // Use in controller class ArticleController extends Controller { public function __construct( private readonly ArticleRepositoryInterface $articles ) {} public function index(): View { return view('articles.index', [ 'articles' => $this->articles->findPublished(), ]); } } ``` Kucuk projelerde Repository, Eloquent uzerinde gereksiz bir soyutlama olabilir. Buyuk uygulamalarda ise test kolayligi (arayuz mock'lanmasi) ve temiz mimari saglar. ### 19. Laravel'de Action deseni nasil uygulanir? Action deseni, tek bir is islemini tek bir genel metoda sahip ozel bir sinifta izole eder. Bu, kodu daha test edilebilir, yeniden kullanilabilir ve okunabilir kilar; her sinifin tek, net bir sorumlulugu olur. ```php // Actions/CreateArticleAction.php class CreateArticleAction { public function __construct( private readonly ImageUploader $uploader, private readonly SlugGenerator $slugs ) {} public function execute(User $author, array $data): Article { $slug = $this->slugs->generate($data['title']); $coverPath = isset($data['cover_image']) ? $this->uploader->upload($data['cover_image'], 'articles') : null; $article = $author->articles()->create([ 'title' => $data['title'], 'slug' => $slug, 'body' => $data['body'], 'cover_image' => $coverPath, 'category_id' => $data['category_id'], 'status' => $data['publish'] ? 'published' : 'draft', 'published_at' => $data['publish'] ? now() : null, ]); if (!empty($data['tags'])) { $article->tags()->sync($data['tags']); } if ($article->status === 'published') { event(new ArticlePublished($article)); } return $article; } } ``` ```php // Usage in controller class ArticleController extends Controller { public function store( StoreArticleRequest $request, CreateArticleAction $action ): RedirectResponse { $article = $action->execute( $request->user(), $request->validated() ); return redirect()->route('articles.show', $article); } } // Reusable in Artisan commands class ImportArticleCommand extends Command { protected $signature = 'articles:import {file}'; public function handle(CreateArticleAction $action): int { $articles = json_decode( file_get_contents($this->argument('file')), true ); foreach ($articles as $data) { $action->execute($this->getSystemUser(), $data); } return Command::SUCCESS; } } ``` Action'lar ozellikle controller'lar, Artisan komutlari ve kuyruk gorevlerinde paylasilan mantik icin idealdir. Her Action kolayca birim testi yapilabilir. ### 20. Laravel'de Event ve Listener sistemi nasil calisir? Laravel'in olay sistemi Observer desenini uygular. Event'ler uygulamada gerceklesen olaylari temsil eder; Listener'lar bu olaylara tepki verir. Bu yaklasim eylemi sonuclarindan ayirir. ```php // Events/OrderPlaced.php class OrderPlaced { use SerializesModels; public function __construct( public readonly Order $order ) {} } // Listeners/SendOrderConfirmation.php class SendOrderConfirmation implements ShouldQueue { public function handle(OrderPlaced $event): void { Mail::to($event->order->user) ->send(new OrderConfirmationMail($event->order)); } } // Listeners/UpdateInventory.php class UpdateInventory { public function handle(OrderPlaced $event): void { foreach ($event->order->items as $item) { $item->product->decrement('stock', $item->quantity); } } } // Listeners/NotifyWarehouse.php class NotifyWarehouse implements ShouldQueue { public function handle(OrderPlaced $event): void { Http::post('https://warehouse.api/orders', [ 'order_id' => $event->order->id, 'items' => $event->order->items->toArray(), ]); } } ``` ```php // Event registration (EventServiceProvider or auto-discovery) protected $listen = [ OrderPlaced::class => [ SendOrderConfirmation::class, UpdateInventory::class, NotifyWarehouse::class, ], ]; // Dispatching events event(new OrderPlaced($order)); // Or using the static dispatch method OrderPlaced::dispatch($order); // Model observers - events for Eloquent models class OrderObserver { public function created(Order $order): void { event(new OrderPlaced($order)); } public function updated(Order $order): void { if ($order->wasChanged('status')) { event(new OrderStatusChanged($order)); } } } ``` `ShouldQueue` arayuzunu uygulayan Listener'lar otomatik olarak kuyruga alinir ve HTTP yanit surelerinin yavaslmasini onler. Model Observer'lar model yasam dongusu olaylarinin islenisini merkezlestirir. ## Performans ve Optimizasyon ### 21. Laravel'de N+1 sorgu sorunu nasil cozulur? N+1 sorunu, uygulamanin koleksiyon icin bir sorgu, ardindan her eleman icin ayri bir sorgu calistirmasiyla ortaya cikar. `with()` ile eager loading, iliskileri bir veya iki sorguda yukleyerek bu sorunu cozer. ```php // N+1 Problem - 1 query for posts + N queries for authors $posts = Post::all(); foreach ($posts as $post) { echo $post->author->name; // Each access = 1 query } // Result: 1 + N queries (101 queries for 100 posts!) // Solution: Eager Loading $posts = Post::with('author')->get(); // 2 queries total // Nested eager loading $posts = Post::with([ 'author', 'comments.user', // Nested: comments AND their users 'tags', ])->get(); // Conditional eager loading $posts = Post::with(['comments' => function ($query) { $query->where('approved', true) ->latest() ->limit(5); }])->get(); ``` ```php // Prevent N+1 in development // AppServiceProvider boot() public function boot(): void { // Throws exception when lazy loading happens Model::preventLazyLoading(!app()->isProduction()); // Log instead of throwing Model::handleLazyLoadingViolationUsing(function ($model, $relation) { Log::warning("Lazy loading {$relation} on {$model::class}"); }); } // Lazy eager loading - when you already have the collection $posts = Post::all(); $posts->load('author', 'tags'); // Eager load after initial query // withCount for counting without loading $posts = Post::withCount('comments') ->having('comments_count', '>', 10) ->get(); echo $posts[0]->comments_count; // No extra query ``` `Model::preventLazyLoading()` gelistirme ortaminda vazgecilmez bir aractir. N+1 sorununu, uretime gecmeden once gelistirme asamasinda tespit eder. ### 22. Laravel'de onbellekleme nasil calisir ve optimizasyon stratejileri nelerdir? Laravel, birden fazla surucu destegi ile birlesik bir onbellekleme API'si sunar: Redis, Memcached, dosya, veritabani. Onbellekleme stratejisi hem uygulama onbellegini hem de framework'e ozel optimizasyonlari kapsar. ```php // Basic caching operations Cache::put('user:123', $userData, now()->addHours(1)); $user = Cache::get('user:123'); $user = Cache::get('user:123', 'default value'); // Remember pattern - get or compute and store $articles = Cache::remember('popular-articles', 3600, function () { return Article::published() ->withCount('views') ->orderByDesc('views_count') ->limit(10) ->get(); }); // Cache tags for grouped invalidation Cache::tags(['articles', 'homepage'])->put('featured', $articles, 3600); Cache::tags('articles')->flush(); // Clear all article caches // Atomic locks for race condition prevention $lock = Cache::lock('processing-order-'.$orderId, 10); if ($lock->get()) { try { // Process order - guaranteed exclusive access $this->processOrder($orderId); } finally { $lock->release(); } } ``` ```php // Framework optimization commands // Cache configuration files php artisan config:cache // Cache routes php artisan route:cache // Cache views php artisan view:cache // Cache events php artisan event:cache // Optimize all at once php artisan optimize // Database query caching strategy class ArticleService { public function getFeatured(): Collection { return Cache::tags('articles') ->remember('articles:featured', 1800, function () { return Article::published() ->featured() ->with(['author', 'category']) ->latest('published_at') ->limit(6) ->get(); }); } public function clearCache(): void { Cache::tags('articles')->flush(); } } ``` `config:cache` ve `route:cache` komutlari dagitim betiginin parcasi olmalidir. Etiketli onbellek yalnizca etiket destekleyen surucularle (Redis, Memcached) calisir. ## Dagitim ve Uretim ### 23. Bir Laravel uygulamasini uretime dagitma sureci nasil gorunur? Profesyonel Laravel dagitimi, autoloader optimizasyonu, yapilandirma ve rota onbellekleme, asset derleme ve veritabani migrasyonunu icerir. Laravel Forge, Envoyer veya ozel CI/CD pipeline'lari bu sureci otomatiklestirir. ```bash # Production deployment script #!/bin/bash set -e # Pull latest code git pull origin main # Install dependencies (no dev) composer install --no-dev --optimize-autoloader # Run migrations php artisan migrate --force # Clear and rebuild caches php artisan optimize:clear php artisan optimize # Build frontend assets npm ci npm run build # Restart queue workers php artisan queue:restart # Reload PHP-FPM (zero downtime) sudo systemctl reload php8.3-fpm ``` ```php // config/database.php - Production database configuration 'pgsql' => [ 'driver' => 'pgsql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '5432'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', 'search_path' => 'public', // Connection pooling 'pool' => [ 'min' => 2, 'max' => 10, ], ], // Logging configuration for production 'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['daily', 'slack'], ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'warning', // Only warnings+ in production 'days' => 14, ], ], ``` `php artisan migrate` icindeki `--force` flagi uretim ortaminda zorunludur; Laravel varsayilan olarak uretimdeki migrasyonlari engeller. `queue:restart` worker'lara mevcut gorevi tamamladiktan sonra nazikce sonlanmalari sinyalini verir. ### 24. Uretimde kuyruklar nasil yapilandirilir ve izlenir? Uretimdeki dogru kuyruk yapilandirmasi bir surec yonetim araci (Supervisor), hata isletme stratejisi ve izleme gerektirir. Laravel Horizon, Redis kuyruklari icin bir gozetim paneli ve gelismis yapilandirma saglar. ```bash # Supervisor configuration: /etc/supervisor/conf.d/laravel-worker.conf [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/app/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=4 redirect_stderr=true stdout_logfile=/var/www/app/storage/logs/worker.log stopwaitsecs=3600 ``` ```php // config/horizon.php - Laravel Horizon configuration 'environments' => [ 'production' => [ 'supervisor-default' => [ 'maxProcesses' => 10, 'balanceMaxShift' => 1, 'balanceCooldown' => 3, ], 'supervisor-emails' => [ 'connection' => 'redis', 'queue' => ['emails'], 'maxProcesses' => 3, ], 'supervisor-heavy' => [ 'connection' => 'redis', 'queue' => ['audio-processing', 'video-processing'], 'maxProcesses' => 5, 'timeout' => 600, ], ], ], // Failed job handling // config/queue.php 'failed' => [ 'driver' => 'database-uuids', 'database' => 'pgsql', 'table' => 'failed_jobs', ], // Retry failed jobs // php artisan queue:retry all // php artisan queue:retry {uuid} // php artisan queue:flush // Delete all failed ``` Supervisor, ariza durumunda worker'larin otomatik yeniden baslatilmasini garanti eder. Laravel Horizon, Redis kuyruklari icin otomatik dengeleme, metrikler ve yonetim arayuzu ekler. ### 25. Farkli ortamlarda ortam degiskenleri ve yapilandirma nasil yonetilir? Laravel, ortama ozel yapilandirma icin `.env` dosyalarini kullanir. Uretimde yapilandirma onbellekleme, gizli bilgilerin guvenli depolanmasi ve ortamlar arasi dogru ayar ayriminin yapilmasi kritik oneme sahiptir. ```php // .env - Environment-specific values APP_NAME=MyApp APP_ENV=production APP_DEBUG=false APP_URL=https://myapp.com DB_CONNECTION=pgsql DB_HOST=db.internal DB_DATABASE=myapp_prod CACHE_DRIVER=redis QUEUE_CONNECTION=redis SESSION_DRIVER=redis MAIL_MAILER=ses AWS_ACCESS_KEY_ID=your-key AWS_SECRET_ACCESS_KEY=your-secret ``` ```php // Accessing configuration $appName = config('app.name'); $dbHost = config('database.connections.pgsql.host'); // With default fallback $timeout = config('services.api.timeout', 30); // NEVER use env() outside config files! // Bad - breaks with config:cache $key = env('API_KEY'); // Good - always use config() // config/services.php return [ 'payment' => [ 'key' => env('PAYMENT_API_KEY'), 'secret' => env('PAYMENT_API_SECRET'), 'sandbox' => env('PAYMENT_SANDBOX', false), ], ]; // Then use: $key = config('services.payment.key'); // Environment-specific configuration if (app()->isProduction()) { // Production-only logic } // Custom environment detection $environment = match(true) { app()->environment('production') => 'prod', app()->environment('staging') => 'staging', default => 'dev', }; ``` `config:cache` calistirildiktan sonra `env()` fonksiyonu yapilandirma dosyalari disinda `null` dondurur. Bu nedenle `env()` yalnizca `config/` dizinindeki dosyalarda, uygulama kodunda ise her zaman `config()` kullanilmalidir. Yukaridaki 25 sorunun her biri, Laravel'in resmi dokumantasyonu ile daha derin bir analiz gerektirir. Sadece "nasil" degil, ayni zamanda "neden" framework'un belirli mimari kararlar aldigini aciklayabilen adaylar mulakatlarda one cikar. > **Sonraki Adimlar** > > Her soru, Laravel'in resmi dokumantasyonu ile daha derin bir kesfetmeyi hak eder. Mulakatcilar, framework'un inceliklerini bilen ve teknik secimlerini gerekcesini aciklayabilen adaylara deger verir. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/laravel/laravel-php-interview-questions