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

Php Structure Discoverer Laravel Package

spatie/php-structure-discoverer

Discover PHP classes, interfaces, traits, and enums that match conditions (e.g., implement an interface) across your project. Fast scanning with built-in caching and rich metadata—ideal for auto-registration, tooling, and framework integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/php-structure-discoverer
    

    For Laravel, publish the config:

    php artisan vendor:publish --tag="structure-discoverer-config"
    
  2. First Use Case: Discover all classes in app/ that implement Arrayable:

    use Spatie\StructureDiscoverer\Discover;
    
    $arrayableClasses = Discover::in(app_path())->classes()->implementing(\Illuminate\Contracts\Support\Arrayable::class)->get();
    
  3. Key Files:

    • config/structure-discoverer.php (Laravel)
    • vendor/spatie/php-structure-discoverer/src/ (Core package)

Implementation Patterns

Core Workflows

  1. Basic Discovery:

    // Discover all classes in a directory
    Discover::in(app_path('Models'))->classes()->get();
    
    // Discover enums with a specific name
    Discover::in(app_path('Enums'))->enums()->named('StatusEnum')->get();
    
  2. Conditional Discovery:

    // Classes extending a base model
    Discover::in(app_path())->classes()->extending(\Illuminate\Database\Eloquent\Model::class)->get();
    
    // Classes using a specific attribute
    Discover::in(app_path())->withAttribute(\Illuminate\Foundation\Testing\Concerns\InteractsWithTime::class)->get();
    
  3. Custom Conditions:

    // Using closure
    Discover::in(app_path())
        ->custom(fn($structure) => str_contains($structure->namespace, 'App\\Policies'))
        ->get();
    
    // Using a dedicated class
    class PolicyCondition extends DiscoverCondition {
        public function satisfies($structure) {
            return str_contains($structure->namespace, 'App\\Policies');
        }
    }
    Discover::in(app_path())->custom(new PolicyCondition())->get();
    
  4. Combining Conditions:

    // OR logic for classes or enums
    use Spatie\StructureDiscoverer\ConditionBuilder;
    
    Discover::in(app_path())
        ->any(
            ConditionBuilder::create()->classes(),
            ConditionBuilder::create()->enums()
        )
        ->get();
    

Integration Tips

  1. Laravel Service Providers: Register scouts in boot():

    public function boot() {
        StructureScoutManager::add(\App\Scouts\PolicyScout::class);
    }
    
  2. Artisan Commands: Cache scouts during deployment:

    // In a command
    StructureScoutManager::cache([app_path('Scouts')]);
    
  3. Testing: Use NullDiscoverCacheDriver for unit tests:

    Discover::in(__DIR__)
        ->withCache('test', new NullDiscoverCacheDriver())
        ->get();
    
  4. Performance Optimization:

    // Parallel discovery (requires amphp/parallel)
    Discover::in(app_path())->parallel(100)->get();
    

Gotchas and Tips

Pitfalls

  1. Cache Invalidation:

    • Forget to clear caches after refactoring:
      php artisan structure-scouts:clear
      
    • Fix: Always run php artisan structure-scouts:cache post-deployment.
  2. Chains Overhead:

    • Enabling chains (extending()/implementing()) can significantly slow discovery for large codebases.
    • Fix: Use withoutChains() for performance-critical paths:
      Discover::in(app_path())->withoutChains()->extending(BaseModel::class)->get();
      
  3. Namespace Conflicts:

    • Custom conditions may misfire if namespace checks are too broad.
    • Fix: Use DiscoveredStructure properties like $namespace or $file for precision.
  4. Parallel Limitations:

    • Parallel mode may fail on shared hosting with low resource limits.
    • Fix: Test locally first and fall back to sequential mode:
      if (!extension_loaded('pcntl')) {
          Discover::in(app_path())->get(); // Sequential fallback
      }
      

Debugging

  1. Cache Issues:

    • Verify cache driver paths in config/structure-discoverer.php.
    • Debug: Temporarily use FileDiscoverCacheDriver with a writable directory.
  2. Condition Logic:

    • Use full() to inspect DiscoveredStructure objects:
      $structures = Discover::in(app_path())->full()->get();
      dd($structures[0]->extendsChain); // Inspect inheritance
      
  3. Performance Bottlenecks:

    • Profile with ->withoutChains() to isolate slow queries.
    • Tool: Use Laravel Debugbar to measure query time.

Extension Points

  1. Custom Cache Drivers:

    class RedisDiscoverCacheDriver implements DiscoverCacheDriver {
        public function has(string $id): bool { /* ... */ }
        public function get(string $id): array { /* ... */ }
        // Implement remaining methods
    }
    
  2. Structure Scouts:

    • Extend StructureScout for reusable queries:
      class PolicyScout extends StructureScout {
          protected function definition() {
              return Discover::in(app_path('Policies'))
                  ->classes()
                  ->custom(fn($s) => str_contains($s->namespace, 'App\\Policies'));
          }
      }
      
  3. Metadata Enrichment:

    • Override DiscoveredStructure to add custom properties:
      class CustomDiscoveredStructure extends DiscoveredStructure {
          public function __construct(...) {
              parent::__construct(...);
              $this->customProperty = $this->parseCustomLogic();
          }
      }
      

Configuration Quirks

  1. Ignored Files:

    • Add paths to ignored_files in config to exclude vendor/ or tests/:
      'ignored_files' => [
          app_path('Tests'),
          vendor_path(),
      ],
      
  2. Directory Scoping:

    • Ensure structure_scout_directories includes all relevant paths:
      'structure_scout_directories' => [
          app_path(),
          database_path('Factories'),
      ],
      
  3. Laravel Cache Store:

    • Specify a non-default cache store for scouts:
      'cache' => [
          'driver' => \Spatie\StructureDiscoverer\Cache\LaravelDiscoverCacheDriver::class,
          'store' => 'redis',
      ],
      
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope