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.

Laravel ve PHP mulakat sorulari gelistiriciler icin

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.

AppServiceProvider.phpphp
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')
        );
    });
}
OrderController.phpphp
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().

AnalyticsServiceProvider.phpphp
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.

User.phpphp
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.

Post.php - Local Scopesphp
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.

User.php - Attribute Casting and Mutatorsphp
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.

Laravel mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

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.

EnsureUserIsSubscribed.phpphp
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;
    }
}
bootstrap/app.php (Laravel 11+)php
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.

routes/web.phpphp
// 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']);
ArticleController.php - Resource Controllerphp
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.

ProcessPodcastJob.phpphp
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.

RateLimitedJob.phpphp
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
<form method="POST" action="/profile">
    @csrf  {{-- Generates hidden token field --}}
    @method('PUT')
    <input type="text" name="name" value="{{ $user->name }}">
    <button type="submit">Update</button>
</form>

// XSS Protection - Blade auto-escapes
{{ $userInput }}        {{-- Escaped: &lt;script&gt; --}}
{!! $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.

config/auth.phpphp
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
PostPolicy.phpphp
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)
    <a href="{{ route('posts.edit', $post) }}">Edit</a>
@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.

StoreArticleRequest.php - Form Requestphp
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.

Laravel mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

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.

Feature test - tests/Feature/ArticleTest.phpphp
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.

database/factories/ArticleFactory.phpphp
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.

Contracts/ArticleRepositoryInterface.phpphp
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.

Actions/CreateArticleAction.phpphp
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.

Events/OrderPlaced.phpphp
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
config/database.php - Production database configurationphp
'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
config/horizon.php - Laravel Horizon configurationphp
'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.

.env - Environment-specific valuesphp
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.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#laravel
#php
#interview
#eloquent
#technical interview

Paylaş

İlgili makaleler