codewiser / casts
Object casting, enum collection, morph validator for Laravel
Requires
- php: ^8.2
- laravel/framework: >=12.0
Requires (Dev)
- phpunit/phpunit: ^11.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Object Casting
Just like Laravel allows to cast data to a Collection, it allows to cast data into an object.
use App\Collections\OptionCollection; use Codewiser\Casts\AsObject; use Illuminate\Database\Eloquent\Casts\AsCollection; /** * Get the attributes that should be cast. * * @return array<string, string> */ protected function casts(): array { return [ 'option' => AsObject::of(Option::class), 'options' => AsCollection::using(OptionCollection::class, Option::class), ]; }
Enum Collections
Laravel provides AsEnumCollection to cast array of enum values into a
collection, but actually it is REDUNDANT. It is more than enough to use
AsCollection:of(Enum:class).
Much worse, that base collection can't handle enum values in some cases. For
example, intersect or diff fails, as array_intersect doesn't support
enums.
This package provides enum collection, where these methods are fixed to work with enums.
You may cast enum collection this way:
use App\Collections\OptionCollection; use Codewiser\Collections\EnumCollection; use Illuminate\Database\Eloquent\Casts\AsCollection; /** * Get the attributes that should be cast. * * @return array<string, string> */ protected function casts(): array { return [ 'roles' => AsCollection::using(EnumCollection::class, RoleEnum::class), ]; }
Date-time with timezone Casting
Laravel doesn't respect timezone.
Cast \Codewiser\Casts\AsDatetimeWithTZ fixes this behaviour.
Before
class Article extends \Illuminate\Database\Eloquent\Model { protected $casts = [ 'date' => 'datetime' ]; }
// e.g. Laravel has Europe/London (+01:00) timezone config()->set('app.timezone', 'Europe/London'); $model = new Article(); $model->date = '2000-01-01T10:00:00+02:00'; echo $model->date->format('c'); // Expecting 2000-01-01T09:00:00+01:00 // Actual 2000-01-01T10:00:00+01:00
After
class Article extends \Illuminate\Database\Eloquent\Model { protected $casts = [ 'date' => \Codewiser\Casts\AsDatetimeWithTZ::class ]; }
// e.g. Laravel has Europe/London (+01:00) timezone config()->set('app.timezone', 'Europe/London'); $model = new Article(); $model->date = '2000-01-01T10:00:00+02:00'; echo $model->date->format('c'); // Expecting 2000-01-01T09:00:00+01:00 // Actual 2000-01-01T09:00:00+01:00
Form Request morph Validator
Before
use Illuminate\Database\Eloquent\Relations\Relation; class MyRequest extends FormRequest { public function rules(): array { return [ 'commentable_type' => 'required|string', 'commentable_id' => 'required', ]; } public function getCommentable(): Model { $class = Relation::getMorphedModel($this->input('commentable_type')); return $class::find($this->integer('commentable_id')); } }
After
use Codewiser\Requests\HasMorphs; use Illuminate\Database\Eloquent\Relations\Relation; class MyRequest extends FormRequest { use HasMorphs; public function rules(): array { return [ ...$this->morph('commentable') ]; } public function getCommentable(): Model { return $this->morphed('commentable'); } }
Additionally, you may pass list of classes, the morphed model could be.
use Codewiser\Requests\HasMorphs; use Illuminate\Database\Eloquent\Relations\Relation; class MyRequest extends FormRequest { use HasMorphs; public function rules(): array { return [ ...$this->nullableMorph('commentable', [Post::class, Article::class]) ]; } public function hasCommentable(): bool { return $this->hasMorph('commentable'); } public function getCommentable(): null|Post|Article { return $this->morphed('commentable'); } }