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

Data Model Laravel Package

zero-to-prod/data-model

Reflection-based PHP data models that hydrate typed objects from arrays with a single from($data) call. Use #[Describe] attributes to define casting, validation, defaults, nullable/required rules, and assignments—keeping mapping logic predictable, readable, and verifiable.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require zero-to-prod/data-model
    
  2. Basic Usage: Add the DataModel trait to any class and define properties with type hints.

    use Zerotoprod\DataModel\DataModel;
    
    class User {
        use DataModel;
    
        public string $name;
        public int $age;
    }
    
    $user = User::from(['name' => 'Alice', 'age' => 30]);
    
  3. First Use Case: Replace manual array-to-object mapping with type-safe hydration:

    $user = User::from($request->all()); // Automatically casts and validates
    

Where to Look First

  • Describe Attribute: Core configuration for property hydration.
  • from() Method: Static factory for instantiation.
  • Type Hints: Leverage PHP’s type system for validation and autocompletion.

Implementation Patterns

Core Workflow

  1. Define Model:
    class User {
        use DataModel;
    
        #[Describe(['required' => true])]
        public string $name;
    
        #[Describe(['default' => 18])]
        public int $age;
    }
    
  2. Hydrate Data:
    $user = User::from($apiResponse);
    
  3. Recursive Hydration:
    class Profile {
        use DataModel;
        public User $user;
    }
    $profile = Profile::from($data); // Automatically hydrates nested `User`
    

Integration Tips

  • Laravel Requests:
    $user = User::from($request->validated());
    
  • API Responses:
    $user = User::from(json_decode($response, true));
    
  • Validation: Combine with Laravel’s ValidatesWhen or custom pre/post hooks.

Common Patterns

  1. Default Values:
    #[Describe(['default' => fn() => now()])]
    public Carbon $createdAt;
    
  2. Custom Casting:
    #[Describe(['cast' => [User::class, 'hashPassword']])]
    public string $password;
    
  3. Nested Collections:
    class Team {
        use DataModel;
        public array $members; // Automatically hydrates array of `User`
    }
    

Gotchas and Tips

Pitfalls

  1. Circular References: Avoid bidirectional relationships (e.g., User->Team and Team->User) without custom via logic.

    #[Describe(['via' => [Team::class, 'fromArray']])]
    public Team $team;
    
  2. Type Mismatches: Ensure cast methods return the exact property type (e.g., string for public string $name).

  3. Attribute Conflicts: Duplicate #[Describe] on the same property throws DuplicateDescribeAttributeException.

Debugging Tips

  • Inspect Resolution Order: Use Describe::$extra to log debug info:
    #[Describe(['my_key' => 'debug'])]
    public string $name;
    
  • Validate with null: Test edge cases by passing null or empty arrays to from().

Extension Points

  1. Custom Attributes: Subclass Describe to add domain-specific keys:

    #[Attribute]
    class CustomDescribe extends Describe {
        public function __construct(array $options = []) {
            parent::__construct($options + ['custom_key' => 'value']);
        }
    }
    
  2. Override from(): Extend hydration logic for complex cases:

    class User extends BaseUser {
        public static function from(mixed $context): static {
            $user = parent::from($context);
            $user->normalize();
            return $user;
        }
    }
    
  3. Laravel Integration: Use DataModelFactory to integrate with Eloquent:

    $user = (new DataModelFactory(User::class))->from($request->all());
    

Configuration Quirks

  • Callable Signatures: Prefer 4-parameter callables ($value, $context, $Attribute, $Property) for full control.
  • String Context: Pass strings to from() (treated as empty context) for default-value testing:
    $user = User::from(''); // Uses `default` values
    

Performance

  • Avoid Reflection Overhead: Cache ReflectionProperty instances if hydrating the same class repeatedly.
  • Batch Processing: Use DataModelHelper for collections:
    $users = DataModelHelper::mapOf(User::class, $apiData['users']);
    
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata