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

Laravel Data Laravel Package

spatie/laravel-data

Define rich, typed data objects once and use them for requests, validation, API resources/transformers, and TypeScript definitions. Create from arrays/requests/models, apply rules automatically, and transform only what’s needed with lazy properties.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-data
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Spatie\LaravelData\LaravelDataServiceProvider" --tag="config"
    
  2. Define a Data Object: Create a class extending Spatie\LaravelData\Data in app/Data (or your configured directory):

    namespace App\Data;
    
    use Spatie\LaravelData\Data;
    
    class SongData extends Data
    {
        public function __construct(
            public string $title,
            public string $artist,
        ) {}
    }
    
  3. First Use Case: Create a SongData instance from an array:

    $songData = SongData::from([
        'title'  => 'Bohemian Rhapsody',
        'artist' => 'Queen',
    ]);
    

Implementation Patterns

Core Workflows

  1. Request Validation & Transformation: Replace FormRequests with Data objects for validation and transformation:

    use Spatie\LaravelData\Data;
    use Spatie\LaravelData\Attributes\Validation;
    
    class CreateSongRequest extends Data
    {
        public function __construct(
            #[Validation('required|string|max:255')]
            public string $title,
            #[Validation('required|string')]
            public string $artist,
        ) {}
    }
    
    // In controller:
    $requestData = CreateSongRequest::from($request->all());
    
  2. API Responses: Use Data as API resources (no need for separate transformers):

    return response()->json(SongData::from($song));
    
  3. Model Integration: Attach Data to Eloquent models for type-safe serialization:

    use Spatie\LaravelData\WithData;
    
    class Song extends Model
    {
        use WithData;
    
        protected $dataClass = SongData::class;
    }
    
    // Usage:
    $songData = Song::find(1)->getData();
    
  4. TypeScript Generation: Generate frontend types via CLI:

    php artisan data:generate-typescript
    

Advanced Patterns

  1. Lazy Properties: Load nested data on-demand:

    class AlbumData extends Data
    {
        public function __construct(
            public string $name,
            public ?SongData $featuredSong = null,
        ) {}
    
        public function getFeaturedSong(): ?SongData
        {
            return $this->featuredSong ?? SongData::from([
                'title'  => 'Lazy Loaded',
                'artist' => 'Dynamic',
            ]);
        }
    }
    
  2. Custom Casts: Transform input values (e.g., strings to Carbon):

    use Spatie\LaravelData\Casts\Cast;
    use Spatie\LaravelData\Attributes\WithCast;
    
    class DateCast implements Cast
    {
        public function cast($value): \Carbon\Carbon
        {
            return \Carbon\Carbon::parse($value);
        }
    }
    
    class EventData extends Data
    {
        public function __construct(
            #[WithCast(DateCast::class)]
            public string $date,
        ) {}
    }
    
  3. Nested Data: Handle arrays/collections of Data:

    class PlaylistData extends Data
    {
        public function __construct(
            public array $songs, // Automatically casts to SongData[]
        ) {}
    }
    

Gotchas and Tips

Pitfalls

  1. Reflection Overhead:

    • Avoid heavy reflection in production. Cache structures:
      php artisan data:cache-structures
      
    • Configure cache store in config/data.php:
      'structure_caching' => [
          'cache' => ['store' => 'redis'],
      ],
      
  2. Null Handling:

    • Casts never receive null (use magic methods or default values):
      public function __construct(
          public ?string $optionalField = null,
      ) {}
      
  3. Type Mismatches:

    • PHP’s type system enforces strict validation. Use #[Validation] for runtime checks:
      #[Validation('nullable|string')]
      public ?string $field;
      
  4. Circular References:

    • Avoid bidirectional relationships (e.g., UserDataProfileData) to prevent infinite loops.

Debugging Tips

  1. Inspect Data Structure: Use dd($data->toArray()) or dd($data->getProperty('field')) to debug properties.

  2. Validation Errors: Catch ValidationException for detailed error messages:

    try {
        $data = SongData::from($request->all());
    } catch (ValidationException $e) {
        return response()->json($e->errors(), 422);
    }
    
  3. Performance Profiling: Disable caching temporarily to measure reflection impact:

    'structure_caching' => ['enabled' => false],
    

Extension Points

  1. Custom Validation: Extend ValidationStrategy for reusable rules:

    use Spatie\LaravelData\Support\Validation\ValidationStrategy;
    
    class CustomValidationStrategy extends ValidationStrategy
    {
        protected function validateProperty($value, $rule): void
        {
            // Custom logic
        }
    }
    
  2. Dynamic Properties: Use magic methods for runtime properties:

    public function getFullTitle(): string
    {
        return "{$this->artist} - {$this->title}";
    }
    
  3. Global Casts: Register casts globally in AppServiceProvider:

    use Spatie\LaravelData\Casts\Cast;
    
    public function boot()
    {
        Data::macro('castUsing', function (Cast $cast) {
            Data::addGlobalCast($cast);
        });
    }
    
  4. TypeScript Customization: Override generateTypescript in Data:

    public static function generateTypescript(): string
    {
        return "export interface CustomSongData { ... }";
    }
    
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