flolefebvre / serializer
0.0.12
2025-06-29 08:21 UTC
Requires
- laravel/framework: ^12.3
- laravel/sanctum: ^4.0
Requires (Dev)
- orchestra/testbench: ^10.1
- pestphp/pest: ^3.7
- pestphp/pest-plugin-laravel: ^3.1
README
A zero‑boilerplate, attribute‑driven serializer / DTO helper for Laravel 10 & 11
Built for PHP ≥ 8.2 — lighter than 20 KB.
Table of Contents
- Why another serializer?
- Features
- Requirements
- Installation
- Quick start
- Advanced usage
- Performance & Limitations
- Contributing
- License
Why another serializer?
flolefebvre/serializer
focuses on simplicity and strictness:
- DTOs are just classes extending
Serializable
. - Validation occurs before the object exists — no invalid state can persist.
- No generated code or heavy reflection caches; your build stays ultra‑fast.
Features
✅ Constructor‑promoted DTOs only | ✅ Automatic validation via #[Rule] |
✅ Pure attribute configuration | ✅ Typed arrays (#[ArrayType] ) |
✅ Laravel DI & Request auto‑binding | ✅ Custom type‑casts (TypeCast interface) |
✅ Eloquent JSON cast (single / list) | ✅ JsonResponse ready to return |
Requirements
- PHP 8.2+
- Laravel 10 / 11
ext-json
Installation
composer require flolefebvre/serializer
Quick start
Create a DTO:
<?php namespace App\DTO; use Flolefebvre\Serializer\Serializable; use Flolefebvre\Serializer\Attributes\Rule; class PostData extends Serializable { public function __construct( public string $title, #[Rule('nullable|string|max:280')] public ?string $excerpt, #[Rule('required|url')] public string $url, ) {} }
Bind it in a route:
use App\DTO\PostData; use Illuminate\Support\Facades\Route; Route::post('/posts', function (PostData $data) { // $data is a fully validated DTO. // ... return $data; // => JsonResponse 201 });
Try it:
curl -X POST http://localhost/api/posts -H "Content-Type: application/json" -d '{"title":"Hello","excerpt":null,"url":"https://example.com"}'
Response:
{ "title": "Hello", "excerpt": null, "url": "https://example.com", "_type": "App\\DTO\\PostData" }
Advanced usage
Custom TypeCast
use Ramsey\Uuid\UuidInterface; use Flolefebvre\Serializer\Attributes\CastTypeWith; use Flolefebvre\Serializer\Casts\TypeCast; use Ramsey\Uuid\Uuid; class UuidCast implements TypeCast { // How the value will appear once serialized public string $serializedType = 'uuid'; public function serialize(mixed $value): mixed { return (string) $value; } public function unserialize(mixed $value): mixed { return Uuid::fromString($value); } } class OrderData extends Serializable { public function __construct( #[CastTypeWith(UuidCast::class)] public UuidInterface $id, ) {} }
Arrays of DTOs
use Flolefebvre\Serializer\Attributes\ArrayType; class BlogData extends Serializable { public function __construct( #[ArrayType(CommentData::class)] public array $comments, ) {} }
Performance & Limitations
Topic | Notes |
---|---|
Reflection | Metadata is rebuilt on every call → enable OPcache and/or add a static cache for high‑traffic endpoints. |
Union/Intersection Types | Not yet supported — contributions welcome. |
Polymorphism | The _type field is required for subclasses during deserialization. |
Contributing
- Fork & clone
composer install && composer test
- Create your feature branch (
git checkout -b feature/my-feature
) - Push and open a PR
- Ensure tests pass and follow PSR‑12.
License
Released under the MIT License — see LICENSE.