Laravel Model Service Generator: Streamline Your Service Layer Architecture

Laravel’s make:model command is a developer’s best friend, instantly scaffolding models alongside migrations, controllers, and factories. But if you follow the service layer pattern – separating business logic from controllers – you’ve likely found yourself manually creating service classes after every make:model command.

The laravel-model-service package eliminates this repetitive task by extending Laravel’s model generator to automatically create service classes with a single flag.

What Is Laravel Model Service?

Laravel Model Service is a developer productivity package that augments the built-in make:model Artisan command. It adds a new -S (or --service) flag that generates a corresponding service class in app/Services whenever you create a model.

This small enhancement aligns perfectly with modern Laravel architecture patterns, where services encapsulate business logic, repositories handle data access, and controllers remain thin orchestration layers.

The Service Layer Pattern

Before diving into the package, let’s understand why service classes matter.

In a typical Laravel controller, you might see:

public function store(Request $request)
{
    $validated = $request->validate([...]);
    
    $post = Post::create($validated);
    
    if ($request->has('tags')) {
        $post->tags()->attach($request->tags);
    }
    
    Mail::to($post->author)->send(new PostPublished($post));
    
    Cache::tags('posts')->flush();
    
    return redirect()->route('posts.show', $post);
}

This controller knows too much: validation rules, database operations, email logic, cache management, and routing. Testing requires mocking multiple facades, and reusing this logic elsewhere means duplicating code.

The service layer pattern extracts this into a dedicated class:

// PostService.php
public function createPost(array $data): Post
{
    $post = Post::create($data);
    
    if (isset($data['tags'])) {
        $post->tags()->attach($data['tags']);
    }
    
    Mail::to($post->author)->send(new PostPublished($post));
    Cache::tags('posts')->flush();
    
    return $post;
}

// PostController.php
public function store(PostRequest $request, PostService $service)
{
    $post = $service->createPost($request->validated());
    return redirect()->route('posts.show', $post);
}

The controller becomes a thin orchestration layer, while the service handles business logic. Testing improves dramatically – mock the service, not individual facades.

Installation

Add the package via Composer:

composer require mattyeend/laravel-model-service

Laravel’s auto-discovery handles registration automatically. No configuration files, no service provider registration – it just works.

Basic Usage

The package integrates seamlessly with your existing workflow. Use the -S or --service flag with make:model:

# Create a model with service
php artisan make:model Post -S

# Create model, migration, controller, and service
php artisan make:model Post -mcrS

# Long form
php artisan make:model Post --service

This generates both the model and a corresponding service class:

app/
  Models/
    Post.php
  Services/
    PostService.php

Working with the -a Flag

Laravel’s -a flag creates everything: model, migration, factory, seeder, policy, controller, and form requests. The laravel-model-service package extends this to include the service class:

php artisan make:model Post -a

This creates:

app/
  Models/
    Post.php
  Services/
    PostService.php
  Http/
    Controllers/
      PostController.php
    Requests/
      StorePostRequest.php
      UpdatePostRequest.php
  Policies/
    PostPolicy.php
database/
  factories/
    PostFactory.php
  migrations/
    2025_08_15_000000_create_posts_table.php
  seeders/
    PostSeeder.php

A complete CRUD setup with service layer in a single command.

The Generated Service Class

The package uses a stub template to generate service classes. By default, you get a basic structure:

<?php

namespace App\Services;

use App\Models\Post;

class PostService
{
    public function __construct()
    {
        //
    }
    
    // Add your service methods here
}

This minimal scaffold lets you immediately start adding business logic methods without worrying about namespace declarations or basic structure.

Customising the Service Stub

Every project has coding standards. You can customise the generated service class by publishing the stub:

php artisan vendor:publish --tag=stubs

This creates stubs/service.stub in your project root. Modify it to match your team’s conventions:

<?php

namespace App\Services;

use App\Models\{{ model }};

class {{ class }}Service
{
    /**
     * Create a new service instance.
     */
    public function __construct()
    {
        //
    }
    
    /**
     * Get all {{ modelPlural }}.
     */
    public function getAll()
    {
        return {{ model }}::all();
    }
    
    /**
     * Create a new {{ model }}.
     */
    public function create(array $data): {{ model }}
    {
        return {{ model }}::create($data);
    }
    
    /**
     * Update a {{ model }}.
     */
    public function update({{ model }} ${{ modelVariable }}, array $data): {{ model }}
    {
        ${{ modelVariable }}->update($data);
        return ${{ modelVariable }};
    }
    
    /**
     * Delete a {{ model }}.
     */
    public function delete({{ model }} ${{ modelVariable }}): bool
    {
        return ${{ modelVariable }}->delete();
    }
}

Now every generated service includes CRUD methods out of the box.

Real-World Use Cases

Multi-Step Business Logic

Services excel at orchestrating complex operations:

// OrderService.php
public function placeOrder(User $user, array $items): Order
{
    DB::beginTransaction();
    
    try {
        $order = Order::create([
            'user_id' => $user->id,
            'total' => $this->calculateTotal($items),
        ]);
        
        foreach ($items as $item) {
            $order->items()->create($item);
            $this->updateInventory($item['product_id'], $item['quantity']);
        }
        
        $this->sendConfirmationEmail($user, $order);
        $this->notifyWarehouse($order);
        
        DB::commit();
        return $order;
        
    } catch (\Exception $e) {
        DB::rollBack();
        throw $e;
    }
}

Third-Party Integration

Isolate external service calls:

// PaymentService.php
public function processPayment(Order $order): PaymentResult
{
    $stripe = new \Stripe\StripeClient(config('services.stripe.secret'));
    
    try {
        $charge = $stripe->charges->create([
            'amount' => $order->total * 100,
            'currency' => 'usd',
            'source' => $order->payment_token,
        ]);
        
        $order->update(['payment_status' => 'paid']);
        
        return new PaymentResult(true, $charge->id);
        
    } catch (\Stripe\Exception\CardException $e) {
        Log::error('Payment failed', ['order' => $order->id, 'error' => $e->getMessage()]);
        return new PaymentResult(false, null, $e->getMessage());
    }
}

Reusable Business Rules

Share logic across controllers, commands, and jobs:

// UserService.php
public function suspendUser(User $user, string $reason): void
{
    $user->update(['status' => 'suspended']);
    $user->sessions()->delete();
    
    Mail::to($user)->send(new AccountSuspended($reason));
    
    Log::info('User suspended', [
        'user_id' => $user->id,
        'reason' => $reason,
        'suspended_by' => auth()->id(),
    ]);
}

// Use from controller
public function suspend(User $user, Request $request)
{
    $this->userService->suspendUser($user, $request->reason);
    return back()->with('success', 'User suspended');
}

// Use from Artisan command
public function handle()
{
    $inactiveUsers = User::where('last_login_at', '<', now()->subMonths(6))->get();
    
    foreach ($inactiveUsers as $user) {
        $this->userService->suspendUser($user, 'Inactive for 6 months');
    }
}

Compatibility

The package supports Laravel 10, 11, 12, and 13 with PHP 8.1 or higher. This ensures compatibility with modern Laravel applications while maintaining support for projects on long-term support versions.

Package Stats

With 9 installs and 1 GitHub star, laravel-model-service is a newer package in the ecosystem. The latest version (v1.1.3) was released on March 13, 2026, demonstrating active maintenance and responsiveness to the Laravel release cycle.

The package has zero open issues, suggesting a focused scope and stable implementation.

PSR-4 Compliance

The package follows PSR-4 autoloading standards, ensuring seamless integration with Composer’s autoloader and Laravel’s namespace conventions. Services are automatically discoverable, and dependency injection works without additional configuration.

Why This Package Matters

Laravel’s philosophy emphasises developer happiness through reducing friction. This package embodies that philosophy by eliminating a repetitive manual task.

Without this package, creating a model with service requires:

php artisan make:model Post -mcr
# Manually create app/Services/PostService.php
# Add namespace, use statements, class declaration
# Save and continue

With the package:

php artisan make:model Post -mcrS
# Service created automatically, ready to use

The time savings compound across dozens or hundreds of models in a typical application. More importantly, the package reinforces architectural best practices by making the service layer pattern as easy to adopt as any other Laravel convention.

The Bottom Line

The laravel-model-service package is a small tool that solves a specific problem elegantly. If you use the service layer pattern – and you should – this package eliminates the busywork of creating service classes manually.

It integrates transparently with Laravel’s existing scaffolding tools, requires zero configuration, and respects your customization preferences through publishable stubs.

For teams committed to maintainable, testable Laravel applications, this package is a workflow enhancement that pays dividends from the first make:model command onward.


Package Stats:

  • Installs: 9
  • Stars: 1
  • Open Issues: 0
  • License: MIT
  • Latest Version: v1.1.3

Links: