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

Handler Basics Extension Laravel Package

quantumtecnology/handler-basics-extension

A lightweight extension for Laravel/PHP handler workflows. It offers basic utilities, conventions, and reusable helpers to simplify custom handler setup and keep integrations consistent with minimal configuration. Fits into existing projects and supports handler-based packages.

View on GitHub
Deep Wiki
Context7

Getting Started

quantumtecnology/handler-basics-extension is a small MIT-licensed package (single star, zero dependents) that layers reusable handler scaffolding onto Laravel's service container. Treat it as an internal-convention package, not a community-standard one: the value is in the base classes and contracts it gives you so that every "do the thing" class in your app has the same shape.

Minimum viable setup

composer require quantumtecnology/handler-basics-extension
composer dump-autoload

Then verify whether it ships a provider and whether discovery is wired:

# 1. Does it auto-register?
cat vendor/quantumtecnology/handler-basics-extension/composer.json | grep -A5 '"extra"'

# 2. What does it actually contain?
find vendor/quantumtecnology/handler-basics-extension/src -type f -name '*.php'

# 3. Publish anything configurable?
php artisan vendor:publish --provider="QuantumTecnology\\HandlerBasicsExtension\\HandlerBasicsExtensionServiceProvider"

If step 1 shows no extra.laravel.providers, add the provider to bootstrap/providers.php (Laravel 11+) or config/app.php by hand.

Where to look first, in this order

  1. composer.json — require tells you the supported Laravel/PHP range (critical for a package with a near-future release date like 2026-10-14; confirm it doesn't pin you to an unreleased framework major).
  2. src/ — the contracts (*Interface) are the real API surface; base classes are convenience.
  3. The service provider's register() — anything bindable is bound there; that's where extension points live.
  4. README.md last, and skeptically. At this adoption level the source is the documentation.

First use case

Pick one fat controller method you already dislike and convert it into a handler. The goal of the first pass is not architecture perfection — it's proving the container can resolve your class end-to-end:

// app/Handlers/RegisterUserHandler.php  (illustrative — match the package's real base class name)
final class RegisterUserHandler extends BaseHandler
{
    public function __construct(private readonly UserRepository $users) {}

    public function handle(RegisterUserData $data): User
    {
        return $this->users->create($data->toArray());
    }
}

Then app(RegisterUserHandler::class)->handle($data) from the controller. If that works, the package is doing its job: constructor injection, one public entry point, controller reduced to a single line.


Implementation Patterns

1. One handler per use case, not per model

Resist UserHandler with create/update/delete. The pattern pays off when handlers map 1:1 to intents (RegisterUserHandler, SuspendUserHandler, ExportUserCsvHandler). This is what makes them trivially testable and safe to queue later.

2. Interface + base class split

Follow the package's own structure: put a thin contract in app/Contracts/ (handle() with a typed parameter and typed return) and extend the package base class for the boilerplate. Your controllers and jobs should depend on the interface, bound in a dedicated HandlerServiceProvider:

public function register(): void
{
    $this->app->bind(RegisterUserHandlerInterface::class, RegisterUserHandler::class);
}

This lets you swap in a fake during tests without touching call sites.

3. Wrap cross-cutting concerns in one place

If the extension exposes a pipeline/middleware hook (check register() for Pipeline usage or a through()-style method), route transactions and logging through it once rather than repeating DB::transaction() in forty handlers:

protected array $through = [
    WrapInTransaction::class,
    LogHandlerExecution::class,
];

If no pipeline exists, wrap at the dispatch site instead — a single HandlerDispatcher service is the cheapest substitute.

4. Dispatch from the edges, not from other handlers

Controllers, FormRequests, console commands, and jobs should be the only callers. When handler B needs handler A's result, inject A into B's constructor — never call app() inside handle().

5. Queue the same class

Because handlers are constructor-injected and side-effect-scoped, RegisterUserHandler::dispatch($data) (or wrapping in a job) should require no handler changes. Verify serialization: DTOs must be SerializesModels-friendly and not hold closures or Eloquent models with unsaved state.

6. Testing pattern

it('registers a user', function () {
    $handler = new RegisterUserHandler(new InMemoryUserRepository());

    $user = $handler->handle(new RegisterUserData(name: 'Ada'));

    expect($user->name)->toBe('Ada');
});

Instantiate directly — no container, no HTTP, no database. That speed is the entire point of the pattern.

7. Integration with the rest of Laravel

  • Fire domain events from the handler's return path, not from the controller.
  • Let FormRequest own validation; the handler assumes valid input.
  • Use Context/Log::withContext() so every handler log line carries a request or job ID.

Gotchas and Tips

Documentation is thin — budget a discovery hour. At one star and zero dependents there is no Stack Overflow corpus and no blog posts. Read every file in src/ before designing around it. If src/ is under ~10 files, you can absorb it fully.

Pin the version, and vendor it if you must. A 2026-10-14 release date on a package with no dependents means you are the only one testing this code path. Use an exact constraint ("quantumtecnology/handler-basics-extension": "1.0.3"), commit composer.lock, and if you find a bug, fork it into packages/ with a VCS repository entry rather than waiting on an upstream fix.

Service provider auto-discovery is not guaranteed. If classes "cannot be resolved" or config keys come back null, the provider almost certainly isn't registered. php artisan about and php artisan package:discover -v will confirm.

Primitive constructor arguments will blow up resolution. The container cannot autowire a string or int without a binding. Use a DTO (data object) as the single handle() parameter instead of scalars — this also makes queuing and versioning easier.

Watch for config merge weirdness. If the package ships a config file, check whether the provider calls mergeConfigFrom() or only publishes(). If it only publishes, your app breaks the moment you skip the publish step — copy the defaults into config/handler-basics-extension.php explicitly during setup.

Don't let the base class become a god object. Small handler packages tend to accumulate authorize(), validate(), log(), cache() helper methods on the abstract parent. Subclass only what you use; if you start overriding more than one or two parent methods, stop extending and implement the contract directly.

Name collisions. Laravel already has Illuminate\Bus\Dispatcher, Illuminate\Foundation\Bus\Dispatchable, and the job/middleware vocabulary. If you also use league/tactician or a command bus, alias imports deliberately — use App\Handlers\BaseHandler as Handler; — so readers don't confuse the two systems.

Debugging checklist, in order:

php artisan tinker
>>> app(YourHandler::class)          # resolution failure? binding/autowire issue
>>> app()->bound(YourHandler::class) # binding registered?
>>> class_parents(YourHandler::class) # right base class?

If handle() runs but the effect is missing, check whether the provider registered a decorator around your class — that's the most common silent surprise in handler-extension packages.

Extension points to prefer. Override handle() only. If the package exposes protected hooks (beforeHandle, afterHandle, through), use those for cross-cutting concerns so upgrades to the base class stay mergeable. Avoid editing anything under vendor/.

Have an exit plan. If your handler count grows past ~30 and you're fighting the base class, the migration is cheap: your handlers already have one public method and typed DTOs. Dropping the package and keeping your own 30-line abstract class is a half-day of work — which is exactly why adopting a tiny, low-traffic package here is a low-risk bet.

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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr