🧳 Real-life Use Case: Travel Booking Service
Let’s say we’re building an API where users can book a tour. Instead of putting everything in the controller, we’ll:
- Create a BookingServicefor booking logic.
- Define a BookingServiceInterface.
- Bind it using a Service Provider.
- Use a Form Request class to handle validation.
- Inject the service into a controller for actual usage.
1. Create the Interface
php artisan make:interface Services/BookingServiceInterface
app/Services/BookingServiceInterface.php:
<?php
namespace App\Services;
interface BookingServiceInterface
{
    public function createBooking(array $data);
}
2. Create the Service Class
php artisan make:service Services/BookingService
app/Services/BookingService.php:
<?php
namespace App\Services;
use App\Models\Booking;
class BookingService implements BookingServiceInterface
{
    public function createBooking(array $data)
    {
        return Booking::create([
            'user_id' => $data['user_id'],
            'tour_id' => $data['tour_id'],
            'date'    => $data['date'],
            'people'  => $data['people'],
        ]);
    }
}
3. Create a Custom Form Request for Validation
php artisan make:request StoreBookingRequest
app/Http/Requests/StoreBookingRequest.php:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreBookingRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }
    public function rules(): array
    {
        return [
            'user_id' => 'required|integer',
            'tour_id' => 'required|integer',
            'date'    => 'required|date',
            'people'  => 'required|integer|min:1',
        ];
    }
}
✅ Now all validation logic is separated and reusable!
4. Create a Service Provider
php artisan make:provider BookingServiceProvider
app/Providers/BookingServiceProvider.php:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\BookingService;
use App\Services\BookingServiceInterface;
class BookingServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(BookingServiceInterface::class, BookingService::class);
    }
    public function boot()
    {
        //
    }
}
Then register this provider in config/app.php:
App\Providers\BookingServiceProvider::class,
5. Use the Service in a Controller
php artisan make:controller BookingController
app/Http/Controllers/BookingController.php:
<?php
namespace App\Http\Controllers;
use App\Services\BookingServiceInterface;
use App\Http\Requests\StoreBookingRequest;
class BookingController extends Controller
{
    protected $bookingService;
    public function __construct(BookingServiceInterface $bookingService)
    {
        $this->bookingService = $bookingService;
    }
    public function store(StoreBookingRequest $request)
    {
        $booking = $this->bookingService->createBooking($request->validated());
        return response()->json([
            'message' => 'Booking created successfully!',
            'data' => $booking,
        ]);
    }
}
Now the controller is super clean — all it does is call the service with validated data.
✅ Why This Pattern Works in the Real World
- Separation of Concerns: Controllers don’t care about validation or logic.
- 
Testable: Easily mock BookingServiceInterfacein tests.
- Reusable: Same service can be used elsewhere — even in commands or jobs.
- 
Maintainable: Validation logic is centralized in StoreBookingRequest.
🧪 Bonus: Mocking the Service in a Test
public function test_booking_creation()
{
    $mock = \Mockery::mock(BookingServiceInterface::class);
    $mock->shouldReceive('createBooking')->once()->andReturn(['id' => 1]);
    $this->app->instance(BookingServiceInterface::class, $mock);
    $response = $this->postJson('/api/bookings', [
        'user_id' => 1,
        'tour_id' => 2,
        'date'    => '2025-06-01',
        'people'  => 2,
    ]);
    $response->assertStatus(200);
}
🧵 Wrapping Up
This is how you build Laravel applications that scale without becoming messy.
 
 
              
 
    
Top comments (0)