rawilk/laravel-casters
Collection of custom Eloquent cast classes for Laravel models. Add handy casts like Name to normalize and manipulate attributes automatically. Install via Composer; full docs available online.
Installation:
composer require rawilk/laravel-casters
Ensure your composer.json lists Laravel 11+ and PHP 8.2+ (check releases).
First Use Case:
Apply the Name cast to a model’s name attribute for automatic formatting (e.g., title case, trimming):
use Rawilk\LaravelCasters\Casts\Name;
class User extends Model
{
protected $casts = [
'name' => Name::class,
];
}
Now, $user->name = ' john doe ' will auto-trim and title-case to "John Doe" when accessed.
Key Entry Points:
Attribute Casting:
protected $casts = [
'email' => Email::class, // Validates and normalizes emails
'slug' => Slug::class, // Generates URL-friendly slugs
'tags' => Tags::class, // Handles comma-separated tags
'active' => Boolean::class, // Ensures boolean storage (e.g., `1`/`0` → `true`/`false`)
];
getCasts() to conditionally apply casts:
public function getCasts()
{
return array_merge(parent::getCasts(), [
'formatted_address' => $this->shouldFormatAddress() ? Address::class : 'string',
]);
}
Customizing Casts:
use Rawilk\LaravelCasters\Casts\Name;
class CustomName extends Name
{
protected $format = 'UPPER'; // Override default formatting
}
Illuminate\Contracts\Database\Eloquent\CastsAttributes:
use Rawilk\LaravelCasters\Casts\Cast;
class CustomCast extends Cast
{
public function get($model, string $key, $value, array $attributes)
{
return strtoupper($value);
}
public function set($model, string $key, $value, array $attributes)
{
return strtolower($value);
}
}
Model-Specific Patterns:
HasSingleNameColumn contract for models with a single name field:
use Rawilk\LaravelCasters\Contracts\HasSingleNameColumn;
class Product extends Model implements HasSingleNameColumn
{
// ...
}
This ensures proper serialization of the name attribute.API Responses:
toArray() or toJson() for consistent formatting:
public function toArray()
{
return [
'name' => $this->name, // Automatically cast via $casts
'created_at' => $this->created_at->format('Y-m-d'),
];
}
Form Requests:
use Rawilk\LaravelCasters\Casts\Email;
public function rules()
{
return [
'email' => ['required', new Email], // Custom cast as a validator
];
}
Database Schema:
Boolean or Tags may require specific column types (e.g., TEXT for tags, TINYINT for booleans).Testing:
public function test_name_cast()
{
$user = new User(['name' => ' jane doe ']);
$this->assertEquals('Jane Doe', $user->name);
}
Model::newFromBuilder() to test cast hydration:
$model = User::newFromBuilder([
'name' => ' john doe ',
]);
$this->assertEquals('John Doe', $model->name);
Performance:
array_map on collections).Laravel Ecosystem:
Slug integrate seamlessly with Laravel Scout for searchable slugs.Database Writes:
name) directly to the database. The Name cast in v3.0.3+ prevents this, but ensure your migrations don’t duplicate logic.1/0 for booleans by default. If your database uses TRUE/FALSE, explicitly set:
protected $casts = [
'is_active' => Boolean::class,
];
protected $attributes = [
'is_active' => 0, // Default to FALSE
];
Null Handling:
Email) may throw exceptions on null values. Use nullable() in your $casts array:
protected $casts = [
'optional_email' => [Email::class, 'nullable'],
];
Version Mismatches:
Password cast was removed in v4.0.0. Use Laravel’s native hash cast instead:
protected $casts = [
'password' => 'hash',
];
Serialization:
array:where or cursor queries. Use getAttributes() or fresh() to re-cast:
$user = User::where('name', 'like', '%john%')->first();
$user->name; // May not be cast if fetched via cursor
$user->fresh()->name; // Re-casts
Cast Order:
$casts. Override getCasts() if order matters:
public function getCasts()
{
return ['slug' => Slug::class, 'name' => Name::class]; // Slug cast runs first
}
Custom Cast Logging:
public function get($model, string $key, $value, array $attributes)
{
Log::debug("Casting {$key}: {$value}");
return strtoupper($value);
}
Common Issues:
Rawilk\LaravelCasters\Casts\Name).tap() to inspect cast behavior:
$user->name->tap(fn($name) => Log::debug("Cast result: {$name}"));
Custom Cast Attributes:
protected $casts = [
'name' => [Name::class, 'format' => 'UPPER'],
];
public function __construct(array $options = [])
{
$this->format = $options['format'] ?? 'title';
}
Global Casts:
AppServiceProvider:
use Rawilk\LaravelCasters\Casts\Email;
public function boot()
{
\Illuminate\Database\Eloquent\Casts\Cast::macro('email', function () {
return Email::class;
});
}
Now use shorthand:
protected $casts = [
'email' => 'email',
];
Testing Custom Casts:
$cast = Mockery::mock(Rawilk\LaravelCasters\Casts\Name::class);
How can I help you explore Laravel packages today?