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

Property Info Laravel Package

symfony/property-info

Symfony PropertyInfo component extracts metadata about PHP class properties—types, access, docs, and more—by reading popular sources like PHPDoc, reflection, and other metadata providers. Useful for serializers, validators, and API tooling.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

Install via Composer:

composer require symfony/property-info

First Use Case: Extracting Property Types

use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;

// Create extractor (combines multiple strategies)
$extractor = new PropertyInfoExtractor([
    new PhpDocExtractor(), // Handles @var, @return, etc.
    new ReflectionExtractor(), // Falls back to reflection
]);

// Get type info for a class property
$class = new \stdClass();
$propertyName = 'someProperty';
$typeInfo = $extractor->getTypes($class, $propertyName);

Key Entry Points

  • PropertyInfoExtractor: Main class combining multiple extractors.
  • Extractors:
    • PhpDocExtractor: Parses PHPDoc annotations.
    • ReflectionExtractor: Uses PHP reflection.
    • PhpStanExtractor: Integrates with PHPStan for advanced type resolution.
    • DoctrineExtractor: For Doctrine annotations.

Implementation Patterns

Common Workflows

1. Type Resolution for Validation

use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;

// In a validator or form type
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $extractor = $this->container->get(PropertyInfoExtractorInterface::class);
    $type = $extractor->getTypes($options['data'], 'propertyName')[0] ?? null;

    if ($type === 'DateTime') {
        $builder->add('propertyName', DateType::class);
    }
}

2. Dynamic Form Field Mapping

// Map form fields based on property types
$extractor = new PropertyInfoExtractor([new PhpDocExtractor()]);
$types = $extractor->getTypes($entity, 'property');

$fieldType = match ($types[0] ?? null) {
    'string' => TextType::class,
    'integer' => IntegerType::class,
    'boolean' => CheckboxType::class,
    default => TextType::class,
};

3. API Response Transformation

// Convert entity to array with typed values
$extractor = new PropertyInfoExtractor([new ReflectionExtractor()]);
$types = $extractor->getTypes($entity, 'property');

$value = $entity->property;
$serialized = match ($types[0] ?? null) {
    'DateTime' => $value->format('Y-m-d'),
    'Collection' => array_map(fn($item) => $item->id, $value->toArray()),
    default => $value,
};

4. Custom Extractor Integration

use Symfony\Component\PropertyInfo\Extractor\ExtractorInterface;

class CustomExtractor implements ExtractorInterface
{
    public function getTypes(object $object, string $property): array
    {
        // Custom logic (e.g., database schema, YAML config)
        return ['App\\CustomType'];
    }
}

// Register with the main extractor
$extractor = new PropertyInfoExtractor([
    new CustomExtractor(),
    new PhpDocExtractor(),
]);

Integration Tips

Laravel-Specific Patterns

  1. Service Provider Binding

    // In AppServiceProvider
    public function register()
    {
        $this->app->bind(PropertyInfoExtractorInterface::class, function () {
            return new PropertyInfoExtractor([
                new PhpDocExtractor(),
                new ReflectionExtractor(),
                new PhpStanExtractor(), // Optional: if using PHPStan
            ]);
        });
    }
    
  2. Dynamic Validation Rules

    // In a Form Request
    public function rules()
    {
        $extractor = app(PropertyInfoExtractorInterface::class);
        $types = $extractor->getTypes($this->entity, 'attribute');
    
        $rules = [];
        foreach ($types as $type) {
            if ($type === 'email') {
                $rules['attribute'] = 'required|email';
            } elseif ($type === 'date') {
                $rules['attribute'] = 'required|date';
            }
        }
        return $rules;
    }
    
  3. API Resource Transformation

    // In a Fractal transformer
    public function transform($entity)
    {
        $extractor = app(PropertyInfoExtractorInterface::class);
        $types = $extractor->getTypes($entity, 'property');
    
        return [
            'property' => $this->formatValue($entity->property, $types[0] ?? null),
        ];
    }
    

Performance Considerations

  • Cache Extracted Types: Store results in memory or Redis for repeated calls.
    $cache = new \Symfony\Component\Cache\SimpleCache();
    $extractor = new PropertyInfoExtractor([...], $cache);
    
  • Prioritize Extractors: Place faster extractors (e.g., ReflectionExtractor) before slower ones (e.g., PhpStanExtractor).

Gotchas and Tips

Pitfalls

  1. Extractor Order Matters

    • Extractors are evaluated in order, and the first match wins.
    • Fix: Reorder extractors to prioritize the most reliable source (e.g., PhpStanExtractor before PhpDocExtractor).
  2. PHPStan Conflicts

    • Issue: phpdocumentor/reflection-docblock v6+ causes conflicts.
    • Fix: Downgrade to phpdocumentor/reflection-docblock:^5.0 or use the PhpStanExtractor carefully.
      composer require phpdocumentor/reflection-docblock:^5.0
      
  3. Promoted Properties

    • Issue: DocBlock parsing fails for promoted properties (PHP 8.0+).
    • Fix: Use PhpStanExtractor or ensure @var tags are present.
      class User {
          public function __construct(
              public string $name, // Promoted property
          ) {}
      }
      /**
       * @var string
       */
      public $name; // Explicit docblock fallback
      
  4. Nullable Types

    • Issue: mixed[] or ?array may not resolve as expected.
    • Fix: Normalize types post-extraction:
      $type = str_replace('[]', '', $extractedType);
      $type = str_replace('?', '', $type); // Handle nullable
      
  5. Self/Parent Type Resolution

    • Issue: self or parent in DocBlocks may fail.
    • Fix: Use PhpStanExtractor or resolve manually:
      $reflectionClass = new \ReflectionClass($object);
      $parentClass = $reflectionClass->getParentClass();
      
  6. Underscore-Only Properties

    • Issue: Properties like __token may be skipped.
    • Fix: Ensure ReflectionExtractor is included.

Debugging Tips

  1. Inspect Extracted Types

    $extractor = new PropertyInfoExtractor([...]);
    $types = $extractor->getTypes($object, 'property');
    dump($types); // Debug output
    
  2. Enable Verbose Logging

    $extractor = new PropertyInfoExtractor([...], null, [
        'debug' => true,
    ]);
    
  3. Test Edge Cases

    • Promoted properties: Ensure @var tags work.
    • Generic types: Test ArrayObject, Collection.
    • Interfaces/Traits: Verify inheritance works.

Extension Points

  1. Custom Type Resolvers

    use Symfony\Component\PropertyInfo\Type;
    
    $extractor = new PropertyInfoExtractor([...]);
    $type = $extractor->getType($object, 'property');
    
    if ($type instanceof Type && $type->getClassName() === 'App\\CustomType') {
        // Handle custom logic
    }
    
  2. Override Default Extractors

    $extractor = new PropertyInfoExtractor([
        new class implements ExtractorInterface {
            public function getTypes(object $object, string $property): array
            {
                return ['App\\OverriddenType'];
            }
        },
    ]);
    
  3. Add Metadata Sources

    • Integrate with Doctrine, API Platform, or Neomerx/JsonApi.
    • Example for Doctrine:
      use Doctrine\Common\Annotations\Reader;
      
      $annotationReader = new Reader();
      $extractor = new PropertyInfoExtractor([
          new DoctrineExtractor($annotationReader),
      ]);
      
  4. Leverage PropertyDescription

    $description = $extractor->getProperties($object);
    foreach ($description as $property => $info) {
        if ($info->isWritable()) {
            // Handle writable properties
        }
    }
    

Laravel-Specific Gotchas

  1. Eloquent Model Properties
    • Issue: hasMany, belongsTo relations may not resolve correctly.
    • Fix: Use PhpStanExtractor or add custom
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport