Skip to content

Chapter 7 of 7

Service Container, Facades, and Cross-Cutting Concerns

Laravel's service container is the backbone of dependency injection. It resolves classes and their dependencies automatically, including all of Laravel's own components. Bind implementations with $this->app->bind(Interface::class, Implementation::class); use singleton() instead of bind() when the same instance should be returned on every resolution. Service providers are the central place to register bindings in register() and configure services in boot(), which runs after all providers register. Facades provide a static-like syntax (Cache::get('key')) on top of container-resolved classes, concise yet still testable. Real-time facades extend this pattern: prefix any class with Facades\ in a use statement and Laravel dynamically generates a facade that resolves the class from the container, letting you swap implementations in tests without code changes.

Validation guards incoming data. Inline rules run via $request->validate(['title' => 'required|max:255']); for reusable logic, generate a Form Request with make:request StorePostRequest, define rules in rules(), and type-hint it in the controller so Laravel resolves and validates it automatically. Common rules include required, string|max:255, email, unique:users,email, confirmed (matches a field_confirmation value), exists:posts,id, and nullable|image|mimes:jpg,png. Custom rules are first-class: make:rule Uppercase generates a class whose validate() method calls $fail(...) on invalid input; apply with 'name' => [new Uppercase]. For custom 404 and 500 pages, drop Blade files at resources/views/errors/{code}.blade.php; for JSON responses, throw abort(response()->json(...), 422) or hook withExceptions() in bootstrap/app.php.

Testing is integrated end-to-end. Feature tests generated with make:test UserTest use HTTP testing helpers like $this->get('/')->assertStatus(200). The RefreshDatabase trait wraps each test in a transaction that rolls back at the end, keeping tests isolated without re-running migrations. Authenticate routes with \(this->actingAs(\)user), or for Sanctum tokens: \(this->actingAs(\)user, 'sanctum'). Mock collaborators with \(this->mock(Service::class, fn (\)m) => $m->shouldReceive(...)); use Bus::fake(), Event::fake(), and Notification::fake() to assert framework interactions without executing them. For HTTP client tests, Http::fake([...]) and Http::assertSent(...) intercept requests; pair with Http::preventStrayRequests() to catch unwired external calls. Format code with Laravel Pint (vendor/bin/pint, with --test to report without fixing) or PHP_CodeSniffer for stricter PSR-12 enforcement.

Cross-cutting concerns cover caching, mail, storage, logging, and configuration. The Cache facade offers Cache::remember($key, $ttl, $cb) for memoized lookups, rememberForever() for indefinite storage, atomic Cache::lock('key', 10)->block(5, $cb) for race-free operations, and Cache::tags(['users'])->flush() for tag-based eviction on supported stores. Mail supports raw messages via Mail::raw or full Mailable classes generated with make:mail that implement envelope(), content(), and attachments(); add ShouldQueue to send asynchronously. Markdown mail renders pre-styled HTML; publish templates with vendor:publish --tag=laravel-mail to customize themes. Storage uses disks (local, public, s3): php artisan storage:link makes the public disk accessible at /storage. File uploads go through $request->file('avatar')->store('avatars', 'public') after validating with image|max:2048; helper methods include getClientOriginalName(), extension(), size(), and isValid(). Laravel's HTTP client (Http::get(...)) supports timeouts, retries, bearer tokens, and throw() for 4xx/5xx handling. Logging routes through configured channels (single, daily, slack, stack) via the Log facade, with contextual arrays such as Log::info('User signed in', ['id' => $u->id]). Always read config via config('app.timezone') and never env() outside config files, because php artisan config:cache causes env() calls elsewhere to return null in production.

All chapters
  1. 1The HTTP Layer: Routing and Middleware
  2. 2Eloquent ORM: Models, Relationships, and Querying
  3. 3Database Migrations, Schema, and Data Seeding
  4. 4Blade Templates, Views, and Pagination
  5. 5Authentication, Authorization, and Sessions
  6. 6Queues, Events, Notifications, and Broadcasting
  7. 7Service Container, Facades, and Cross-Cutting Concerns

Drill it

Reading is not remembering. These come from the Laravel Framework deck:

Q

What is Laravel Eloquent ORM?

Eloquent is Laravel's built-in Active Record ORM. Each database table has a corresponding Model class used to interact with that table. It provides an expressiv...

Q

How do you define a one-to-many relationship in Eloquent?

In the parent model, define a method returning hasMany():public function posts() { return $this->hasMany(Post::class); }In the child model, define the inverse w...

Q

What is eager loading in Eloquent and why is it important?

Eager loading solves the N+1 query problem by loading relationships upfront:$books = Book::with('author')->get();Without it, accessing a relationship in a loop...

Q

How do you create a new Eloquent model and migration together?

Use the Artisan command:php artisan make:model Post -mThe -m flag generates a migration file alongside the model. You can also add -f for a factory and -s for a...