VOOZH about

URL: https://deepwiki.com/hypervel/bus/3-core-concepts

⇱ Core Concepts | hypervel/bus | DeepWiki


Loading...
Menu

Core Concepts

This page explains the fundamental concepts underlying the hypervel/bus package: what commands and jobs are, how handlers process them, the role of the Dispatcher abstraction, and the distinction between synchronous and asynchronous execution. For information about configuring specific dispatch mechanisms, see Dispatching Jobs. For details on job traits that enable dispatching behavior, see Job Traits.


Commands and Jobs

In the context of this package, commands and jobs are interchangeable terms referring to objects that encapsulate an action or unit of work to be executed. The system treats any PHP object as a potential command that can be dispatched through the bus.

A command is typically a plain PHP class that:

  • Represents a single action or task (e.g., SendEmail, ProcessOrder, GenerateReport)
  • Contains the data necessary to perform that action as properties
  • May optionally implement handler logic in a handle() method (self-handling)
  • May implement ShouldQueue to indicate it should be processed asynchronously

The package does not enforce a strict command interface. Any object can be dispatched, though specific interfaces and traits enable additional functionality:

Interface/TraitPurpose
ShouldQueueMarks a command for asynchronous queue processing
ShouldBeUniquePrevents duplicate dispatch of the same command
Queueable traitAdds queue configuration properties (connection, queue name, delay)
Dispatchable traitAdds static dispatch methods to the command class
Batchable traitAllows commands to participate in batch processing

Sources: src/Dispatcher.php170-173 composer.json1-60


Handlers

A handler is responsible for executing the business logic of a command. There are two approaches to defining handlers:

Self-Handling Commands

Commands can handle themselves by implementing a handle() method directly on the command class. The Dispatcher will call this method when executing the command:


The Dispatcher uses the DI container's call() method to resolve dependencies in the handler method src/Dispatcher.php100-105

External Handlers

Commands can be mapped to separate handler classes using the map() method on the Dispatcher. The handler class must implement either a handle() or __invoke() method:


The Dispatcher retrieves handlers from the command-to-handler mapping src/Dispatcher.php148-165 and executes the appropriate method src/Dispatcher.php91-96

Handler Resolution Process

The following diagram shows how the Dispatcher resolves and executes handlers:


Sources: src/Dispatcher.php80-112 src/Dispatcher.php148-165


The Dispatcher Abstraction

The Dispatcher is the core abstraction that serves as the command bus, routing commands to their handlers. It provides a unified interface for executing commands regardless of whether they run synchronously or asynchronously.

Dispatcher Contract

The Dispatcher interface defines the basic contract src/Contracts/Dispatcher.php1-45:

MethodDescription
dispatch($command)Route command to handler, queuing if ShouldQueue
dispatchSync($command, $handler)Execute synchronously using 'sync' queue
dispatchNow($command, $handler)Execute immediately in current process
hasCommandHandler($command)Check if command has mapped handler
getCommandHandler($command)Retrieve handler for command
pipeThrough(array $pipes)Configure middleware pipeline
map(array $map)Map commands to external handlers

QueueingDispatcher Contract

The QueueingDispatcher interface extends Dispatcher to add batch processing capabilities src/Contracts/QueueingDispatcher.php1-27:

MethodDescription
findBatch($batchId)Retrieve a batch by ID
batch($jobs)Create a new batch of jobs
dispatchToQueue($command)Explicitly dispatch to queue

Concrete Implementation

The Dispatcher class src/Dispatcher.php1-244 implements both contracts. Key components include:

The following diagram maps the contract hierarchy to concrete implementations:


Sources: src/Contracts/Dispatcher.php1-45 src/Contracts/QueueingDispatcher.php1-27 src/Dispatcher.php20-48


Synchronous vs Asynchronous Execution

The bus supports two execution modes: synchronous (immediate) and asynchronous (queued). The mode is determined by the command's implementation and the dispatch method used.

Execution Mode Determination

The Dispatcher determines execution mode using the following logic src/Dispatcher.php53-58:


Synchronous Execution

Synchronous execution runs commands immediately in the current process. Three methods provide synchronous execution:

  1. dispatchNow($command, $handler = null) - Executes immediately without queue consideration src/Dispatcher.php80-112
  2. dispatchSync($command, $handler = null) - Similar to dispatchNow(), but routes ShouldQueue commands to the 'sync' queue src/Dispatcher.php65-75
  3. dispatch($command) - Executes synchronously if command does not implement ShouldQueue src/Dispatcher.php53-58

When executing synchronously, the Dispatcher:

  1. Resolves the command handler (external or self-handling)
  2. Creates a SyncJob wrapper if the command uses InteractsWithQueue trait src/Dispatcher.php82-89
  3. Passes the command through the middleware pipeline src/Dispatcher.php108-111
  4. Invokes the handler and returns the result

Asynchronous Execution

Asynchronous execution pushes commands to a queue for later processing by queue workers. This occurs when:

  • The command implements ShouldQueue interface
  • A queue resolver is configured
  • dispatch() or dispatchToQueue() is called

The async dispatch process src/Dispatcher.php180-215:

  1. Resolves the queue connection from the command's connection property
  2. Obtains a Queue instance via the queue resolver closure
  3. Calls the command's queue() method if it exists, otherwise pushes to queue
  4. Respects the command's queue and delay properties for routing

Execution Mode Comparison

AspectSynchronousAsynchronous
Execution TimingImmediateDeferred to queue worker
ProcessCurrent processBackground worker process
Return ValueHandler's return valueQueue job ID
Error HandlingException propagates to callerHandled by queue worker
Use CaseFast operations, transactionalSlow operations, background tasks
Command InterfaceAny objectMust implement ShouldQueue

The sync Queue Connection

The 'sync' queue connection is a special queue that executes jobs synchronously while maintaining queue semantics. When dispatchSync() is called on a ShouldQueue command, it temporarily changes the connection to 'sync' src/Dispatcher.php67-72:


This allows testing and development scenarios where queue infrastructure isn't available, but the code path should behave as if queued.

Sources: src/Dispatcher.php53-75 src/Dispatcher.php80-112 src/Dispatcher.php170-173 src/Dispatcher.php180-215


The Pipeline System

The Dispatcher uses a middleware pipeline to process commands before they reach their handlers. This allows cross-cutting concerns (logging, validation, authorization) to be applied uniformly.

Pipeline Configuration

Middleware is configured using the pipeThrough() method src/Dispatcher.php228-233:


Pipeline Execution

When a command is dispatched, the Dispatcher sends it through the pipeline src/Dispatcher.php108-111:


The Pipeline class (from hypervel/support) executes each middleware in order, passing control to the next middleware in the chain until the handler is finally invoked.

Middleware Structure

Each middleware should accept the command and a $next closure:


Sources: src/Dispatcher.php24-30 src/Dispatcher.php108-111 src/Dispatcher.php228-233


Command Bus Flow

The following sequence diagram illustrates the complete flow from dispatch to handler execution:


Sources: src/Dispatcher.php53-112 src/Dispatcher.php180-215


Key Architectural Patterns

Dependency Injection

The Dispatcher is instantiated with the DI container and queue resolver src/Dispatcher.php43-48:


This design allows:

  • Handler resolution from the container
  • Dependency injection into handler methods
  • Queue connection resolution
  • Testability through mock containers

Command-Handler Decoupling

Commands are decoupled from their handlers through:

  1. Self-handling: Command defines its own handler logic
  2. Explicit mapping: Commands mapped to external handlers via map()
  3. Convention-based resolution: Container resolves handlers by convention

This flexibility allows different architectural styles (CQRS, transaction script, domain model) to coexist.

Interface Segregation

The two-tier contract hierarchy separates concerns:

  • Dispatcher: Core synchronous dispatch functionality
  • QueueingDispatcher: Extends with batching and async capabilities

This allows systems that don't need batching to depend only on the simpler Dispatcher contract.

Sources: src/Dispatcher.php43-48 src/Contracts/Dispatcher.php7-45 src/Contracts/QueueingDispatcher.php11-27