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

Attributes Laravel Package

windwalker/attributes

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require windwalker/attributes ^4.0
    

    Add to composer.json if using a framework like Laravel:

    "require": {
        "windwalker/attributes": "^4.0"
    }
    
  2. First Use Case: Define a custom attribute (e.g., #[Route] for API endpoints):

    use WindWalker\Attributes\Attribute;
    
    #[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
    class Route
    {
        public function __construct(public string $path) {}
    }
    

    Resolve attributes in a class/method:

    use WindWalker\Attributes\Attributes;
    
    class UserController {
        #[Route('/users')]
        public function index() {}
    }
    
    $reflection = new \ReflectionClass(UserController::class);
    $attributes = Attributes::get($reflection->getMethod('index'));
    $route = $attributes->get(Route::class); // Returns Route instance with path='/users'
    

Implementation Patterns

1. Attribute Resolution Workflows

  • Class/Method/Property Targeting: Use Attributes::get() with a ReflectionClass, ReflectionMethod, or ReflectionProperty to fetch attributes.

    $classAttributes = Attributes::get(new \ReflectionClass(MyClass::class));
    $methodAttributes = Attributes::get(new \ReflectionMethod(MyClass::class, 'myMethod'));
    
  • Global Attribute Resolution: For Laravel, create a service provider to pre-resolve attributes on boot:

    public function boot()
    {
        $this->app->resolving(MyClass::class, function ($class) {
            $attributes = Attributes::get(new \ReflectionClass($class));
            // Cache or inject resolved attributes.
        });
    }
    

2. Integration with Laravel

  • Service Container Binding: Bind resolved attributes to the container for dependency injection:

    $this->app->bind(Route::class, function ($app, $parameters) {
        $reflection = new \ReflectionMethod(...);
        return Attributes::get($reflection)->get(Route::class);
    });
    
  • Middleware/Filtering: Use attributes to dynamically apply middleware (e.g., #[Authenticate]):

    #[Attribute(Attribute::TARGET_METHOD)]
    class Authenticate {}
    
    // In middleware:
    if (Attributes::get($reflection)->has(Authenticate::class)) {
        return redirect('login');
    }
    

3. Dynamic Attribute Handling

  • Attribute Aggregation: Combine multiple attributes into a single object for cleaner logic:

    $attributes = Attributes::get($reflection);
    $meta = new ControllerMeta(
        $attributes->get(Route::class),
        $attributes->get(Authenticate::class)
    );
    
  • Fluent Interface: Chain attribute checks for readability:

    if (Attributes::get($reflection)
        ->has(Route::class)
        ->get(Route::class)->path === '/admin') {
        // Admin route logic
    }
    

Gotchas and Tips

Pitfalls

  1. Reflection Overhead:

    • Avoid resolving attributes in performance-critical paths (e.g., loop iterations). Cache results:
      static $cachedAttributes = [];
      $reflection = new \ReflectionMethod(...);
      $cacheKey = $reflection->getName();
      return $cachedAttributes[$cacheKey] ?? ($cachedAttributes[$cacheKey] = Attributes::get($reflection));
      
  2. Attribute Target Mismatch:

    • Ensure attributes are applied to the correct target (e.g., TARGET_METHOD for methods). Misconfiguration throws ReflectionException.
  3. PHP 8+ Dependency:

    • Requires PHP 8.0+. Test on lower versions will fail.
  4. Namespace Collisions:

    • Attributes must have unique fully qualified names (FQCNs). Avoid naming conflicts with other packages.

Debugging Tips

  1. Inspect Attributes: Use var_dump() or dd() to debug resolved attributes:

    dd(Attributes::get($reflection)->all());
    
  2. Check Reflection: Verify the reflection object is correct:

    $method = new \ReflectionMethod(MyClass::class, 'myMethod');
    if (!$method->exists()) {
        throw new \RuntimeException("Method not found");
    }
    
  3. Attribute Existence: Use has() before get() to avoid exceptions:

    if (Attributes::get($reflection)->has(MyAttribute::class)) {
        $attr = Attributes::get($reflection)->get(MyAttribute::class);
    }
    

Extension Points

  1. Custom Attribute Resolvers: Extend the Attributes class to add custom resolution logic:

    class CustomAttributes extends Attributes {
        public static function getFromContainer($reflection) {
            return self::get($reflection)->filter(fn($attr) => $attr instanceof CustomAttribute);
        }
    }
    
  2. Attribute Inheritance: For Laravel, create a trait to auto-resolve parent class attributes:

    trait AttributeInheritance {
        public function getInheritedAttributes() {
            $parent = (new \ReflectionClass($this))->getParentClass();
            return $parent ? Attributes::get($parent) : new Attributes();
        }
    }
    
  3. Attribute Validation: Validate attributes at runtime (e.g., ensure Route paths are non-empty):

    $route = Attributes::get($reflection)->get(Route::class);
    if (empty($route->path)) {
        throw new \InvalidArgumentException("Route path cannot be empty");
    }
    
  4. Laravel Service Provider Hooks: Use register to bind attribute resolvers globally:

    public function register() {
        $this->app->singleton('attributes', function () {
            return new Attributes();
        });
    }
    
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.
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
christhompsontldr/laravel-inky
spatie/mailcoach-vapor