Weave 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
create-php-attribute
alizharb/agent-skills
claude-code
php-attributes
metadata
reflection
architecture-checks
middleware
testing

Use when creating or reviewing a custom PHP 8 attribute for metadata, framework integration, architecture checks, tests, middleware, scanners, or support tooling in this Laravel application.

Install
php artisan boost:add-skill alizharb/agent-skills

Save this content to: .claude/skills/create-php-attribute/SKILL.md

# Create PHP Attribute

## When To Use

Use this skill when stable metadata should be declared with PHP 8 attributes and consumed by application code, tests, middleware, scanners, or tooling.

## Inputs Needed

- Attribute purpose, target, allowed arguments, consuming code, security impact, tests, and naming.

## Workflow

1. Confirm a custom attribute is better than a method, interface, config value, enum, policy, middleware, injection attribute, Eloquent attribute, queue attribute, Form Request attribute, resource attribute, or other Laravel built-in attribute.
2. Inspect existing attribute and support-class conventions.
3. Create the attribute under `app/Attributes` unless the project already has a different convention.
4. Use native PHP `#[Attribute(...)]` targets and repeatability flags.
5. Make the attribute class `final readonly` when possible.
6. Type every constructor parameter.
7. Keep the attribute as metadata only.
8. Create or update the consumer that reads the attribute via reflection, routing, middleware, tests, or support tooling.
9. Add tests for the consumer behavior.
10. Run Pint and focused tests.

## Files That May Be Created

- `app/Attributes/*.php`
- Consumer classes in middleware, support, testing, or scanner namespaces.
- Tests for the attribute consumer.

## Files That May Be Modified

- Classes or methods that receive the attribute.
- Middleware, Actions, Services, Providers, tests, or architecture tests that consume the attribute.

## Architecture Rules

- Attributes describe metadata; they do not perform business workflows.
- Do not use custom attributes to bypass Actions, Policies, DTOs, Events, Jobs, or Services.
- Prefer Laravel built-in attributes before custom attributes.
- Every custom attribute must have a real consumer when introduced.
- Custom attributes are metadata and must not be used to bypass dependency injection.

## Testing Requirements

- Test the consumer behavior.
- Test invalid or missing metadata where relevant.
- Add architecture tests when the attribute marks security, sensitivity, external integrations, or layer boundaries.

## Security Requirements

- Attributes must not store secrets.
- Attributes must not become the only authorization mechanism unless the consumer explicitly enforces policy or gate checks.
- Treat reflected metadata as code-level metadata, not trusted user input.

## Review Checklist

- Is an attribute the simplest clear tool?
- Is there a consumer?
- Are targets and repeatability correct?
- Is the class immutable and typed?
- Are tests focused on behavior?

## Examples

### Good Example

```php
// app/Attributes/RequiresPlan.php
namespace App\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
final readonly class RequiresPlan
{
    public function __construct(public string $plan = 'basic') {}
}
```

```php
// app/Http/Middleware/CheckPlanSubscription.php
namespace App\Http\Middleware;

use Closure;
use ReflectionClass;
use App\Attributes\RequiresPlan;
use Illuminate\Http\Request;

final class CheckPlanSubscription
{
    public function handle(Request $request, Closure $next)
    {
        $controller = $request->route()?->controller;
        if (! $controller) {
            return $next($request);
        }

        // Use reflection to check for attribute on controller class
        $reflection = new ReflectionClass($controller);
        $attribute = $reflection->getAttributes(RequiresPlan::class)[0] ?? null;

if ($attribute) {
            $requiresPlan = $attribute->newInstance();
            if (! $request->user()?->subscribed($requiresPlan->plan)) {
                abort(403, 'Subscription Plan Required');
            }
        }

        return $next($request);
    }
}
```

### Bad Example

```php
// ❌ Constructing custom reflection tags, dynamic execution inside constructor, no targeting filters.
#[Attribute]
class RequiresPlan {
    public function __construct($plan) {
        if (!auth()->user()->subscribed($plan)) {
            redirect('/billing'); // DO NOT run side-effects inside attributes!
        }
    }
}
```

Create PHP Attribute

When To Use

Use this skill when stable metadata should be declared with PHP 8 attributes and consumed by application code, tests, middleware, scanners, or tooling.

Inputs Needed

  • Attribute purpose, target, allowed arguments, consuming code, security impact, tests, and naming.

Workflow

  1. Confirm a custom attribute is better than a method, interface, config value, enum, policy, middleware, injection attribute, Eloquent attribute, queue attribute, Form Request attribute, resource attribute, or other Laravel built-in attribute.
  2. Inspect existing attribute and support-class conventions.
  3. Create the attribute under app/Attributes unless the project already has a different convention.
  4. Use native PHP #[Attribute(...)] targets and repeatability flags.
  5. Make the attribute class final readonly when possible.
  6. Type every constructor parameter.
  7. Keep the attribute as metadata only.
  8. Create or update the consumer that reads the attribute via reflection, routing, middleware, tests, or support tooling.
  9. Add tests for the consumer behavior.
  10. Run Pint and focused tests.

Files That May Be Created

  • app/Attributes/*.php
  • Consumer classes in middleware, support, testing, or scanner namespaces.
  • Tests for the attribute consumer.

Files That May Be Modified

  • Classes or methods that receive the attribute.
  • Middleware, Actions, Services, Providers, tests, or architecture tests that consume the attribute.

Architecture Rules

  • Attributes describe metadata; they do not perform business workflows.
  • Do not use custom attributes to bypass Actions, Policies, DTOs, Events, Jobs, or Services.
  • Prefer Laravel built-in attributes before custom attributes.
  • Every custom attribute must have a real consumer when introduced.
  • Custom attributes are metadata and must not be used to bypass dependency injection.

Testing Requirements

  • Test the consumer behavior.
  • Test invalid or missing metadata where relevant.
  • Add architecture tests when the attribute marks security, sensitivity, external integrations, or layer boundaries.

Security Requirements

  • Attributes must not store secrets.
  • Attributes must not become the only authorization mechanism unless the consumer explicitly enforces policy or gate checks.
  • Treat reflected metadata as code-level metadata, not trusted user input.

Review Checklist

  • Is an attribute the simplest clear tool?
  • Is there a consumer?
  • Are targets and repeatability correct?
  • Is the class immutable and typed?
  • Are tests focused on behavior?

Examples

Good Example

// app/Attributes/RequiresPlan.php
namespace App\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
final readonly class RequiresPlan
{
    public function __construct(public string $plan = 'basic') {}
}
// app/Http/Middleware/CheckPlanSubscription.php
namespace App\Http\Middleware;

use Closure;
use ReflectionClass;
use App\Attributes\RequiresPlan;
use Illuminate\Http\Request;

final class CheckPlanSubscription
{
    public function handle(Request $request, Closure $next)
    {
        $controller = $request->route()?->controller;
        if (! $controller) {
            return $next($request);
        }

        // Use reflection to check for attribute on controller class
        $reflection = new ReflectionClass($controller);
        $attribute = $reflection->getAttributes(RequiresPlan::class)[0] ?? null;

if ($attribute) {
            $requiresPlan = $attribute->newInstance();
            if (! $request->user()?->subscribed($requiresPlan->plan)) {
                abort(403, 'Subscription Plan Required');
            }
        }

        return $next($request);
    }
}

Bad Example

// ❌ Constructing custom reflection tags, dynamic execution inside constructor, no targeting filters.
#[Attribute]
class RequiresPlan {
    public function __construct($plan) {
        if (!auth()->user()->subscribed($plan)) {
            redirect('/billing'); // DO NOT run side-effects inside 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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager