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.
- 🚀 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
- PHP 8.3 or 8.4
- Laravel 10.x, 11.x, or 12.x
You can install the package via composer:
composer require mellivora/laravel-api-casteruse 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' => '[email protected]'
]);
// Access data
echo $entity->id; // 123
echo $entity->name; // John Doe
echo $entity->email; // [email protected]// 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;
}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::ACTIVEclass 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 instanceclass 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 . ')';
}
}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,
];
}| 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 |
composer test# Run all quality checks
composer quality
# Fix code style
composer phpcs-fix
# Run static analysis
composer phpstan
# Run rector
composer rector-fix__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
__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
cast(string $cast, mixed $value): mixed- Cast valuevalue(string $cast, mixed $value): mixed- Get original value
- 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
- Use
includesto limit processed fields - Avoid deep nesting when possible
- Cache entity instances for repeated use
- Use collections for bulk operations
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
The MIT License (MIT). Please see License File for more information.