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

Util Accessor Laravel Package

phrity/util-accessor

Access nested data (arrays, objects, scalars) using simple slash-delimited paths. Provides get() with optional default return and type coercion, plus has() to check if a path exists. Lightweight utility for safe, convenient data retrieval.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require phrity/util-accessor
    
  2. First Use Case: Access nested data in Eloquent models or arrays without manual traversal:

    use Phrity\Util\Accessor;
    
    $accessor = new Accessor();
    $user = User::find(1);
    $email = $accessor->get($user, 'profile/email'); // Access nested attribute
    

Laravel Integration

For Eloquent models, pair with a trait (custom implementation):

use Phrity\Util\AccessorTrait;

class User extends Model
{
    use AccessorTrait;

    public function getFullNameAttribute()
    {
        return $this->accessorGet($this->attributes, 'first_name') .
               ' ' . $this->accessorGet($this->attributes, 'last_name');
    }
}

Implementation Patterns

Core Workflows

  1. Dynamic Attribute Access: Replace manual array/object traversal with path-based access:

    $accessor = new Accessor();
    $value = $accessor->get($model->toArray(), 'address/city');
    
  2. Form Request Validation: Validate nested request data:

    public function rules()
    {
        return [
            'user.address.city' => 'required|string',
        ];
    }
    // Parse with:
    $accessor->has($request->all(), 'user/address/city');
    
  3. API Response Transformation: Use DataAccessor to normalize responses:

    $response = new DataAccessor($user->toArray());
    return response()->json([
        'data' => [
            'name' => $response->get('profile/name'),
            'email' => $response->get('profile/email'),
        ],
    ]);
    

Laravel-Specific Patterns

  • Service Container Binding: Bind the accessor as a singleton for global use:

    $app->singleton(Accessor::class, fn($app) => new Accessor());
    
  • Model Observers: Use PathAccessor to standardize attribute access in observers:

    class UserObserver
    {
        protected $accessor;
    
        public function __construct()
        {
            $this->accessor = new PathAccessor('profile/email');
        }
    
        public function saving(User $user)
        {
            $user->setAttribute('profile_email', $this->accessor->get($user->toArray()));
        }
    }
    
  • API Resource Customization: Extend JsonResource to use DataAccessor for consistent serialization:

    public function toArray($request)
    {
        $accessor = new DataAccessor(parent::toArray($request));
        return [
            'data' => [
                'name' => $accessor->get('name'),
                'metadata' => $accessor->get('metadata/*'),
            ],
        ];
     }
    

Gotchas and Tips

Pitfalls

  1. Immutable Objects: set() fails on immutable objects (e.g., stdClass with __set restrictions). Use DataAccessor for mutable copies:

    $dataAccessor = new DataAccessor($immutableObject);
    $dataAccessor->set('path/to/value', 'new_value');
    $updatedData = $dataAccessor->getSubject();
    
  2. Circular References: Deep cloning may fail with circular references. Use unserialize() as a fallback:

    $accessor->get($subject, 'path', clone: false);
    
  3. Type Coercion Edge Cases: Custom transformers may not handle null inputs. Add null checks:

    $accessor = new Accessor(new FirstMatchResolver([
        new NullSafeTransformer(), // Custom wrapper
        new BasicTypeConverter(),
    ]));
    

Debugging

  • Path Parsing Errors: Use accessorParsePath() to validate paths before runtime:

    $path = $this->accessorParsePath('invalid#path', '#');
    if ($path === false) {
        throw new \InvalidArgumentException('Invalid path format');
    }
    
  • Performance Bottlenecks: Profile get() calls with nested paths. Consider flattening data structures:

    // Before:
    $accessor->get($user, 'profile/address/city');
    
    // After (pre-computed):
    $user->setAttribute('profile_city', $user->profile->address->city);
    

Configuration Quirks

  1. Custom Separators: Override the default / separator globally via a service provider:

    $app->bind(Accessor::class, fn() => new Accessor('.'));
    
  2. Transformer Conflicts: Order matters in FirstMatchResolver. Place stricter transformers first:

    $transformer = new FirstMatchResolver([
        new EnumConverter(),       // High priority
        new StringableConverter(), // Lower priority
    ]);
    

Extension Points

  1. Custom Accessor Classes: Extend Accessor to add domain-specific logic:

    class ModelAccessor extends Accessor
    {
        public function getRelation($subject, string $path, $default = null)
        {
            $relation = $this->get($subject, $path, $default);
            return $relation instanceof Model ? $relation->fresh() : $relation;
        }
    }
    
  2. Path Validation: Add a validator for API paths:

    use Phrity\Util\Accessor;
    
    class PathValidator extends FormRequest
    {
        public function rules()
        {
            return [
                'path' => ['required', function ($attribute, $value, $fail) {
                    $accessor = new Accessor();
                    if ($accessor->accessorParsePath($value) === false) {
                        $fail('The '.$attribute.' must be a valid access path.');
                    }
                }],
            ];
        }
    }
    
  3. Event-Driven Access: Dispatch events for accessor operations:

    $accessor = new Accessor();
    event(new AccessorAttempted(
        $subject,
        $path,
        $accessor->has($subject, $path)
    ));
    

Laravel-Specific Tips

  • Cache Accessors: Cache computed accessors in model events:

    protected static function booted()
    {
        static::retrieved(function ($model) {
            if (!$model->offsetExists('cached_accessor')) {
                $model->cached_accessor = $model->accessorGet(
                    $model->toArray(),
                    'heavy/path',
                    fn() => Cache::remember('heavy.path', 3600, fn() => $model->computeHeavyPath())
                );
            }
        });
    }
    
  • Policy Integration: Use accessors in policies for authorization:

    public function update(User $user, User $model)
    {
        return $user->can('edit_profile') &&
               $this->accessor->has($model->toArray(), 'profile/role') &&
               $model->profile->role === 'admin';
    }
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity