In https://chasingcode.dev/blog/csv-import-with-laravel-building-blocks-part-1/ I described the command I built with Laravel Prompts to import a CSV file into a SQLite database. Now, I'll dive deeper into how I used https://spatie.be/docs/laravel-data/v3/introduction for the ItemData DTO, plus some custom data casts for the CSV columns.
These are the contents of the class: namespace App\DataObjects; use App\DataCasts\CommaSeparatedStringToArrayCast; use App\DataCasts\DollarStringToIntCast; use App\DataCasts\DateStringToCarbonImmutableCast; use App\DataCasts\StringToNullCast; use Carbon\CarbonImmutable; use Spatie\LaravelData\Attributes\WithCast; use Spatie\LaravelData\Data; class ItemData extends Data { public function __construct( #[WithCast(DateStringToCarbonImmutableCast::class, 'm/d/Y')] public CarbonImmutable|null $received_on, #[WithCast(DateStringToCarbonImmutableCast::class, 'm/d/Y')] public CarbonImmutable|null $ordered_on, #[WithCast(StringToNullCast::class)] public string|null $brand, public string $model, #[WithCast(DollarStringToIntCast::class)] public int $price, public string $with_tax, #[WithCast(StringToNullCast::class)] public string|null $store, #[WithCast(CommaSeparatedStringToArrayCast::class)] public array $tags, public string $notes, ) { }}
use Carbon\CarbonImmutable; class DateStringToCarbonImmutableCast implements Cast { private string $timezone = 'UTC'; // 'America/Chicago' public function __construct( protected ?string $format = null, ) { } public function cast(DataProperty $property, mixed $value, array $context): ?CarbonImmutable { if (! $value) return null; return CarbonImmutable::createFromFormat($this->format, $value, $this->timezone)->startOfDay(); }}
class StringToNullCast implements Cast { public function cast(DataProperty $property, mixed $value, array $context): string|null { return $value === '' ? null : $value; }}