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 Access Laravel Package

symfony/property-access

Symfony PropertyAccess lets you read and write values on objects and arrays using a simple property-path string syntax. Supports nested properties, indexed access, getters/setters, and safe navigation for flexible data mapping and forms.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/property-access
    

    Add to composer.json if using Laravel Mix or Vite (though this is a PHP package).

  2. First Use Case: Access nested properties in an object or array using a dot-notation path.

    use Symfony\Component\PropertyAccess\PropertyAccess;
    use Symfony\Component\PropertyAccess\PropertyAccessor;
    
    // Create an accessor instance
    $accessor = PropertyAccess::createPropertyAccessor();
    
    // Example object
    $user = new class {
        public $name = 'John';
        public $profile = [
            'address' => [
                'street' => '123 Main St',
                'city' => 'Metropolis'
            ]
        ];
    };
    
    // Read a nested value
    $city = $accessor->getValue($user, 'profile.address.city');
    // Returns: 'Metropolis'
    
    // Write a nested value
    $accessor->setValue($user, 'profile.address.city', 'Gotham');
    
  3. Where to Look First:


Implementation Patterns

Core Workflows

1. Reading Nested Data

Use getValue() to traverse objects/arrays with dot notation.

$accessor = PropertyAccess::createPropertyAccessor();
$value = $accessor->getValue($entity, 'path.to.nested.property');

Common Use Cases:

  • Form Handling: Extract nested values from request data.
    $data = $request->all();
    $city = $accessor->getValue($data, 'user.address.city');
    
  • DTO Hydration: Populate objects from arrays.
    $dto = new UserDto();
    $accessor->setValue($dto, 'profile.email', $arrayData['email']);
    
  • API Responses: Normalize nested data for JSON output.
    $responseData['user']['address']['city'] = $accessor->getValue($user, 'address.city');
    

2. Writing Nested Data

Use setValue() to update nested properties.

$accessor->setValue($object, 'path.to.property', $newValue);

Example: Dynamic Updates

$rules = ['user.address.city' => 'required|string'];
foreach ($rules as $path => $validation) {
    $accessor->setValue($formData, $path, $request->input(explode('.', $path)));
}

3. Integration with Laravel

  • Service Container Binding:

    $this->app->singleton(PropertyAccessor::class, function () {
        return PropertyAccess::createPropertyAccessor();
    });
    

    Then inject PropertyAccessor into controllers/services.

  • Form Request Validation:

    use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
    
    public function rules()
    {
        return [
            'user.address.city' => 'required|string',
        ];
    }
    
    public function withValidator($validator)
    {
        $accessor = app(PropertyAccessorInterface::class);
        $validator->after(function ($validator) use ($accessor) {
            $data = $validator->getData();
            $accessor->setValue($data, 'user.address.city', strtoupper($data['user']['address']['city']));
        });
    }
    

4. Handling Arrays and Objects

The package automatically handles both:

$array = ['user' => ['name' => 'Alice']];
$accessor->getValue($array, 'user.name'); // 'Alice'

$object = new stdClass();
$object->user = (object)['name' => 'Bob'];
$accessor->getValue($object, 'user.name'); // 'Bob'

5. Custom Accessors

Extend functionality with custom type hints or logic:

$accessor = PropertyAccess::createPropertyAccessorBuilder()
    ->enableExceptionOnInvalidIndex()
    ->enableMagicAccessor()
    ->getPropertyAccessor();

Integration Tips

  1. Performance Optimization:

    • Cache the PropertyAccessor instance as a singleton in Laravel’s service container.
    • For hot paths, pre-compile property paths using PropertyPath:
      $path = PropertyPath::fromString('user.profile.address');
      $accessor->getValue($data, $path);
      
  2. Error Handling:

    • Configure behavior for invalid paths:
      $accessor = PropertyAccess::createPropertyAccessorBuilder()
          ->setExceptionOnInvalidIndex(true) // Throw \InvalidArgumentException
          ->setExceptionOnInvalidPropertyPath(true)
          ->getPropertyAccessor();
      
    • Use isReadable()/isWritable() to check path validity before access:
      if ($accessor->isReadable($data, 'user.address.city')) {
          $city = $accessor->getValue($data, 'user.address.city');
      }
      
  3. Laravel-Specific Patterns:

    • Eloquent Models:
      $user = User::find(1);
      $city = $accessor->getValue($user, 'address.city');
      
    • API Resources:
      public function toArray($request)
      {
          return [
              'address' => [
                  'city' => $this->accessor->getValue($this->resource, 'address.city'),
              ],
          ];
      }
      
  4. Testing:

    • Mock PropertyAccessor in unit tests:
      $mockAccessor = $this->createMock(PropertyAccessorInterface::class);
      $mockAccessor->method('getValue')->with($obj, 'path')->willReturn('value');
      
    • Test edge cases: missing paths, circular references, and mixed arrays/objects.

Gotchas and Tips

Pitfalls

  1. Getter/Setter Ambiguity:

    • The package prioritizes public properties over getter methods if both exist with the same name.
    • Fix: Use explicit paths or configure the accessor:
      $accessor = PropertyAccess::createPropertyAccessorBuilder()
          ->getPropertyAccessor();
      // Defaults to properties > getters for same-named access.
      
  2. Circular References:

    • Accessing circularly referenced objects (e.g., A->B->A) may cause infinite loops.
    • Solution: Use enableExceptionOnCircularReference() or handle manually.
  3. PHP 8.4+ Asymmetric Visibility:

    • The package supports PHP 8.4’s asymmetric visibility (e.g., public getName(): string).
    • Note: Older PHP versions may require pinned versions (e.g., ^6.4 for PHP 7.4).
  4. Array vs. Object Behavior:

    • Arrays use index-based access (e.g., array[0]), while objects use property/method access.
    • Gotcha: Mixed structures (e.g., ['key' => (object)[]]) may behave unexpectedly.
    • Tip: Normalize data to objects/arrays before access if consistency is critical.
  5. Performance Overhead:

    • Reflection is used under the hood, which can be slow for frequent access.
    • Mitigation:
      • Cache the PropertyAccessor instance.
      • Pre-compile paths for hot loops:
        $path = PropertyPath::fromString('user.address.city');
        foreach ($users as $user) {
            $accessor->getValue($user, $path); // Faster than string paths
        }
        
  6. Case Sensitivity:

    • Property paths are case-sensitive by default (e.g., user.Nameuser.name).
    • Workaround: Normalize case or use PropertyPath::fromString() with custom normalization.

Debugging Tips

  1. Enable Debug Mode:

    • Set PropertyAccess::DEBUG to log access attempts:
      define('PropertyAccess::DEBUG', true);
      
    • Check logs for failed paths or ambiguous access.
  2. Validate Paths:

    • Use isReadable()/isWritable() to debug invalid paths:
      if (!$accessor->isReadable($data, 'user.address.city')) {
          dd('Invalid path: user.address.city');
      }
      
  3. Common Errors:

    • \InvalidArgumentException: Invalid path or missing property.
      • Check for typos in the path string.
      • Verify the object/array structure matches the path.
    • \RuntimeException: Circular references or unsupported types.
      • Use enableExceptionOnCircularReference() to catch these early.
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