Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Service Generator Laravel Package

timwassenburg/laravel-service-generator

Laravel Service Generator adds an artisan command to quickly scaffold service classes, keeping business logic out of controllers. Customize stubs, generate services with dependencies, and follow a clean, testable architecture. A simple way to organize Laravel apps as they grow.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package via Composer; Laravel's package auto-discovery registers the service provider:

composer require timwassenburg/laravel-service-generator

Publish the config so you can control where services land and what they are named:

php artisan vendor:publish --tag=service-generator-config
# if the tag differs in your version:
php artisan vendor:publish --provider="TimWassenburg\ServiceGenerator\ServiceGeneratorServiceProvider"

Confirm the command is registered before relying on it:

php artisan list | grep -i service

Generate your first service:

php artisan make:service UserService

You should get app/Services/UserService.php (or whatever path/namespace the config declares). Open the generated file and the published config/service-generator.php side by side — those two files are the whole package. There is no runtime component, no facade, no container magic; everything the package does is produce a PHP file from a stub.

First use case: pull one fat controller action apart. Move the orchestration (fetch → transform → persist → notify) into the generated service, leave the controller with validation and a single call, and inject the service into the controller constructor. That single refactor is the best way to judge whether the package's defaults match your project's conventions.

Implementation Patterns

Controller → Service → Repository. The generated class is an empty shell, so establish the shape yourself:

namespace App\Services;

class UserService
{
    public function __construct(private UserRepository $users) {}

    public function register(array $data): User
    {
        return DB::transaction(function () use ($data) {
            $user = $this->users->create($data);
            event(new UserRegistered($user));
            return $user;
        });
    }
}

Inject it in the controller via constructor promotion and keep the action to a few lines.

Domain subfolders. If the generator supports nested names, php artisan make:service Billing/InvoiceService keeps large apps navigable. If it does not, either adjust path per generation or fall back to make:class for anything non-flat — do not fight the tool.

Interfaces are your job. The package generates a concrete class only. The standard pattern is to hand-write UserServiceInterface (or extract it later), then bind it in a service provider:

$this->app->bind(UserServiceInterface::class, UserService::class);

Type-hint the interface in controllers and jobs, never the concrete class, or you lose the ability to swap implementations in tests.

Custom stub for team conventions. Publish the stub, then bake in your house style — a Logger trait, a protected array $dependencies, a standard docblock, whatever your review checklist demands. This is the highest-leverage feature of the package: every new service starts compliant instead of being fixed in code review.

Batch scaffolding. When introducing the pattern to an existing codebase, generate all services in one pass (make:service OrderService, make:service PaymentService, …), commit the empty shells, then fill them in over several PRs. Reviewers see structure before logic.

Testing. Because services are plain classes with constructor dependencies, instantiate them directly in unit tests with mocked collaborators. No app() resolution, no HTTP layer — this is the payoff of the pattern.

Gotchas and Tips

  • It is a stub generator, nothing more. It does not register bindings, does not create interfaces, does not wire anything into the container. If you expected auto-DI from the description, you will be disappointed; the value is consistency, not functionality.
  • Suffix duplication. If the config defines a Service suffix and you also pass UserService, you may end up with UserServiceService. Pick one convention: either always omit the suffix from the argument or set the config suffix to an empty string.
  • Namespace/path drift. The namespace and path config values must agree. Setting path to app/Domain/Services while leaving namespace as App\Services produces a class that Composer cannot autoload. Change both together, and run composer dump-autoload after pointing the path outside app/.
  • Verify against your Laravel version. The last release is April 2023. Auto-discovery and the command signature are stable, but check php artisan make:service --help after install rather than assuming flags like --force or --interface exist.
  • No overwrite safety net by default. Regenerating an existing service may fail silently or clobber your code depending on the version. Generate only into clean paths; treat any existing file as sacred.
  • Command name collisions. Other packages also claim make:service. If php artisan list shows a different signature than the README, another provider won the registration — check config/app.php providers and discovery order.
  • Debugging is trivial but worth knowing. If the command is missing, it is almost always a cached config or a stale Composer autoload: php artisan config:clear && composer dump-autoload. If the file lands in the wrong place, the published config was not picked up (env-specific config caching is a common culprit).
  • Extension point is the stub, not the code. Do not subclass the generator or hook into it — publish the stub and edit it. That is the only supported customization surface, and it survives package updates.
  • Know when to skip it. For a one-off class, php artisan make:class Services/Foo is equivalent and adds no dependency. Adopt this package when you want the directory, the namespace, and the stub standardized across a team — otherwise it is ceremony.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel