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

Laravel Auto Discoverer Laravel Package

spatie/laravel-auto-discoverer

Fast, cached discovery of PHP structures in your codebase. Find classes, interfaces, traits, and enums by conditions like “implements interface” or “uses trait,” and get rich metadata. Ideal for automation, registration, and scanning in production.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  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 implementing Arrayable in the app directory:

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

    • README.md: Focus on the "Usage" section for basic queries.
    • Config File: Check config/structure-discoverer.php for ignored files/directories and cache settings.
    • Laravel Artisan Commands: structure-scouts:cache and structure-scouts:clear for production optimization.

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 namespace
    Discover::in(app_path('Enums'))->enums()->custom(fn($structure) => str_starts_with($structure->namespace, 'App\\Enums\\'))->get();
    
  2. Conditional Discovery:

    // Classes extending a base model
    Discover::in(app_path('Models'))->extending(\Illuminate\Database\Eloquent\Model::class)->get();
    
    // Classes using a specific attribute
    Discover::in(app_path())->withAttribute(\Spatie\LaravelActivitylog\Traits\LogsActivity::class)->get();
    
  3. Combining Conditions:

    // Classes OR enums implementing interfaces
    Discover::in(app_path())
        ->any(
            ConditionBuilder::create()->classes()->implementing(\JsonSerializable::class),
            ConditionBuilder::create()->enums()->implementing(\Stringable::class)
        )
        ->get();
    
  4. Caching with Scouts:

    // Define a scout in `app/Scouts/`
    class UserModelScout extends StructureScout {
        protected function definition(): Discover {
            return Discover::in(app_path('Models'))->classes()->extending(\Illuminate\Database\Eloquent\Model::class);
        }
    }
    
    // Use the scout (cached after first run)
    $models = UserModelScout::create()->get();
    
  5. Parallel Discovery (for large codebases):

    Discover::in(base_path())->parallel(100)->get();
    

Integration Tips

  • Laravel Service Providers: Register scouts in register():

    StructureScoutManager::add(\App\Scouts\UserModelScout::class);
    
  • Dynamic Directory Scanning: Use app_path() or base_path() dynamically:

    $directories = [app_path('Models'), app_path('Policies')];
    Discover::in(...$directories)->classes()->get();
    
  • Metadata Utilization: Fetch full structure details for introspection:

    $structures = Discover::in(app_path())->full()->get();
    foreach ($structures as $structure) {
        if ($structure instanceof DiscoveredClass) {
            dump($structure->extendsChain); // Full inheritance chain
        }
    }
    
  • Testing: Use NullDiscoverCacheDriver to bypass caching:

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

Gotchas and Tips

Pitfalls

  1. Cache Invalidation:

    • Issue: Forgetting to run php artisan structure-scouts:cache after adding new scouts or code changes.
    • Fix: Clear and warm caches manually or automate with a post-deploy hook:
      php artisan structure-scouts:clear && php artisan structure-scouts:cache
      
  2. Performance Spikes:

    • Issue: Parallel scanning (->parallel()) may overload systems with many small files.
    • Fix: Limit parallelism or exclude directories with ignored_files in config.
  3. Chains Overhead:

    • Issue: Disabling chains (->withoutChains()) speeds up queries but may miss indirect relationships.
    • Fix: Use ->extendingWithoutChain() or ->implementingWithoutChain() selectively.
  4. Namespace Conflicts:

    • Issue: Custom conditions may misfire due to namespace mismatches (e.g., App\ vs app\).
    • Fix: Normalize namespaces in closures:
      ->custom(fn($structure) => str_contains(strtolower($structure->namespace), 'app\\'))
      
  5. Attribute Detection:

    • Issue: withAttribute() may fail if attributes are not fully loaded (e.g., in compiled code).
    • Fix: Ensure attributes are analyzed during discovery (default behavior is correct).

Debugging Tips

  1. Verify Discovery Scope:

    // Log directories being scanned
    Discover::in(app_path())->debug()->get();
    
  2. Inspect Cached Data:

    // Check cache keys (Laravel)
    \Spatie\StructureDiscoverer\Cache\LaravelDiscoverCacheDriver::getPrefix() . '*';
    
  3. Slow Queries:

    • Profile with Xdebug or Laravel Debugbar to identify bottlenecks in custom conditions.
  4. File Permissions:

    • Ensure cache directories (e.g., storage/framework/cache) are writable:
      chmod -R 755 storage/
      

Extension Points

  1. Custom Cache Drivers: Extend DiscoverCacheDriver for database-backed caching:

    class DatabaseDiscoverCacheDriver implements DiscoverCacheDriver {
        public function has(string $id): bool { /* ... */ }
        // Implement other methods
    }
    
  2. Dynamic Scout Registration: Auto-discover scouts in a directory:

    $scouts = app()->tag('structure-scout');
    foreach ($scouts as $scout) {
        StructureScoutManager::add($scout);
    }
    
  3. Metadata Enrichment: Add custom properties to DiscoveredStructure by extending the class:

    class CustomDiscoveredClass extends DiscoveredClass {
        public function isTestable(): bool {
            return str_contains($this->name, 'Test');
        }
    }
    
  4. Conditional Logic: Create reusable conditions:

    class HasCastAttribute extends DiscoverCondition {
        public function satisfies(DiscoveredStructure $structure): bool {
            return in_array(\Spatie\LaravelActivitylog\Traits\LogsActivity::class, $structure->attributes);
        }
    }
    
  5. Sorting Customization: Add custom sort options by extending the Sort enum:

    enum CustomSort implements Sort {
        case LastModified;
        // Implement comparison logic
    }
    

Laravel-Specific Quirks

  1. Config Overrides: Override cache settings in config/structure-discoverer.php:

    'cache' => [
        'driver' => \Spatie\StructureDiscoverer\Cache\DatabaseDiscoverCacheDriver::class,
        'store' => 'redis',
    ],
    
  2. Artisan Command Hooks: Extend StructureScoutsCommand to add custom logic:

    protected $signature = 'structure-scouts:cache {--directory=*}';
    
  3. Package Development: Use StructureScoutManager::add() in the package’s service provider to register scouts globally.

  4. Testing: Mock the Discover facade or use NullDiscoverCacheDriver in tests:

    $this->app->singleton(Discover::class, function () {
        return Discover::in(__DIR__)->withCache('test', new NullDiscoverCacheDriver());
    });
    
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony