laravel-arc maintained by rajska
Laravel Arc
Arc (architecture) is a dev-only Laravel package that turns your artisan make:* commands into an architecture-aware, config-driven generator — driven by a single arc.neon file at your project root, right next to phpstan.neon.
Instead of fighting Laravel's fixed file locations, you describe your architecture once — modules, DDD layers, hexagonal composition, or a plain vanilla Laravel tree — and Arc transparently intercepts the native make:* commands to put every generated file exactly where your architecture says it belongs.
Arc is a
require-devdependency. It never boots outside your local environment and has zero runtime footprint in production.
Why Arc
Laravel's generators are excellent, but their target paths are effectively hardcoded. The moment you adopt modules, bounded contexts, or a layered architecture, you end up maintaining custom commands, editing stubs by hand, or reaching for a heavier framework-within-a-framework.
Arc takes a different approach:
- Transparent — you keep typing
php artisan make:controller. Arc silently substitutes the native command, so there is nothing new to learn for the common case. - Config over code — new generators like
make:actionormake:dtoare declared entirely inarc.neon. No PHP class to write per generator. - Convention with escape hatches — sensible Laravel-mirroring defaults out of the box, overridable down to a single key.
- Architecture-agnostic — plain Laravel, modules, DDD, hexagonal, or any combination. You decide the vocabulary and the layout.
Requirements
- PHP 8.3+
- Laravel 11, 12, or 13
Installation
composer require rajska/laravel-arc --dev
That's it. Arc auto-registers via package discovery and only activates in your local environment.
Quick Start
Create an arc.neon at your project root:
context:
enabled:
- Catalog
- Billing
generators:
controller: Generator(path: "app/Http/Controllers/{context}")
Now run a native generator:
php artisan make:controller SupplierController
Arc detects the configured contexts, prompts you to pick one (Catalog or Billing), and generates the file at app/Http/Controllers/Catalog/SupplierController.php — no flags, no new commands to learn.
To skip the prompt, pass the context directly:
php artisan make:controller SupplierController --context=Catalog
Configuration
Arc reads a single arc.neon file. It uses the NEON format — the same human-friendly format PHPStan uses — chosen for its readable entities, which keep declarations compact without sacrificing expressiveness.
Contexts
A context is your unit of business separation — call it a module, a domain, a bounded context, or a feature. The label is cosmetic and configurable; only the list matters.
context:
label: Context
enabled:
- Catalog
- Billing
- Tenancy
Layers
Optional. Layers add a second axis of separation — the how within each context. Declare them only when you want a layered or hexagonal composition.
layers:
domain: Layer(path: src/Domain/{context})
infrastructure: Layer(path: src/Infrastructure, scoped: false)
delivery: Layer(path: app/Modules/{context})
The {context} token is substituted at generation time. A layer marked scoped: false (like a shared Infrastructure kernel) drops the token entirely and never prompts for a context.
Overriding native generators
Point Laravel's built-in make:* commands at your architecture:
generators:
controller: Generator(layer: delivery, path: "Controllers/{surface}")
model: Generator(layer: domain, path: Models)
policy: Generator(layer: domain, path: Policies)
Custom generators
Declare brand-new commands that Laravel doesn't ship. No PHP required — Arc registers them dynamically at boot.
commands:
action: Command(
name: "make:action"
layer: domain
path: Actions
extends: "Domain\\Shared\\Actions\\BaseAction"
implements: Companion(
path: Contracts
suffix: Contract
)
)
dto: Command(
name: "make:dto"
layer: domain
path: DataObjects
implements: "Domain\\Shared\\Contracts\\StatefulObject"
)
A Companion is a secondary file generated alongside the primary one, with its name derived from the primary (e.g. CreateSupplier → CreateSupplierContract). Arc generates the companion first, then injects its fully-qualified name into the primary file's implements/extends clause.
When stub is omitted, Arc falls back to a built-in generic class stub that respects any declared extends, implements, and traits.
Vanilla Laravel
No context, no layers — Arc still works. Custom generators resolve to a plain, fixed path:
commands:
action: Command(
name: "make:action"
path: "app/Actions"
)
Development
This package is developed with DDEV (PHP 8.3+).
ddev start
ddev composer install
ddev composer test # Pest
ddev composer analyse # PHPStan level 8
ddev composer lint # Laravel Pint
Contributing
Please see CONTRIBUTING.md for details, including the commit convention.
License
The MIT License (MIT). Please see the LICENSE file for more information.