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

Metadata Laravel Package

fsi/metadata

DEPRECATED: do not use. FSi Metadata Component reads class configuration metadata from sources like annotations (currently PHP annotations only). Provides a ClassMetadata object and abstract drivers (e.g., annotation driver) to store class/property/method metadata.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel

  1. Install Dependencies:

    composer require doctrine/annotations symfony/yaml spatie/array-to-xml
    

    (Note: fsi/metadata is deprecated; use this as a reference for similar functionality.)

  2. Create a Custom Driver (Laravel-compatible):

    // app/Metadata/AnnotationDriver.php
    namespace App\Metadata;
    
    use Doctrine\Common\Annotations\AnnotationReader;
    use FSi\Component\Metadata\Driver\AbstractAnnotationDriver;
    use FSi\Component\Metadata\ClassMetadataInterface;
    
    class AnnotationDriver extends AbstractAnnotationDriver
    {
        public function __construct(private AnnotationReader $reader) {}
    
        public function loadClassMetadata(ClassMetadataInterface $metadata): void
        {
            $reflection = $metadata->getClassReflection();
            foreach ($reflection->getProperties() as $property) {
                foreach ($this->reader->getPropertyAnnotations($property) as $annotation) {
                    $metadata->addPropertyMetadata(
                        $property->name,
                        $annotation->name,
                        $annotation->value
                    );
                }
            }
        }
    }
    
  3. Register in Laravel:

    // app/Providers/MetadataServiceProvider.php
    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    use App\Metadata\AnnotationDriver;
    use Doctrine\Common\Annotations\AnnotationReader;
    use FSi\Component\Metadata\MetadataFactory;
    use Illuminate\Contracts\Cache\Store;
    
    class MetadataServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton(AnnotationReader::class, fn() => new AnnotationReader());
            $this->app->singleton(AnnotationDriver::class, fn($app) =>
                new AnnotationDriver($app->make(AnnotationReader::class))
            );
            $this->app->singleton(MetadataFactory::class, fn($app) =>
                new MetadataFactory(
                    $app->make(AnnotationDriver::class),
                    $app->make(Store::class),
                    'laravel-metadata'
                )
            );
        }
    }
    
  4. First Usage:

    // In a controller or service
    $metadata = app(MetadataFactory::class)->getClassMetadata(\App\Models\User::class);
    $emailRule = $metadata->getPropertyMetadata('email', 'Field');
    

Implementation Patterns

1. Annotation-Driven Workflows

  • Use Case: Replace hardcoded logic (e.g., validation, API responses) with annotations.
    // app/Models/User.php
    namespace App\Models;
    
    use FSi\Component\Metadata\Annotation\Field;
    
    class User
    {
        #[Field(name: "email", value: "required|email")]
        public string $email;
    }
    
  • Pattern: Load metadata in a service provider or model boot method:
    // app/Providers/AppServiceProvider.php
    public function boot()
    {
        $factory = app(MetadataFactory::class);
        $userMetadata = $factory->getClassMetadata(User::class);
        // Cache or process metadata globally.
    }
    

2. YAML/XML Configuration

  • Use Case: Externalize class configurations (e.g., feature flags, caching policies).
    # config/metadata/user.yml
    App\Models\User:
      properties:
        email:
          Field: { name: "email", value: "required|email" }
    
  • Pattern: Create a YamlDriver (extend AbstractDriver):
    class YamlDriver extends AbstractDriver
    {
        public function loadClassMetadata(ClassMetadataInterface $metadata): void
        {
            $config = yaml_parse_file(config_path('metadata/' . $metadata->getClassName() . '.yml'));
            // Parse YAML into metadata.
        }
    }
    

3. Caching Strategies

  • Laravel Cache Adapter:
    $cache = new LaravelCacheAdapter(app('cache.store'));
    $factory = new MetadataFactory($driver, $cache, 'laravel-metadata');
    
  • Cache Invalidation: Clear cache on class changes (e.g., updated: models event):
    event(new ModelUpdated(User::class));
    // In event listener:
    app('cache')->forget('laravel-metadata-' . User::class);
    

4. Custom Metadata Classes

  • Use Case: Extend ClassMetadataInterface for domain-specific data (e.g., CMS fields).
    class CmsMetadata implements ClassMetadataInterface
    {
        public function addFieldMetadata(string $name, array $config): void
        {
            // Custom logic.
        }
    }
    
  • Pattern: Pass class name to MetadataFactory:
    $factory = new MetadataFactory($driver, $cache, 'prefix', CmsMetadata::class);
    

5. Integration with Laravel Features

  • Dynamic API Resources:
    // app/Http/Resources/UserResource.php
    public function toArray($request)
    {
        $metadata = app(MetadataFactory::class)->getClassMetadata(User::class);
        $fields = $metadata->getPropertyMetadata('email', 'Field')['value'] ?? [];
        return ['email' => $this->email, 'rules' => $fields];
    }
    
  • Form Request Validation:
    // app/Http/Requests/StoreUserRequest.php
    public function rules()
    {
        $metadata = app(MetadataFactory::class)->getClassMetadata(User::class);
        $rules = [];
        foreach ($metadata->getPropertyMetadata('email', 'Field') as $value) {
            $rules['email'][] = $value;
        }
        return $rules;
    }
    

Gotchas and Tips

Pitfalls

  1. Deprecation Risk:

    • The package is abandoned. Fork or migrate to Laravel’s Attribute + Reflection for long-term use.
    • Workaround: Use doctrine/annotations directly with a custom AnnotationReader wrapper.
  2. Symfony Dependencies:

    • AnnotationReader and Doctrine\Common\Cache are Symfony-centric. Laravel requires adapters:
      // Adapter for Doctrine Cache
      class LaravelCacheAdapter implements \Doctrine\Common\Cache\Cache
      {
          public function fetch($id) { return app('cache')->get($id); }
          public function save($id, $data, $lifeTime = 0) { return app('cache')->put($id, $data, $lifeTime); }
          // Implement remaining methods...
      }
      
  3. Performance Overhead:

    • Reflection is slow. Cache metadata aggressively:
      $factory = new MetadataFactory($driver, app('cache.store'), 'laravel-metadata', null, 3600); // 1-hour TTL
      
  4. Annotation Conflicts:

    • Laravel’s #[Attribute] (PHP 8+) and Symfony’s @Annotation may clash. Use namespaced annotations:
      namespace App\Metadata\Annotation;
      #[Attribute(Attribute::TARGET_PROPERTY)]
      class Field {}
      
  5. YAML/XML Parsing:

    • Laravel lacks native YAML/XML parsers. Add dependencies:
      composer require symfony/yaml spatie/array-to-xml
      
    • Tip: Parse YAML/XML once at boot (e.g., in AppServiceProvider) and store in Laravel’s cache.

Debugging Tips

  1. Metadata Not Loading?

    • Verify the driver’s loadClassMetadata is called. Add logging:
      public function loadClassMetadata(ClassMetadataInterface $metadata): void
      {
          logger()->debug('Loading metadata for:', [$metadata->getClassName()]);
          // ...
      }
      
  2. Cache Issues:

    • Clear Laravel’s cache and metadata cache:
      php artisan cache:clear
      php artisan metadata:clear  # Custom artisan command
      
  3. Annotation Reader Errors:

    • Ensure annotations are properly namespaced and use #[Attribute] (PHP 8+) or @Annotation (legacy).
    • Fix: Autoload annotations:
      $reader = new AnnotationReader();
      $reader->addNamespace('App\Metadata\Annotation');
      

Extension Points

  1. Add New Drivers:

    • Extend AbstractDriver for JSON, TOML, or database-backed metadata:
      class DatabaseDriver extends AbstractDriver
      {
          public function loadClassMetadata(ClassMetadataInterface $metadata): void
          {
              $config = DB::table('metadata')->where('class', $metadata->getClassName())->first();
              // Parse $config into metadata.
          }
      }
      
  2. Custom Metadata Storage:

    • Override ClassMetadataInterface to store metadata in a database or Redis:
      class RedisMetadata implements ClassMetadataInterface
      {
          public function __construct(private \Illuminate\Redis\Connections\Connection $redis) {}
      
          public function getProperty
      
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.
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
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