Top 50 Laravel Interview Questions and Answers (Part 2: Eloquent & Advanced)

Published on December 06, 2025
Laravel EloquentORM AdvancedLaravel PHP Database LaravelInterview SeniorDeveloper BackendDevelopment LaravelAdvanced WebDevelopment

Introduction

Welcome to Part 2 of our Laravel Interview Questions series! While Part 1 covered the fundamentals, this guide dives deep into advanced Laravel concepts, with a special focus on Eloquent ORM. These are the questions that separate junior developers from senior ones, and mastering them will prepare you for even the most challenging Laravel interviews.

Section 1: Advanced Eloquent ORM

1. What is Eloquent ORM and how does it differ from Query Builder?

Answer: Eloquent ORM (Object-Relational Mapping) is Laravel's ActiveRecord implementation for database interaction. It provides an elegant, expressive syntax for working with databases using object-oriented models.

Key differences from Query Builder:

// Query Builder (fluent interface)
$users = DB::table('users')
    ->where('active', 1)
    ->orderBy('name')
    ->take(10)
    ->get();

// Eloquent ORM (ActiveRecord pattern)
$users = User::where('active', 1)
    ->orderBy('name')
    ->take(10)
    ->get();

// Eloquent advantages:
// - Model represents table row as object
// - Automatic timestamps, casting, relationships
// - Event observers, accessors/mutators
// - More readable and maintainable

2. Explain Eloquent's "with()" vs "load()" methods

Answer: Both methods enable eager loading, but with different usage patterns:

// with() - Eager load at query time
$users = User::with('posts')->get();
// Single query for users, single query for all related posts

// load() - Lazy eager load after query
$users = User::all();
$users->load('posts');
// Two separate queries

// loadMissing() - Load only if not already loaded
$users = User::all();
$users->loadMissing(['posts', 'profile']);

When to use which:

  • with(): When you know you'll need the relationship upfront
  • load(): When you need to load relationships after the initial query
  • loadMissing(): When conditionally loading relationships

3. What is the N+1 Query Problem and how does Laravel solve it?

Answer: The N+1 problem occurs when fetching related data in a loop, causing many unnecessary database queries:

// PROBLEM: N+1 Queries
$books = Book::all(); // 1 query
foreach ($books as $book) {
    echo $book->author->name; // N queries (1 for each book)
}
// Total: 1 + N queries

// SOLUTION: Eager Loading with with()
$books = Book::with('author')->get(); // 2 queries total
// 1 query for books, 1 query for all related authors

Laravel's solutions:

  • Eager Loading: with(), load()
  • Lazy Eager Loading: load() after initial query
  • Aggregates: withCount(), withSum(), etc.

4. Explain Eloquent Scopes (Local and Global)

Answer: Scopes allow you to define common query constraints:

// Local Scope (must be called explicitly)
class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
    
    public function scopePopular($query, $minFollowers = 1000)
    {
        return $query->where('followers', '>=', $minFollowers);
    }
}

// Usage
$activeUsers = User::active()->get();
$popularUsers = User::popular(5000)->get();

// Global Scope (applies automatically)
class User extends Model
{
    protected static function booted()
    {
        static::addGlobalScope('active', function (Builder $builder) {
            $builder->where('active', 1);
        });
    }
}

// Remove global scope
User::withoutGlobalScope('active')->get();

5. What are Eloquent Accessors, Mutators, and Attribute Casting?

Answer: These features allow you to transform attribute values:

class User extends Model
{
    // ACCESSOR: Transform when getting
    public function getFullNameAttribute()
    {
        return "{$this->first_name} {$this->last_name}";
    }
    // Usage: $user->full_name
    
    // MUTATOR: Transform when setting
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = strtolower($value);
    }
    // Usage: $user->first_name = 'JOHN';
    
    // ATTRIBUTE CASTING: Automatic type conversion
    protected $casts = [
        'is_admin' => 'boolean',
        'settings' => 'array',
        'birthday' => 'date',
        'price' => 'decimal:2',
        'created_at' => 'datetime:Y-m-d',
    ];
    // Usage: automatically casts when accessed
}

6. Explain Polymorphic Relationships in Eloquent

Answer: Polymorphic relationships allow a model to belong to multiple other models on a single association:

// Database tables
// comments
//   id - integer
//   body - text
//   commentable_id - integer
//   commentable_type - string

// posts
//   id - integer
//   title - string

// videos
//   id - integer
//   title - string

// Comment model
class Comment extends Model
{
    public function commentable()
    {
        return $this->morphTo();
    }
}

// Post and Video models
class Post extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

class Video extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

// Usage
$post = Post::find(1);
foreach ($post->comments as $comment) {
    // Access comments
}

$comment = Comment::find(1);
$commentable = $comment->commentable; // Returns Post or Video

7. What are Many-to-Many Polymorphic Relationships?

Answer: Also known as "polymorphic many-to-many", these allow a model to belong to multiple other models through an intermediate table:

// Database tables
// tags
//   id - integer
//   name - string

// taggables
//   tag_id - integer
//   taggable_id - integer
//   taggable_type - string

// Post and Video models
class Post extends Model
{
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

class Video extends Model
{
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

// Tag model
class Tag extends Model
{
    public function posts()
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }
    
    public function videos()
    {
        return $this->morphedByMany(Video::class, 'taggable');
    }
}

8. Explain Eloquent's "has" and "whereHas" methods

Answer: These methods allow you to query based on relationship existence:

// Get users who have at least one post
$users = User::has('posts')->get();

// Get users who have at least 3 posts
$users = User::has('posts', '>=', 3)->get();

// Get users who have posts with specific conditions
$users = User::whereHas('posts', function ($query) {
    $query->where('published', true);
})->get();

// With nested relationships
$users = User::whereHas('posts.comments', function ($query) {
    $query->where('approved', true);
})->get();

// Doesn't have relationship
$users = User::doesntHave('posts')->get();

9. What are Eloquent Events and Observers?

Answer: Events allow you to hook into model lifecycle events:

// Events available
retrieved, creating, created, updating, updated,
saving, saved, deleting, deleted, restoring, restored

// Using closures
User::creating(function ($user) {
    $user->api_token = Str::random(60);
});

// Using Observer class
php artisan make:observer UserObserver --model=User

class UserObserver
{
    public function creating(User $user)
    {
        $user->api_token = Str::random(60);
    }
    
    public function created(User $user)
    {
        // Send welcome email
    }
}

// Register in AppServiceProvider
public function boot()
{
    User::observe(UserObserver::class);
}

10. Explain Eloquent's "touch()" method and timestamps

Answer: The touch() method updates a model's updated_at timestamp:

$user = User::find(1);
$user->touch(); // Updates updated_at to current time

// Touch with specific timestamp
$user->touch('last_login_at');

// Touch parent's timestamp through relationship
$comment = Comment::find(1);
$comment->post->touch(); // Updates post's updated_at

// Automatic touching
class Comment extends Model
{
    protected $touches = ['post'];
    // Whenever comment is updated, post's updated_at is also updated
}

11. What is Eloquent's "replicate()" method?

Answer: The replicate() method creates a new unsaved instance with copied attributes:

$user = User::find(1);
$newUser = $user->replicate();

// Exclude specific attributes
$newUser = $user->replicate()->fill([
    'email' => 'new@example.com',
]);

// Replicate with relationships
$newUser = $user->replicate();
$newUser->push(); // Saves the user

foreach ($user->posts as $post) {
    $newPost = $post->replicate();
    $newPost->user_id = $newUser->id;
    $newPost->save();
}

12. Explain Eloquent's "save()" vs "create()" vs "update()" methods

Answer: Different methods for creating/updating records:

// save() - Save model instance
$user = new User;
$user->name = 'John';
$user->email = 'john@example.com';
$user->save(); // Creates new record

$user = User::find(1);
$user->name = 'Jane';
$user->save(); // Updates existing record

// create() - Create with array (mass assignment)
$user = User::create([
    'name' => 'John',
    'email' => 'john@example.com',
    'password' => bcrypt('password'),
]);

// update() - Update with array
User::where('active', 1)->update(['status' => 'verified']);

// updateOrCreate() - Update or create
$user = User::updateOrCreate(
    ['email' => 'john@example.com'], // Find by these attributes
    ['name' => 'John', 'active' => 1] // Update/create with these
);

13. What is Mass Assignment and how is it secured?

Answer: Mass assignment allows setting multiple attributes at once. Security is handled through fillable/guarded properties:

class User extends Model
{
    // Mass Assignment Protection
    
    // OPTION 1: Fillable (allow list)
    protected $fillable = [
        'name', 'email', 'password'
    ];
    // Only these fields can be mass assigned
    
    // OPTION 2: Guarded (block list)
    protected $guarded = [
        'id', 'is_admin'
    ];
    // All fields except these can be mass assigned
    
    // OPTION 3: Guard all
    protected $guarded = ['*'];
    // No mass assignment allowed
    
    // Force fill (bypass protection)
    $user->forceFill([
        'is_admin' => true
    ])->save();
}

14. Explain Eloquent's "firstOrNew()", "firstOrCreate()", and "firstOr()" methods

Answer: These methods find or create records:

// firstOrNew() - Find or instantiate (not saved)
$user = User::firstOrNew(
    ['email' => 'john@example.com'],
    ['name' => 'John', 'active' => 1]
);
// Returns existing user or new unsaved instance
if (!$user->exists) {
    $user->save();
}

// firstOrCreate() - Find or create and save
$user = User::firstOrCreate(
    ['email' => 'john@example.com'],
    ['name' => 'John', 'active' => 1]
);
// Returns existing user or creates new one

// firstOr() - Find or execute callback
$user = User::where('email', 'john@example.com')
    ->firstOr(function () {
        return User::create([
            'email' => 'john@example.com',
            'name' => 'John',
        ]);
    });

15. What is Eloquent's "withCount()" method?

Answer: withCount() adds a count of related models to the query results:

// Basic usage
$posts = Post::withCount('comments')->get();
foreach ($posts as $post) {
    echo $post->comments_count;
}

// Multiple counts
$posts = Post::withCount(['comments', 'likes'])->get();
// Access: $post->comments_count, $post->likes_count

// With conditions
$posts = Post::withCount([
    'comments',
    'comments as approved_comments_count' => function ($query) {
        $query->where('approved', true);
    }
])->get();

// Order by count
$posts = Post::withCount('comments')
    ->orderBy('comments_count', 'desc')
    ->get();

// Similar methods: withSum(), withAvg(), withMin(), withMax()
$posts = Post::withSum('comments', 'likes')->get();
// Access: $post->comments_sum_likes

Section 2: Database & Migrations Advanced

16. Explain Database Indexes in Laravel Migrations

Answer: Indexes improve query performance. Laravel supports various index types:

// Creating indexes in migrations
Schema::table('users', function (Blueprint $table) {
    // Simple index
    $table->index('email');
    
    // Unique index
    $table->unique('email');
    
    // Composite index
    $table->index(['first_name', 'last_name']);
    
    // Full-text index (MySQL/PostgreSQL)
    $table->fullText('body');
    
    // Spatial index (MySQL/PostgreSQL)
    $table->spatialIndex('location');
    
    // Foreign key with index
    $table->foreign('country_id')
        ->references('id')
        ->on('countries')
        ->onDelete('cascade');
});

// Dropping indexes
$table->dropIndex(['email']);
$table->dropUnique(['email']);

17. What are Database Transactions in Laravel?

Answer: Transactions ensure a set of database operations complete successfully or roll back completely:

// Basic transaction
DB::transaction(function () {
    $user = User::create(['email' => 'john@example.com']);
    $user->orders()->create(['total' => 100]);
    // If any operation fails, all are rolled back
});

// Manual transaction control
DB::beginTransaction();
try {
    $user = User::create(['email' => 'john@example.com']);
    $user->orders()->create(['total' => 100]);
    
    DB::commit();
} catch (\Exception $e) {
    DB::rollBack();
    throw $e;
}

// Transaction levels (for deadlocks)
DB::transaction(function () {
    // Nested transactions are converted to savepoints
}, 5); // 5 retries on deadlock

// Eloquent model transactions
User::createOrFail(['email' => 'john@example.com']);
// Automatically rolls back on failure

18. Explain Database Seeding with Relationships

Answer: Advanced seeding with related models:

// DatabaseSeeder.php
public function run()
{
    // Create 10 users
    $users = User::factory(10)->create();
    
    // Each user has 5 posts
    $users->each(function ($user) {
        $posts = Post::factory(5)->create([
            'user_id' => $user->id
        ]);
        
        // Each post has 3 comments
        $posts->each(function ($post) use ($user) {
            Comment::factory(3)->create([
                'post_id' => $post->id,
                'user_id' => $user->id
            ]);
        });
    });
}

// Using states in factories
User::factory()
    ->count(5)
    ->has(
        Post::factory()
            ->count(3)
            ->has(
                Comment::factory()->count(2)
            )
    )
    ->create();

19. What are Database Raw Expressions in Laravel?

Answer: Raw expressions allow executing raw SQL within Laravel's query builder:

// Raw select
$users = DB::table('users')
    ->select(DB::raw('count(*) as user_count, status'))
    ->where('status', '<>', 1)
    ->groupBy('status')
    ->get();

// Raw where
$users = DB::table('users')
    ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
    ->get();

// Raw joins
$orders = DB::table('orders')
    ->select('orders.*', DB::raw('SUM(items.price) as total'))
    ->join('items', 'orders.id', '=', 'items.order_id')
    ->groupBy('orders.id')
    ->get();

// Order by raw
$users = User::orderByRaw('updated_at - created_at DESC')->get();

// Raw insert
DB::insert('insert into users (id, name) values (?, ?)', [1, 'John']);

// WARNING: Always use parameter binding to prevent SQL injection
// DON'T: DB::raw("WHERE name = '$name'")
// DO: DB::raw("WHERE name = ?", [$name])

20. Explain Database Query Caching in Laravel

Answer: Laravel provides query result caching:

// Basic caching
$users = Cache::remember('users', $seconds = 3600, function () {
    return DB::table('users')->get();
});

// Eloquent caching
$users = User::remember($seconds)->get();

// Cache with tags
$users = Cache::tags(['users', 'active'])
    ->remember('active_users', $seconds, function () {
        return User::active()->get();
    });

// Automatic cache clearing on model events
class User extends Model
{
    protected static function booted()
    {
        static::saved(function () {
            Cache::tags(['users'])->flush();
        });
        
        static::deleted(function () {
            Cache::tags(['users'])->flush();
        });
    }
}

// Cache locking (prevent cache stampede)
$value = Cache::lock('foo')->get(function () {
    return DB::table('users')->get();
});

Section 3: Advanced Routing & Middleware

21. What are Route Model Binding Customizations?

Answer: Customize how route parameters are resolved to models:

// Implicit binding with key
Route::get('/api/posts/{post:slug}', function (Post $post) {
    return $post;
});

// Multiple parameters
Route::get('/api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

// Custom resolution logic
// In RouteServiceProvider
public function boot()
{
    parent::boot();
    
    // Custom binding
    Route::bind('post', function ($value) {
        return Post::where('slug', $value)
            ->orWhere('id', $value)
            ->firstOrFail();
    });
    
    // Model binding with scope
    Route::model('post', Post::class, function () {
        return Post::published();
    });
}

// Scoped binding
Route::bind('post', function ($value, $route) {
    return $route->user->posts()
        ->where('slug', $value)
        ->firstOrFail();
});

22. Explain Rate Limiting in Laravel

Answer: Rate limiting controls request frequency:

// In routes/web.php or routes/api.php
Route::middleware(['throttle:api'])->group(function () {
    Route::get('/user', function () {
        // ...
    });
});

// Custom rate limiting
// In App\Providers\RouteServiceProvider
protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
    
    RateLimiter::for('uploads', function (Request $request) {
        return $request->user()->vipCustomer()
            ? Limit::none()
            : Limit::perMinute(10)->by($request->ip());
    });
    
    // Dynamic limits
    RateLimiter::for('global', function (Request $request) {
        return [
            Limit::perMinute(1000),
            Limit::perMinute(100)->by($request->ip()),
            Limit::perMinute(50)->by($request->user()?->id),
        ];
    });
}

// Using in routes
Route::middleware(['throttle:uploads'])->post('/photo', function () {
    // ...
});

23. What are Signed Routes in Laravel?

Answer: Signed routes create URLs with a signature to prevent URL tampering:

// Creating signed routes
Route::get('/unsubscribe/{user}', function (Request $request, User $user) {
    if (!$request->hasValidSignature()) {
        abort(403);
    }
    // Unsubscribe logic
})->name('unsubscribe');

// Generate signed URL
$url = URL::signedRoute('unsubscribe', ['user' => 1]);
// Result: /unsubscribe/1?signature=...

// Temporary signed URL (expires)
$url = URL::temporarySignedRoute(
    'unsubscribe', 
    now()->addMinutes(30), 
    ['user' => 1]
);

// In middleware
Route::get('/unsubscribe/{user}', function (User $user) {
    // Automatically validated by middleware
})->middleware('signed');

// Validate in controller
public function unsubscribe(Request $request, User $user)
{
    if (!$request->hasValidSignature()) {
        abort(403);
    }
    // ...
}

24. Explain Route Caching and its Benefits

Answer: Route caching compiles all routes into a single file for performance:

# Generate route cache
php artisan route:cache

# Clear route cache
php artisan route:clear

# List routes (shows cached routes)
php artisan route:list

Benefits:

  • Faster route registration (up to 5x faster)
  • Reduced memory usage
  • Better performance in production

Limitations:

  • Cannot use closure-based routes (must use controllers)
  • Must clear cache after route changes
  • Some dynamic route features may not work
// BAD: Cannot cache
Route::get('/user', function () {
    return view('user');
});

// GOOD: Can cache
Route::get('/user', [UserController::class, 'index']);

25. What are Macroable Traits in Laravel?

Answer: Macroable traits allow adding methods to classes at runtime:

// Adding macros to existing classes
Route::macro('admin', function () {
    return Route::prefix('admin')
        ->middleware(['auth', 'admin'])
        ->group(function () {
            // Admin routes
        });
});

// Usage
Route::admin()->group(function () {
    Route::get('/dashboard', 'AdminController@dashboard');
});

// Macro with parameters
Response::macro('caps', function ($value) {
    return Response::make(strtoupper($value));
});

// Usage
return response()->caps('hello'); // Returns "HELLO"

// Macroable classes in Laravel:
// - Illuminate\Support\Collection
// - Illuminate\Support\Str
// - Illuminate\Http\Request
// - Illuminate\Routing\ResponseFactory
// - Illuminate\Routing\Route

Section 4: Advanced Service Container & Service Providers

26. Explain Contextual Binding in Service Container

Answer: Contextual binding allows different implementations based on usage context:

// In AppServiceProvider
$this->app->when(PhotoController::class)
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('photos');
    });

$this->app->when(VideoController::class)
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('videos');
    });

// With parameters
$this->app->when(ReportGenerator::class)
    ->needs('$timezone')
    ->give(config('app.timezone'));

// Tagging
$this->app->tag([PhotoFilter::class, VideoFilter::class], 'filters');

$this->app->when(ImageProcessor::class)
    ->needs('$filters')
    ->giveTagged('filters');

// Primitive binding
$this->app->when(OrderService::class)
    ->needs('$retryAttempts')
    ->give(3);

27. What are Service Provider Deferral and When to Use It?

Answer: Deferred providers only load when their services are actually needed:

class MyServiceProvider extends ServiceProvider
{
    // Register as deferred
    protected $defer = true;
    
    // Register services
    public function register()
    {
        $this->app->singleton(MyService::class, function ($app) {
            return new MyService($app['config']);
        });
    }
    
    // Define which services this provider registers
    public function provides()
    {
        return [MyService::class];
    }
}

// Benefits:
// - Faster application boot time
// - Reduced memory usage
// - Only loaded when service is requested

// When to use:
// - For services not used on every request
// - Heavy services with slow initialization
// - Optional features that might not be used

28. Explain Method Injection vs Constructor Injection

Answer: Two patterns for dependency injection in Laravel:

// CONSTRUCTOR INJECTION (Recommended)
class OrderController extends Controller
{
    protected $orderService;
    
    public function __construct(OrderService $orderService)
    {
        $this->orderService = $orderService;
    }
    
    public function show($id)
    {
        return $this->orderService->find($id);
    }
}

// METHOD INJECTION
class OrderController extends Controller
{
    public function show(OrderService $orderService, $id)
    {
        // Service is injected into method
        return $orderService->find($id);
    }
}

// When to use each:
// Constructor Injection:
// - When dependency is used in multiple methods
// - For required dependencies
// - Better for testing

// Method Injection:
// - When dependency is only used in one method
// - For optional dependencies
// - When you want to keep constructor clean

29. What are Container Events in Laravel?

Answer: Container events allow you to hook into service resolution:

// Listening for service resolution
$this->app->resolving(function ($object, $app) {
    // Called when any service is resolved
});

$this->app->resolving(Logger::class, function ($logger, $app) {
    // Called only when Logger is resolved
    $logger->setTimezone($app['config']['app.timezone']);
});

// After resolving event
$this->app->afterResolving(function ($object, $app) {
    // Called after service is resolved
});

// Practical example
$this->app->resolving(Service::class, function ($service, $app) {
    if ($app->environment('local')) {
        $service->enableDebug();
    }
});

// In middleware or controllers
app()->resolving(function ($object) {
    if (method_exists($object, 'initialize')) {
        $object->initialize();
    }
});

30. Explain Service Container's "extend()" Method

Answer: The extend() method allows modifying resolved services:

// Extending a singleton
$this->app->extend(Logger::class, function ($logger, $app) {
    // Add custom handler to existing logger
    $logger->pushHandler(new CustomHandler());
    return $logger;
});

// Extending a binding
$this->app->extend('cache', function ($cache, $app) {
    // Wrap cache with custom decorator
    return new CacheDecorator($cache);
});

// Practical example: Adding headers to mailer
$this->app->extend('mail.manager', function ($mailManager, $app) {
    $mailManager->alwaysFrom('noreply@example.com', 'Example App');
    $mailManager->alwaysReplyTo('support@example.com');
    return $mailManager;
});

// Extending with interface
$this->app->extend(RepositoryInterface::class, function ($repository, $app) {
    return new CachedRepository($repository, $app['cache.store']);
});

Section 5: Advanced Testing Concepts

31. What is Database Transactions in Testing?

Answer: Using transactions to isolate tests and keep database clean:

use Illuminate\Foundation\Testing\RefreshDatabase;

class ExampleTest extends TestCase
{
    use RefreshDatabase;
    
    public function test_basic_example()
    {
        // Test runs in transaction
        $user = User::factory()->create();
        
        // After test, transaction is rolled back
        // Database returns to original state
    }
}

// Without RefreshDatabase trait
public function setUp(): void
{
    parent::setUp();
    $this->beginDatabaseTransaction();
}

public function tearDown(): void
{
    $this->rollbackDatabaseTransaction();
    parent::tearDown();
}

// Testing with multiple connections
DB::connection('test')->beginTransaction();
// Test code
DB::connection('test')->rollBack();

32. Explain Mocking and Stubbing in Laravel Tests

Answer: Mocking replaces real objects with test doubles:

// Mocking with Mockery
$mock = Mockery::mock(Service::class);
$mock->shouldReceive('process')
    ->once()
    ->with(['data'])
    ->andReturn('result');

// Laravel's helper methods
$mock = $this->mock(Service::class, function ($mock) {
    $mock->shouldReceive('process')
        ->once()
        ->andReturn('mocked result');
});

// Partial mocks
$mock = $this->partialMock(Service::class, function ($mock) {
    $mock->shouldReceive('process')
        ->andReturn('mocked');
    // Other methods use real implementation
});

// Stubbing (simpler than mocking)
$stub = $this->createStub(Service::class);
$stub->method('process')
    ->willReturn('stubbed result');

// Mocking facades
Cache::shouldReceive('get')
    ->with('key')
    ->once()
    ->andReturn('value');

// Spying (verify calls without affecting behavior)
$spy = $this->spy(Service::class);
// Run code
$spy->shouldHaveReceived('process')
    ->with(['data'])
    ->once();

33. What are Custom Test Assertions?

Answer: Creating custom assertions for cleaner tests:

// Custom assertion class
class CustomAssertions
{
    public function assertUserIsActive($user, $message = '')
    {
        Assert::assertTrue(
            $user->isActive(),
            $message ?: "The user [{$user->id}] is not active."
        );
    }
    
    public function assertResponseContainsJson($response, $data)
    {
        $response->assertJson($data);
    }
}

// Using in tests
public function test_user_status()
{
    $user = User::factory()->create(['active' => true]);
    $this->assertUserIsActive($user);
}

// Macros for TestResponse
TestResponse::macro('assertHasPaginatedData', function ($key) {
    $this->assertJsonStructure([
        'data' => [$key],
        'links',
        'meta',
    ]);
    
    return $this;
});

// Usage
$response->assertHasPaginatedData('users');

34. Explain Testing Database Factories States

Answer: States allow creating model instances with specific attributes:

// Defining states
class UserFactory extends Factory
{
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'active' => true,
        ];
    }
    
    public function inactive()
    {
        return $this->state(function (array $attributes) {
            return [
                'active' => false,
            ];
        });
    }
    
    public function admin()
    {
        return $this->state([
            'is_admin' => true,
        ]);
    }
    
    public function withSubscription()
    {
        return $this->afterCreating(function (User $user) {
            $user->subscription()->create([
                'plan' => 'premium',
                'ends_at' => now()->addYear(),
            ]);
        });
    }
}

// Using states
$inactiveUser = User::factory()->inactive()->create();
$adminUser = User::factory()->admin()->create();
$subscribedUser = User::factory()->withSubscription()->create();

// Multiple states
$user = User::factory()
    ->inactive()
    ->admin()
    ->create();

// State with parameters
public function withBalance($amount)
{
    return $this->state([
        'balance' => $amount,
    ]);
}

35. What is Testing with "withoutMiddleware()" and "withoutExceptionHandling()"?

Answer: Methods to bypass middleware and exception handling in tests:

// Without middleware
public function test_api_endpoint()
{
    $this->withoutMiddleware();
    
    // Test API endpoint without auth middleware
    $response = $this->get('/api/users');
    $response->assertOk();
}

// Without specific middleware
$this->withoutMiddleware([
    VerifyCsrfToken::class,
    Authenticate::class,
]);

// Without exception handling
public function test_validation_error()
{
    $this->withoutExceptionHandling();
    
    // Exception will be thrown instead of caught
    $response = $this->post('/users', []);
    // Will see actual validation exception
}

// Without event handling
$this->withoutEvents();

// Without job dispatching
$this->withoutJobs();

// Without notification sending
$this->withoutNotifications();

Section 6: Advanced Queue & Job Processing

36. Explain Job Chains vs Job Batching

Answer: Two patterns for organizing related jobs:

// JOB CHAINS (Sequential execution)
ProcessPodcast::withChain([
    new OptimizePodcast,
    new ReleasePodcast,
])->dispatch();

// With delay between jobs
ProcessPodcast::withChain([
    (new OptimizePodcast)->delay(now()->addMinutes(10)),
    new ReleasePodcast,
])->dispatch();

// JOB BATCHES (Parallel execution, with callbacks)
$batch = Bus::batch([
    new ProcessPodcast(1),
    new ProcessPodcast(2),
    new ProcessPodcast(3),
])->then(function (Batch $batch) {
    // All jobs completed successfully
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected
})->finally(function (Batch $batch) {
    // The batch has finished executing
})->dispatch();

// Batch progress
Route::get('/batch/{batchId}', function (string $batchId) {
    return Bus::findBatch($batchId);
});

// Differences:
// Chains: Sequential, one job after another
// Batches: Parallel, with progress tracking and callbacks

37. What are Job Middleware in Laravel?

Answer: Job middleware allows you to wrap job execution with custom logic:

// Creating job middleware
php artisan make:middleware RateLimited

class RateLimited
{
    public function handle($job, $next)
    {
        Redis::throttle('key')
            ->block(0)->allow(1)->every(5)
            ->then(function () use ($job, $next) {
                // Lock obtained...
                $next($job);
            }, function () use ($job) {
                // Could not obtain lock...
                $job->release(5);
            });
    }
}

// Using middleware in jobs
class ProcessPodcast implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
    public function middleware()
    {
        return [new RateLimited];
    }
}

// Multiple middleware
public function middleware()
{
    return [
        new RateLimited,
        new WithoutOverlapping,
    ];
}

// Global job middleware
// In AppServiceProvider
protected $middleware = [
    \Illuminate\Queue\Middleware\RateLimited::class,
];

// Using WithoutOverlapping middleware
(new ProcessPodcast)->through([
    new WithoutOverlapping('podcast-processing'),
])->dispatch();

38. Explain Failed Jobs and Job Retries

Answer: Handling failed jobs with retry logic:

// Configuring retries
class ProcessPodcast implements ShouldQueue
{
    public $tries = 3; // Max attempts
    
    public $maxExceptions = 3; // Max exceptions
    
    public $timeout = 120; // Seconds
    
    public $backoff = 60; // Seconds between retries
    
    // Dynamic backoff
    public function backoff()
    {
        return [1, 5, 10, 30]; // Exponential backoff
    }
    
    // Retry until
    public function retryUntil()
    {
        return now()->addMinutes(10);
    }
    
    // Handle failure
    public function failed(Throwable $exception)
    {
        // Send notification, log, etc.
    }
}

// Manual retry
$failedJob = DB::table('failed_jobs')->find(1);
(new ProcessPodcast)->dispatch();
DB::table('failed_jobs')->where('id', 1)->delete();

// Automatic retry of all failed jobs
php artisan queue:retry all

// Pruning failed jobs
php artisan queue:prune-failed --hours=48

39. What are Horizon Dashboards and Metrics?

Answer: Laravel Horizon provides a dashboard and metrics for Redis queues:

// Configuring Horizon
// config/horizon.php
'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['default'],
            'balance' => 'auto',
            'processes' => 10,
            'tries' => 3,
            'timeout' => 60,
        ],
    ],
],

// Metrics collection
Horizon::routeMailNotificationsTo('admin@example.com');
Horizon::routeSlackNotificationsTo('slack-webhook-url');

// Custom metrics
Horizon::metrics(function () {
    return [
        'jobs_per_minute' => Redis::get('jobs_per_minute'),
        'pending_jobs' => Redis::llen('queues:default'),
    ];
});

// Dashboard authorization
Horizon::auth(function ($request) {
    return $request->user()->isAdmin();
});

// Snapshot scheduling
// In App\Console\Kernel
protected function schedule(Schedule $schedule)
{
    $schedule->command('horizon:snapshot')->everyFiveMinutes();
}

40. Explain Queue Workers and Supervisor Configuration

Answer: Running queue workers in production:

# Basic worker
php artisan queue:work

# With options
php artisan queue:work --queue=high,default --tries=3 --timeout=90

# Daemon mode (for production)
php artisan queue:work --daemon

# Supervisor configuration
# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/your-app/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/your-app/worker.log
stopwaitsecs=3600

# Multiple queues with different workers
[program:laravel-worker-high]
command=php /var/www/your-app/artisan queue:work --queue=high --tries=3

[program:laravel-worker-default]
command=php /var/www/your-app/artisan queue:work --queue=default --tries=1

Section 7: Advanced Security & Performance

41. Explain CSRF Protection for APIs

Answer: CSRF protection for stateless APIs:

// Excluding API routes from CSRF
// In App\Http\Middleware\VerifyCsrfToken
protected $except = [
    'api/*',
    'stripe/*',
];

// Using API tokens
// In User model
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
}

// Creating tokens
$token = $user->createToken('api-token', ['server:update']);

// API authentication
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

// Using Passport (OAuth2)
php artisan passport:install

// Protecting routes
Route::get('/user', function () {
    // Only accessible with valid token
})->middleware('auth:api');

// Rate limiting APIs
Route::middleware(['throttle:api'])->group(function () {
    Route::get('/user', function () {
        // ...
    });
});

42. What is XSS Protection in Laravel?

Answer: Cross-Site Scripting protection in Blade templates:

// Automatic escaping in Blade
{{ $userInput }} // Escaped automatically

// Raw output (use with caution)
{!! $htmlContent !!}

// Clean user input
use Illuminate\Support\Str;

$clean = Str::of($dirty)
    ->stripTags()
    ->limit(255);

// In validation
$request->validate([
    'content' => 'required|string|max:5000',
]);

// Content Security Policy
// In middleware
class AddSecurityHeaders
{
    public function handle($request, $next)
    {
        $response = $next($request);
        
        $response->headers->set('X-XSS-Protection', '1; mode=block');
        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
        $response->headers->set(
            'Content-Security-Policy',
            "default-src 'self'; script-src 'self' 'unsafe-inline'"
        );
        
        return $response;
    }
}

// Sanitizing HTML with package
composer require mews/purifier

43. Explain Laravel's Encryption vs Hashing

Answer: Two different security mechanisms:

// ENCRYPTION (Two-way, with app key)
use Illuminate\Support\Facades\Crypt;

// Encrypt
$encrypted = Crypt::encryptString('secret');
// Can be decrypted back to original

// Decrypt
$decrypted = Crypt::decryptString($encrypted);

// HASHING (One-way, for passwords)
use Illuminate\Support\Facades\Hash;

// Hash password
$hashed = Hash::make('password');
// Cannot be reversed

// Verify hash
if (Hash::check('password', $hashed)) {
    // Password matches
}

// Rehashing (when algorithm improves)
if (Hash::needsRehash($hashed)) {
    $newHashed = Hash::make('password');
}

// When to use:
// Encryption: Sensitive data that needs retrieval
// Hashing: Passwords, never need to retrieve original

44. What is Query Caching with Redis/Memcached?

Answer: Caching database queries for performance:

// Basic query caching
$users = Cache::remember('users', $seconds = 3600, function () {
    return DB::table('users')->get();
});

// Automatic model caching (with package)
composer require rennokki/laravel-eloquent-query-cache

// Using in models
class User extends Model
{
    use QueryCacheable;
    
    public $cacheFor = 3600; // Cache for 1 hour
    
    protected static $flushCacheOnUpdate = true;
}

// Cache tags (Redis/Memcached only)
$users = Cache::tags(['users', 'active'])
    ->remember('active_users', 3600, function () {
        return User::active()->get();
    });

// Clear tagged cache
Cache::tags(['users'])->flush();

// Cache locking (prevent cache stampede)
$value = Cache::lock('key', 10)->get(function () {
    return DB::table('users')->get();
});

45. Explain Laravel's Eager Loading Optimization

Answer: Advanced eager loading techniques:

// Nested eager loading
$books = Book::with('author.country')->get();

// Constraining eager loads
$users = User::with(['posts' => function ($query) {
    $query->where('published', true);
}])->get();

// Lazy eager loading with constraints
$users = User::all();
$users->load(['posts' => function ($query) {
    $query->orderBy('created_at', 'desc');
}]);

// Multiple relationships with constraints
$users = User::with([
    'posts' => function ($query) {
        $query->where('published', true);
    },
    'posts.comments' => function ($query) {
        $query->where('approved', true);
    }
])->get();

// Eager load counts with constraints
$users = User::withCount([
    'posts',
    'posts as published_posts_count' => function ($query) {
        $query->where('published', true);
    }
])->get();

// Avoiding N+1 with subqueries
$users = User::addSelect(['last_post_date' => Post::select('created_at')
    ->whereColumn('user_id', 'users.id')
    ->latest()
    ->limit(1)
])->get();

Section 8: Advanced Package Development

46. What are Package Service Providers?

Answer: Service providers for Laravel packages:

// Creating a package service provider
php artisan make:provider PackageServiceProvider

// Basic structure
class PackageServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Register bindings
        $this->app->singleton(PackageClass::class, function () {
            return new PackageClass(config('package.key'));
        });
    }
    
    public function boot()
    {
        // Load routes
        $this->loadRoutesFrom(__DIR__.'/routes/web.php');
        
        // Load views
        $this->loadViewsFrom(__DIR__.'/views', 'package');
        
        // Load migrations
        $this->loadMigrationsFrom(__DIR__.'/database/migrations');
        
        // Load translations
        $this->loadTranslationsFrom(__DIR__.'/lang', 'package');
        
        // Publish assets
        $this->publishes([
            __DIR__.'/config/package.php' => config_path('package.php'),
        ], 'package-config');
    }
}

// Deferred provider for performance
protected $defer = true;

public function provides()
{
    return [PackageClass::class];
}

47. Explain Package Auto-Discovery

Answer: Automatic package registration without manual service provider addition:

// In package's composer.json
{
    "extra": {
        "laravel": {
            "providers": [
                "Vendor\\Package\\PackageServiceProvider"
            ],
            "aliases": {
                "Package": "Vendor\\Package\\Facades\\Package"
            }
        }
    }
}

// Disabling auto-discovery
// In application's composer.json
{
    "extra": {
        "laravel": {
            "dont-discover": [
                "barryvdh/laravel-debugbar"
            ]
        }
    }
}

// Manual discovery commands
php artisan package:discover
php artisan package:discover --ansi

// Conditional service providers
class PackageServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Only register if condition is met
        if ($this->app->environment('local')) {
            $this->app->register(LocalServiceProvider::class);
        }
    }
}

48. What are Package Facades and How to Create Them?

Answer: Creating facades for packages:

// Facade class
namespace Vendor\Package\Facades;

use Illuminate\Support\Facades\Facade;

class Package extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'package';
    }
}

// Service binding
$this->app->singleton('package', function ($app) {
    return new PackageManager($app['config']);
});

// Usage in package
Package::method();

// Testing facade
Package::shouldReceive('method')
    ->once()
    ->with('argument')
    ->andReturn('result');

// Macroable facade
Package::macro('customMethod', function ($value) {
    return $this->getFacadeRoot()->method($value);
});

// Facade root access
$instance = Package::getFacadeRoot();

49. Explain Package Configuration Publishing

Answer: Publishing package configuration files:

// In service provider boot method
public function boot()
{
    // Publish single config file
    $this->publishes([
        __DIR__.'/../config/package.php' => config_path('package.php'),
    ], 'config');
    
    // Publish multiple files
    $this->publishes([
        __DIR__.'/../config/package.php' => config_path('package.php'),
        __DIR__.'/../config/another.php' => config_path('another.php'),
    ], 'package-config');
    
    // Publish assets
    $this->publishes([
        __DIR__.'/../assets' => public_path('vendor/package'),
    ], 'public');
    
    // Publish views
    $this->publishes([
        __DIR__.'/../resources/views' => resource_path('views/vendor/package'),
    ], 'views');
    
    // Publish migrations
    $this->publishes([
        __DIR__.'/../database/migrations' => database_path('migrations'),
    ], 'migrations');
}

// Publishing commands
php artisan vendor:publish --tag=config
php artisan vendor:publish --provider="Vendor\Package\PackageServiceProvider"
php artisan vendor:publish --all

// Conditional publishing
if ($this->app->runningInConsole()) {
    $this->publishes([
        // ...
    ], 'config');
}

50. What are Package Routes and Views?

Answer: Including routes and views in packages:

// Package routes
// In service provider
public function boot()
{
    $this->loadRoutesFrom(__DIR__.'/routes/web.php');
}

// routes/web.php in package
Route::group([
    'prefix' => 'package',
    'middleware' => ['web'],
    'namespace' => 'Vendor\Package\Http\Controllers',
], function () {
    Route::get('/dashboard', 'DashboardController@index');
});

// Package views
// In service provider
public function boot()
{
    $this->loadViewsFrom(__DIR__.'/resources/views', 'package');
}

// Using package views
return view('package::dashboard', ['data' => $data]);

// Overriding package views
// Create in application: resources/views/vendor/package/dashboard.blade.php

// Publishing views
$this->publishes([
    __DIR__.'/../resources/views' => resource_path('views/vendor/package'),
], 'views');

// View composers for package views
View::composer('package::dashboard', function ($view) {
    $view->with('count', 100);
});

Conclusion

Mastering these advanced Laravel concepts demonstrates deep understanding of the framework and prepares you for senior-level positions. Remember that while knowing the answers is important, understanding the underlying principles and when to apply each concept is what truly sets expert developers apart.

Key Takeaways from Part 2:

  • Eloquent ORM is incredibly powerful with relationships, scopes, and advanced query techniques
  • Database optimization requires understanding indexes, transactions, and query caching
  • Advanced routing features like rate limiting and signed URLs enhance security
  • Service container mastery enables clean, testable architecture
  • Proper testing strategies include mocking, factories, and database isolation
  • Queue management is essential for scalable applications
  • Security must be considered at multiple levels: input, output, and communication
  • Package development skills allow you to contribute to the Laravel ecosystem

Practice Recommendation:

  • Implement each concept in a test project
  • Study Laravel's source code for deeper understanding
  • Contribute to open-source Laravel packages
  • Follow Laravel News and official documentation updates
  • Join Laravel communities to discuss advanced topics