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

Structarmed Laravel Package

boundwize/structarmed

StructArmed is a dev-only PHP architecture guard: define layers and dependency rules, start from presets (PSR-4/1/12, MVC, DDD), then tune or skip checks in PHP. Run it in CI to catch boundary violations before they become conventions.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require --dev boundwize/structarmed
    

    Add to composer.json under require-dev if not using global CLI.

  2. Initialize Configuration:

    vendor/bin/structarmed init --preset=mvc
    

    This generates structarmed.php in your project root with a basic MVC preset.

  3. First Analysis:

    vendor/bin/structarmed analyse
    

    Run this in your CI pipeline or pre-commit hook to enforce architecture rules.

Where to Look First

  • Presets: Start with Preset::PSR4() or Preset::MVC() for Laravel projects.
  • Configuration: Edit structarmed.php to define layers (e.g., src/Application/, src/Domain/).
  • CLI Output: Review violations in the terminal or JSON report (--report=json).

First Use Case

Enforce Layer Isolation in a Laravel App:

// structarmed.php
return Architecture::define()
    ->layer('Domain', 'src/Domain/')
    ->layer('Application', 'src/Application/')
    ->layer('Infrastructure', 'src/Infrastructure/')
    ->withPreset(Preset::DDD())
    ->ruleset([
        'Domain'      => [],
        'Application' => ['Domain'],
        'Infrastructure' => ['Domain', 'Application'],
    ]);

Run vendor/bin/structarmed analyse to catch cross-layer dependencies (e.g., Infrastructure calling Domain directly).


Implementation Patterns

Workflows

  1. Iterative Enforcement:

    • Start with Preset::PSR4() to validate autoload paths.
    • Gradually add stricter presets (e.g., Preset::PSR12() for visibility rules).
    • Use --generate-baseline for legacy code, then refactor incrementally.
  2. Layer-Based Development:

    • Define layers in structarmed.php to mirror your project’s architecture:
      ->layer('API', 'src/Http/Controllers/')
      ->layer('Services', 'src/Services/')
      ->ruleset([
          'API' => ['Services'],
          'Services' => ['Domain'],
      ]);
      
    • Integrate with Laravel’s service container by ensuring Services layer only depends on Domain entities.
  3. Custom Rules for Laravel-Specific Needs:

    • Enforce that controllers (API layer) must not instantiate Eloquent models directly:
      ->rule('controllers_must_not_instantiate_models', new MayNotDependOnRule(
          from: 'API',
          to: 'Domain',
          toClassNamePattern: '/^.*Model$/'
      ));
      

Integration Tips

  • CI/CD Pipeline: Add to .github/workflows/ci.yml:

    - name: Enforce Architecture
      run: vendor/bin/structarmed analyse --report=json
    

    Fail the job if violations exist.

  • Pre-Commit Hook: Use husky or laravel-pint hooks to run:

    vendor/bin/structarmed analyse --disable-parallel
    

    (Disable parallel for deterministic local runs.)

  • PHPUnit Integration: Add to phpunit.xml:

    <extensions>
        <bootstrap class="Boundwize\StructArmed\PHPUnit\StructArmedExtension"/>
    </extensions>
    

    This blocks test execution if architecture rules are violated.

  • Laravel Service Providers: Use structarmed.php to validate that AppServiceProvider only depends on Domain or Application layers:

    ->layer('Providers', 'app/Providers/')
    ->ruleset(['Providers' => ['Domain', 'Application']]);
    

Gotchas and Tips

Pitfalls

  1. False Positives with Namespaces:

    • If using layerPattern(), ensure regexes are precise to avoid misclassifying classes. Example:
      // ❌ Misclassifies App\Tests\Unit\Http\Controllers\* as 'API'
      ->layerPattern('API', '/^App\\\\.*Controller$/')
      
      // ✅ Correct: Explicit namespace
      ->layerPattern('API', '/^App\\\\Http\\\\Controllers\\\\.*$/')
      
  2. Baseline Overuse:

    • Avoid treating baselines as a crutch. They hide violations, not fix them. Use only for:
      • Legacy code during migration.
      • Temporary exceptions (e.g., third-party libraries).
  3. Parallel Processing Quirks:

    • Disable with --disable-parallel if:
      • Running in a constrained environment (e.g., Docker with limited resources).
      • Debugging a specific violation (parallelism can obscure worker-specific errors).
  4. Rule Key Typos:

    • Always use constants (e.g., DddPreset::ENTITY_MUST_BE_FINAL), not strings. Typos are caught at runtime:
      // ❌ Silent failure (no rule applied)
      ->skipRule('ddd.entity.must_be_final')
      
      // ✅ Explicit (throws RuleNotFoundException)
      ->skipRule(DddPreset::ENTITY_MUST_BE_FINAL);
      
  5. Path Skipping Scope:

    • skipPaths() excludes files from all rules, while skipPathsForRuleset() excludes only ruleset checks. Example:
      // ✅ Tests are scanned for PSR-12 but excluded from layer rules
      ->withPreset(Preset::PSR12())
      ->skipPathsForRuleset(['*tests*'])
      

Debugging

  1. Verbose Output: Use --verbose to see layer resolution and rule application:

    vendor/bin/structarmed analyse --verbose
    
  2. Isolate Violations: Narrow down issues by path:

    vendor/bin/structarmed analyse src/Http/Controllers/
    
  3. Check Layer Resolution: Add debug logs to structarmed.php:

    ->layer('API', 'src/Http/Controllers/')
    ->layerPattern('Services', '/^App\\\\Services\\\\.*$/', '/^App\\\\Services\\\\Tests\\\\.*$/');
    

    Run with --verbose to confirm classes are classified correctly.

Extension Points

  1. Custom Presets for Laravel: Create a preset for Laravel-specific rules (e.g., Preset::Laravel()):

    final class LaravelPreset implements PresetInterface {
        public const CONTROLLERS_MUST_EXTEND_BASE_CONTROLLER = 'laravel.controllers_must_extend_base';
    
        public function apply(Architecture $architecture): void {
            $architecture
                ->layer('Controllers', 'app/Http/Controllers/')
                ->rule(
                    self::CONTROLLERS_MUST_EXTEND_BASE_CONTROLLER,
                    new MustExtendRule(
                        layer: 'Controllers',
                        baseClass: 'App\\Http\\Controllers\\Controller'
                    )
                );
        }
    }
    

    Register it in structarmed.php:

    ->withPreset(new LaravelPreset());
    
  2. Dynamic Rule Configuration: Use Laravel’s config to parameterize rules:

    // structarmed.php
    $maxComplexity = config('structarmed.max_complexity', 5);
    ->withPreset(Preset::DDD(maxComplexity: $maxComplexity));
    
  3. Event Listeners for Violations: Extend StructArmed’s event system (if supported in future versions) to log violations to a database or Slack.

Laravel-Specific Tips

  1. Artisan Command Integration: Create a custom Artisan command to run StructArmed with Laravel’s config:

    // app/Console/Commands/EnforceArchitecture.php
    use Illuminate\Console\Command;
    use Symfony\Component\Process\Process;
    
    class EnforceArchitecture extends Command {
        protected $signature = 'arch:enforce';
        public function handle() {
            $process = new Process(['vendor/bin/structarmed', 'analyse']);
            $process->run();
            $this->output->write($process->getOutput());
            if ($process->getExitCode() !== 0) {
                $this->error('Architecture violations found!');
                exit(1);
            }
        }
    }
    

    Register the command in AppServiceProvider:

    public function boot() {
        if ($this->app->runningInConsole()) {
            $this->commands([EnforceArchitecture::class]);
        }
    }
    
  2. Package Development: For Laravel packages, use StructArmed to enforce that:

    • The package’s src/ layer only depends on Domain or Application layers.
    • Service providers (src/Providers/) do not instantiate framework classes directly.
  3. Testing: Use the PHPUnit extension in your package tests to ensure architecture rules hold during development:

    <!-- phpunit.xml.dist -->
    <extensions>
        <bootstrap class="Boundwize\StructArmed\PHPUnit\StructArmedExtension"/>
    </extensions>
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity