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

Class Meta Bundle Laravel Package

ashleydawson/class-meta-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require ashleydawson/class-meta-bundle
    

    Register the bundle in config/bundles.php (Symfony 4+):

    return [
        // ...
        AshleyDawson\ClassMetaBundle\AshleyDawsonClassMetaBundle::class => ['all' => true],
    ];
    
  2. First Use Case: Annotate a class/constant (e.g., src/Entity/Status.php):

    namespace App\Entity;
    
    /**
     * @ClassMeta(title="User Status", description="Defines user account statuses")
     */
    class Status
    {
        /**
         * @ConstantMeta(title="Active", description="User is active")
         */
        const ACTIVE = 1;
    
        /**
         * @ConstantMeta(title="Suspended", description="User is suspended")
         */
        const SUSPENDED = 2;
    }
    
  3. Access Metadata: Inject the service in a controller/service:

    use AshleyDawson\ClassMetaBundle\ClassMeta\ClassMetaManager;
    
    class StatusController
    {
        public function __construct(private ClassMetaManager $metaManager) {}
    
        public function listStatuses()
        {
            $meta = $this->metaManager->getClassMeta(Status::class);
            $constantsMeta = $this->metaManager->getClassConstantsMeta(Status::class);
    
            return [
                'class' => $meta,
                'constants' => $constantsMeta,
            ];
        }
    }
    

Implementation Patterns

Common Workflows

  1. Domain-Driven Design (DDD) Value Objects: Attach metadata to value objects (e.g., Money, Email) for runtime validation or UI hints:

    /**
     * @ClassMeta(
     *     title="Monetary Value",
     *     validation="amount > 0",
     *     ui={ "type": "currency", "symbol": "$" }
     * )
     */
    class Money { ... }
    
  2. Dynamic Forms/CRUD: Use metadata to generate forms dynamically:

    $formFields = [];
    foreach ($this->metaManager->getClassConstantsMeta(UserRole::class) as $constant => $meta) {
        $formFields[] = [
            'name' => $constant,
            'label' => $meta['title'],
            'type' => 'checkbox',
        ];
    }
    
  3. API Documentation: Auto-generate Swagger/OpenAPI specs from @ClassMeta/@ConstantMeta:

    $schema = [
        'type' => 'object',
        'properties' => [],
    ];
    foreach ($this->metaManager->getClassConstantsMeta(OrderStatus::class) as $constant => $meta) {
        $schema['properties'][$constant] = [
            'type' => 'string',
            'enum' => [$constant],
            'description' => $meta['description'] ?? '',
        ];
    }
    
  4. Scoped Constants: Use scoped annotation to group constants logically:

    /**
     * @ClassMeta(scoped=true)
     */
    class Permission {
        /**
         * @ConstantMeta(scope="admin")
         */
        const MANAGE_USERS = 'admin.manage_users';
    
        /**
         * @ConstantMeta(scope="user")
         */
        const EDIT_PROFILE = 'user.edit_profile';
    }
    

    Access scoped metadata:

    $adminPermissions = $this->metaManager->getScopedClassConstantsMeta(Permission::class, 'admin');
    
  5. Dependency Injection Integration: Tag services to process metadata during compilation (Symfony 4+):

    services:
        App\Metadata\Processor\ClassMetaProcessor:
            tags: [class_meta.processor]
    

Gotchas and Tips

Pitfalls

  1. Cache Invalidation:

    • The bundle uses file modification time for cache invalidation by default. If metadata changes aren’t reflected, clear the cache:
      php bin/console cache:clear
      
    • For production, configure a persistent cache (e.g., FilesystemCache or ApcuCache) with a reasonable TTL (e.g., 3600 seconds).
  2. Annotation Parsing:

    • The bundle relies on Symfony’s annotation system. If annotations are ignored:
      • Ensure classes are autoloaded (e.g., src/ directory is in autoload-dev in composer.json).
      • Verify PHP 7.1+ and Symfony 3.0+/4.0+ compatibility (check composer.json constraints).
  3. Scoped Constants:

    • Scoped constants require scoped=true on the class and a scope value on each constant. Omitting either will exclude them from scoped queries.
  4. Performance:

    • Avoid fetching metadata in tight loops (e.g., per-request). Cache results in your service layer if reused frequently:
      private $cachedMeta = [];
      
      public function getCachedClassMeta(string $class): array
      {
          return $this->cachedMeta[$class] ??= $this->metaManager->getClassMeta($class);
      }
      
  5. Symfony 5+ Deprecations:

    • The bundle is unmaintained (last release 2019). For Symfony 5.4+, consider:
      • Using symfony/property-info + custom annotations.
      • Forking the bundle to update dependencies (e.g., symfony/dependency-injection).

Debugging Tips

  1. Verify Annotations: Use Symfony’s AnnotationReader to debug:

    $reader = new \Doctrine\Common\Annotations\AnnotationReader();
    $reflectionClass = new \ReflectionClass(Status::class);
    $classAnnotation = $reader->getClassAnnotation($reflectionClass, ClassMeta::class);
    
  2. Cache Debugging: Temporarily disable caching by configuring VoidCache:

    ashley_dawson_class_meta:
        cache_provider_service_id: doctrine.cache.null
    
  3. Annotation Syntax:

    • Use @ClassMeta() for empty values (e.g., @ClassMeta() vs @ClassMeta(title="")).
    • Multi-line annotations may break parsing. Use single-line or YAML-style:
      /** @ClassMeta({"title": "Multi-line", "description": "Works"}) */
      

Extension Points

  1. Custom Annotation Parsers: Extend AshleyDawson\ClassMeta\Annotation\ClassMetaReader to support custom annotation formats (e.g., PHPDoc tags).

  2. Metadata Processors: Implement AshleyDawson\ClassMetaBundle\DependencyInjection\Compiler\ClassMetaProcessorInterface to transform metadata during container compilation:

    public function process(array $meta): array
    {
        $meta['processed'] = true;
        return $meta;
    }
    
  3. Cache Providers: Create a custom cache provider (e.g., Redis) by implementing Doctrine\Common\Cache\CacheProvider.

  4. Integration with Doctrine: Use metadata to customize ORM behavior (e.g., dynamic enum types):

    $platform = $this->metaManager->getClassMeta(OrderStatus::class)['platform'] ?? 'string';
    $platform->registerDoctrineTypeMapping(OrderStatus::class, 'enum');
    
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.
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
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle