mellivora / laravel-api-caster
Convert API response results to Entity objects like Laravel Eloquent. Enhanced with type-safe collections and meta support. Supports PHP 8.3+ and Laravel 10+.
Fund package maintenance!
zhouyl
Installs: 52
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/mellivora/laravel-api-caster
Requires
- php: ^8.3|^8.4
- brick/math: ^0.10|^0.11|^0.12
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- nesbot/carbon: ^2.0|^3.0
- psr/http-message: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- guzzlehttp/psr7: ^2.0
- phpstan/extension-installer: *
- phpstan/phpstan: ^1.0|^2.0
- phpstan/phpstan-strict-rules: *
- phpunit/phpunit: ^10.5|^11.0
- rector/rector: ^1.0|^2.0
README
Convert API response results to Entity objects like Laravel Eloquent. This package provides a powerful and flexible way to transform API responses into structured, type-safe entities with support for casting, mapping, data transformation, and enhanced collection handling with metadata support.
Features
- ๐ Laravel Eloquent-like API - Familiar syntax for Laravel developers
- ๐ Automatic Type Casting - Built-in support for common data types
- ๐ฏ Custom Casters - Create your own casting logic
- ๐ฆ Entity Mapping - Map nested data to Entity objects
- ๐ง Flexible Configuration - Includes, excludes, renames, and more
- ๐ Collection with Meta - Enhanced collections with metadata support
- ๐ก๏ธ Type-Safe Collections - Complete type validation for all collection operations
- ๐งช Fully Tested - Comprehensive test suite with 84.79% coverage
- โก High Performance - Optimized for speed and memory efficiency
- ๐ Type Safe - Full PHP 8.3+ type declarations
Requirements
- PHP 8.3 or 8.4
- Laravel 10.x, 11.x, or 12.x
Installation
You can install the package via composer:
composer require mellivora/laravel-api-caster
Quick Start
Basic Usage
use Mellivora\Http\Api\Entity; use Mellivora\Http\Api\Response; // From HTTP Response $response = new Response($httpResponse); $entity = Entity::from($response); // From array data $entity = new Entity([ 'id' => 123, 'name' => 'John Doe', 'email' => 'john@example.com' ]); // Access data echo $entity->id; // 123 echo $entity->name; // John Doe echo $entity->email; // john@example.com
Collections
// Create collection from response $collection = Entity::collectionResponse($response); // Create collection from array $collection = Entity::collection([ ['id' => 1, 'name' => 'User 1'], ['id' => 2, 'name' => 'User 2'], ]); foreach ($collection as $entity) { echo $entity->name; }
Advanced Usage
Type Casting
class UserEntity extends Entity { protected array $casts = [ 'id' => 'int', 'email_verified_at' => 'datetime', 'settings' => 'json', 'score' => 'decimal:2', 'status' => UserStatusEnum::class, ]; } $user = new UserEntity([ 'id' => '123', 'email_verified_at' => '2023-01-01 12:00:00', 'settings' => '{"theme": "dark"}', 'score' => '95.75', 'status' => 'active', ]); // Automatically casted $user->id; // int(123) $user->email_verified_at; // Carbon instance $user->settings; // array ['theme' => 'dark'] $user->score; // string '95.75' $user->status; // UserStatusEnum::ACTIVE
Entity Mapping
class ProductEntity extends Entity { protected array $mappings = [ 'category' => CategoryEntity::class, 'tags[]' => TagEntity::class, ]; } $product = new ProductEntity([ 'id' => 1, 'name' => 'Laptop', 'category' => ['id' => 1, 'name' => 'Electronics'], 'tags' => [ ['id' => 1, 'name' => 'Tech'], ['id' => 2, 'name' => 'Gadget'], ], ]); $product->category; // CategoryEntity instance $product->tags; // EntityCollection of TagEntity instances $product->tags->first(); // TagEntity instance
Field Configuration
class UserEntity extends Entity { // Include only specific fields protected array $includes = ['id', 'name', 'email']; // Exclude specific fields protected array $excludes = ['password', 'secret']; // Rename fields protected array $renames = [ 'user_id' => 'id', 'full_name' => 'name', ]; // Append computed attributes protected array $appends = ['display_name']; public function getDisplayNameAttribute(): string { return $this->name . ' (' . $this->email . ')'; } }
Custom Casters
use Mellivora\Http\Api\Contracts\Castable; use Mellivora\Http\Api\Contracts\CastsAttributes; class MoneyCaster implements Castable { public static function castUsing(array $arguments): CastsAttributes { return new class implements CastsAttributes { public function getCastValue(Entity $entity, string $key, $value): Money { return new Money($value); } public function fromCastValue(Entity $entity, string $key, mixed $value): int { return $value->getCents(); } }; } } class OrderEntity extends Entity { protected array $casts = [ 'total' => MoneyCaster::class, ]; }
Available Cast Types
| Type | Description | Example |
|---|---|---|
int, integer |
Cast to integer | '123' โ 123 |
float, double, real |
Cast to float | '12.34' โ 12.34 |
string |
Cast to string | 123 โ '123' |
bool, boolean |
Cast to boolean | 1 โ true |
array |
Cast JSON to array | '[1,2,3]' โ [1,2,3] |
json |
Alias for array | Same as array |
object |
Cast JSON to object | '{"a":1}' โ stdClass |
collection |
Cast to Collection | [1,2,3] โ Collection |
date |
Cast to Carbon date | '2023-01-01' โ Carbon |
datetime |
Cast to Carbon datetime | '2023-01-01 12:00:00' โ Carbon |
timestamp |
Cast timestamp to Carbon | 1672574400 โ Carbon |
decimal:2 |
Cast to decimal string | 12.345 โ '12.35' |
date:Y-m-d |
Custom date format | Custom format |
datetime:Y-m-d H:i |
Custom datetime format | Custom format |
Testing
composer test
Code Quality
# Run all quality checks composer quality # Fix code style composer phpcs-fix # Run static analysis composer phpstan # Run rector composer rector-fix
API Documentation
Entity Class
Methods
__construct(iterable $attributes = [], array $meta = [])- Create new entityfrom(Response $response): static- Create from Response objectcollection(iterable $items, array $meta = []): Collection- Create collectioncollectionResponse(Response $response): Collection- Create collection from ResponsetoArray(): array- Convert to arraytoJson(int $options = 0): string- Convert to JSONkeys(): array- Get all keysvalues(): array- Get all valuesisEmpty(): bool- Check if emptycopy(): static- Create a copymeta(string $key = null, mixed $default = null): mixed- Get meta dataorigin(string $key = null, mixed $default = null): mixed- Get original data
Response Class
Methods
__construct(HttpResponse|MessageInterface $response)- Create new responsecode(): int- Get response codemessage(): string- Get response messagedata(string $key = null, mixed $default = null): mixed- Get response datameta(string $key = null, mixed $default = null): mixed- Get response metatoArray(): array- Convert to array
Caster Class
Methods
cast(string $cast, mixed $value): mixed- Cast valuevalue(string $cast, mixed $value): mixed- Get original value
Best Practices
- Use Type Hints: Always define proper types in your entity classes
- Leverage Caching: Cache frequently used entities to improve performance
- Validate Data: Use Laravel's validation before creating entities
- Handle Nulls: Always consider null values in your casting logic
- Test Thoroughly: Write tests for your custom entities and casters
Performance Tips
- Use
includesto limit processed fields - Avoid deep nesting when possible
- Cache entity instances for repeated use
- Use collections for bulk operations
Troubleshooting
Common Issues
Issue: "Class not found" error when using custom casters
Solution: Ensure your caster class implements the Castable interface
Issue: Infinite recursion with circular references
Solution: Use excludes to break circular references
Issue: Memory issues with large datasets Solution: Process data in chunks using collections
License
The MIT License (MIT). Please see License File for more information.