Weave Code
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

Onion Laravel Package

aldemeery/onion

Aldemeery Onion is a Laravel package for adding “onion” (layered) architecture patterns to your app, helping you organize code into clear domain, application, and infrastructure layers with cleaner boundaries, structure, and maintainability.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require aldemeery/onion
    

    Add the service provider to config/app.php:

    'providers' => [
        Aldemeery\Onion\OnionServiceProvider::class,
    ],
    
  2. Basic Layer Definition Define layers in config/onion.php:

    'layers' => [
        'api' => [
            'middleware' => ['api', 'auth:sanctum'],
            'routes' => ['api.php'],
        ],
        'web' => [
            'middleware' => ['web'],
            'routes' => ['web.php'],
        ],
    ],
    
  3. First Use Case Register a layer-aware service in a provider:

    $this->app->singleton('MyLayerService', function ($app) {
        return new MyLayerService($app['onion']->layer('api'));
    });
    

Where to Look First

  • Configuration: config/onion.php (layer definitions)
  • Facade: Onion::layer('layer-name') (access layers)
  • Service Provider: Aldemeery\Onion\OnionServiceProvider (boot logic)

Implementation Patterns

Layer-Aware Middleware

Wrap middleware to conditionally apply based on layers:

class LayerAwareMiddleware {
    public function __construct(protected Onion $onion) {}

    public function handle($request, Closure $next) {
        if ($this->onion->isActive('api')) {
            return $next($request);
        }
        return response('Not allowed', 403);
    }
}

Dynamic Route Grouping

Use layers to group routes with shared middleware:

Route::group(['layer' => 'api'], function () {
    Route::get('/users', [UserController::class, 'index']);
});

Dependency Injection by Layer

Resolve services scoped to a layer:

class UserController {
    public function __construct(
        public UserService $service,
        public Onion $onion
    ) {
        $this->service = $this->onion->layer('api')->make(UserService::class);
    }
}

Layer-Specific Configuration

Override config per layer:

$onion = app('onion');
$apiConfig = $onion->layer('api')->config('services.stripe.key');

Workflow: Adding a New Layer

  1. Define the layer in config/onion.php.
  2. Register layer-specific bindings in a service provider:
    $this->app->when('onion.api')->needs('MyService')->give(MyService::class);
    
  3. Use Onion::layer('name')->make() to resolve layer-scoped dependencies.

Gotchas and Tips

Pitfalls

  • Circular Dependencies: Layers can create circular resolution if not structured carefully. Avoid layer A depending on layer B, which depends on layer A.
  • Middleware Override: Middleware defined in a layer will override global middleware for that layer. Test thoroughly.
  • Service Resolution Order: Layer-specific bindings take precedence over global bindings. Use ->needs() carefully to avoid conflicts.

Debugging

  • Check Active Layer: Use Onion::activeLayers() to debug which layers are currently active.
  • Middleware Debugging: Temporarily add dd($this->onion->activeLayers()) in middleware to inspect layer context.
  • Configuration Overrides: Verify layer-specific config overrides with:
    $onion->layer('api')->config('key');
    

Tips

  • Layer Naming: Use descriptive names (e.g., api, web, cli, admin) to avoid ambiguity.
  • Testing: Mock Onion in tests to isolate layer-specific behavior:
    $onionMock = Mockery::mock(Onion::class);
    $onionMock->shouldReceive('layer')->andReturn($layerMock);
    $this->app->instance(Onion::class, $onionMock);
    
  • Performance: Layer resolution adds minimal overhead. Benchmark if critical paths are affected.
  • Extension Points:
    • Extend Aldemeery\Onion\Layer to add custom layer logic.
    • Use Onion::extend() to register custom layer resolvers:
      Onion::extend('custom', function ($app) {
          return new CustomLayer($app);
      });
      
  • CLI Layers: Define a cli layer for Artisan commands:
    'layers' => [
        'cli' => [
            'middleware' => ['standalone'],
            'commands' => [\App\Console\Commands\*],
        ],
    ],
    
  • Fallback Layers: Set a default layer in config/onion.php:
    'default' => 'web',
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui