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 notation. It supports nested access, getters/setters, and array indexes, making data mapping and form handling easier.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require symfony/property-access
    

    For Laravel, prefer using symfony/property-access directly or via Symfony’s PropertyAccessComponent if using other Symfony components.

  2. Basic Usage:

    use Symfony\Component\PropertyAccess\PropertyAccess;
    use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
    
    $accessor = PropertyAccess::createPropertyAccessor();
    $data = ['user' => ['name' => 'John', 'age' => 30]];
    
    // Read
    $name = $accessor->getValue($data, '[user][name]'); // 'John'
    // Write
    $accessor->setValue($data, '[user][age]', 31);
    
  3. First Use Case: Replace manual nested property access in a Laravel controller or service:

    // Before
    $user = $request->user();
    $city = $user->getAddress()->getCity();
    
    // After
    $city = $accessor->getValue($user, 'address.city');
    

Where to Look First

  • Official Documentation (API reference, path syntax).
  • PropertyAccessorInterface for type-hinted usage in services.
  • Path Syntax Guide (e.g., [array][keys], object.property, getter()).

Implementation Patterns

Core Workflows

1. Dynamic Data Access in APIs

// Laravel API Request Handling
public function update(Request $request, User $user) {
    $accessor = PropertyAccess::createPropertyAccessor();
    $data = $request->all();

    // Update nested user data
    $accessor->setValue($user, 'profile.settings.notifications', $data['notifications']);

    // Return transformed response
    return response()->json([
        'user' => $accessor->getValue($user, 'profile')
    ]);
}

2. Form Handling with Nested Fields

// Laravel Form Request Validation
public function rules() {
    return [
        'user.profile.address.city' => 'required|string',
        'user.preferences.theme' => 'nullable|string'
    ];
}

// Access form data dynamically
$city = $accessor->getValue($request->all(), '[user][profile][address][city]');

3. DTO Mapping

// Transform API payload to domain object
$dto = new UserProfileDTO();
$accessor->setValue($dto, 'fullName', $accessor->getValue($payload, 'user.name'));
$accessor->setValue($dto, 'age', $accessor->getValue($payload, 'user.age'));

4. Configuration Systems

// Dynamic feature flags
$config = config('features');
$isEnabled = $accessor->getValue($config, 'user.tier.discount');

Integration Tips

Laravel Facade Wrapper

Create a facade to simplify usage:

// app/Providers/AppServiceProvider.php
use Symfony\Component\PropertyAccess\PropertyAccess;

public function register() {
    $this->app->singleton('property-access', function () {
        return PropertyAccess::createPropertyAccessor();
    });
}

// app/Facades/PropertyAccess.php
namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class PropertyAccess extends Facade {
    protected static function getFacadeAccessor() {
        return 'property-access';
    }
}

// Usage
$value = PropertyAccess::getValue($object, 'nested.path');

Service Container Binding

Bind the accessor to Laravel’s container for dependency injection:

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

Path Validation

Use PropertyPath to validate paths before access:

use Symfony\Component\PropertyAccess\PropertyPath;

$path = new PropertyPath('user.profile.settings');
if ($accessor->isReadable($object, $path)) {
    $value = $accessor->getValue($object, $path);
}

Caching Accessors

For performance-critical paths (e.g., APIs), cache the accessor:

$accessor = PropertyAccess::createPropertyAccessor();
$accessor->setUsedAttributes(['user.profile', 'user.settings']); // Optimize

Custom Type Support

Extend the accessor for Laravel-specific types (e.g., Carbon, Collection):

$accessor = PropertyAccess::createPropertyAccessor();
$accessor->addType('carbon', function ($value) {
    return $value instanceof \Carbon\Carbon ? $value->format('Y-m-d') : null;
});

Gotchas and Tips

Pitfalls

1. Path Syntax Confusion

  • Arrays: Use [key] notation ([user][name]).
  • Objects: Use property or getter() (address.city or getAddress()).
  • Mixed Structures: Combine with [] for arrays inside objects (user[0].name).
  • Gotcha: Forgetting [] for array keys causes PropertyNotFoundException.

2. Getter/Setter Ambiguity

  • If a property and getter method exist (e.g., name and getName()), the component prioritizes the property by default.
  • To force method calls, use getter() in the path: user.getName().
  • Fix: Use PropertyAccess::createPropertyAccessor()->setUseGetterForMissingProperties(true) to prefer getters.

3. Null or Non-Readable Properties

  • Accessing a non-existent path throws PropertyNotFoundException.
  • Solution: Use isReadable() or isWritable() to check first:
    if ($accessor->isReadable($object, 'user.profile')) {
        $value = $accessor->getValue($object, 'user.profile');
    }
    

4. Performance Overhead

  • Reflection-based access adds ~10–20% overhead. Benchmark in hot paths (e.g., API routes).
  • Optimization: Cache the accessor or use setUsedAttributes() to pre-optimize paths.

5. PHP 8.4+ Features

  • Supports read-only properties and enums, but ensure your Laravel/PHP version aligns.
  • Gotcha: Asymmetric visibility (e.g., public getName(): string) may require explicit path syntax.

6. Security Risks

  • Arbitrary path access can expose sensitive data (e.g., user.password).
  • Mitigation:
    • Whitelist allowed paths.
    • Use PropertyPath validation.
    • Combine with Laravel’s authorization (e.g., Gates/Policies).

Debugging Tips

1. Enable Debug Mode

$accessor = PropertyAccess::createPropertyAccessor();
$accessor->setDebug(true); // Logs path resolution

2. Handle Exceptions

Catch specific exceptions for graceful degradation:

use Symfony\Component\PropertyAccess\Exception\ExceptionInterface;

try {
    $value = $accessor->getValue($object, 'invalid.path');
} catch (ExceptionInterface $e) {
    // Fallback logic
}

3. Common Exceptions

  • PropertyNotFoundException: Path doesn’t exist.
  • InvalidArgumentException: Invalid path syntax.
  • UnexpectedTypeException: Type mismatch (e.g., setting a string to a non-string property).

Extension Points

1. Custom Property Accessors

Implement PropertyAccessorInterface for domain-specific logic:

class CustomAccessor implements PropertyAccessorInterface {
    public function getValue($object, $propertyPath) {
        // Custom logic
    }
    // ... other methods
}

2. Type Extensions

Add support for custom types (e.g., Laravel Collections):

$accessor->addType('collection', function ($value) {
    return $value instanceof \Illuminate\Support\Collection ? $value->toArray() : null;
});

3. Path Transformers

Use PropertyPath to transform paths dynamically:

$path = new PropertyPath('user.profile');
$path->addProperty('settings'); // Transforms to 'user.profile.settings'

4. Integration with Laravel Helpers

Combine with Arr::get() for hybrid array/object access:

$value = $accessor->getValue($array, '[key][nested]');
// or
$value = Arr::get($accessor->getValue($object, 'arrayProperty'), 'key');

Configuration Quirks

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.
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
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope