|
7 | 7 | use DateTimeInterface;
|
8 | 8 | use Exception;
|
9 | 9 | use Foo\Bar\EloquentModelNamespacedStub;
|
| 10 | +use Illuminate\Contracts\Database\Eloquent\Castable; |
| 11 | +use Illuminate\Contracts\Database\Eloquent\CastsAttributes; |
10 | 12 | use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
|
11 | 13 | use Illuminate\Contracts\Encryption\Encrypter;
|
12 | 14 | use Illuminate\Contracts\Events\Dispatcher;
|
|
22 | 24 | use Illuminate\Database\Eloquent\Casts\AsEnumArrayObject;
|
23 | 25 | use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
|
24 | 26 | use Illuminate\Database\Eloquent\Casts\AsStringable;
|
| 27 | +use Illuminate\Database\Eloquent\Casts\Attribute; |
25 | 28 | use Illuminate\Database\Eloquent\Collection;
|
26 | 29 | use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
27 | 30 | use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
@@ -2576,6 +2579,45 @@ public function testThrowsWhenAccessingMissingAttributes()
|
2576 | 2579 | }
|
2577 | 2580 | }
|
2578 | 2581 |
|
| 2582 | + public function testThrowsWhenAccessingMissingAttributesWhichArePrimitiveCasts() |
| 2583 | + { |
| 2584 | + $originalMode = Model::preventsAccessingMissingAttributes(); |
| 2585 | + Model::preventAccessingMissingAttributes(); |
| 2586 | + |
| 2587 | + $model = new EloquentModelWithPrimitiveCasts(['id' => 1]); |
| 2588 | + $model->exists = true; |
| 2589 | + |
| 2590 | + $exceptionCount = 0; |
| 2591 | + $primitiveCasts = EloquentModelWithPrimitiveCasts::makePrimitiveCastsArray(); |
| 2592 | + try { |
| 2593 | + try { |
| 2594 | + $this->assertEquals(null, $model->backed_enum); |
| 2595 | + } catch (MissingAttributeException) { |
| 2596 | + $exceptionCount++; |
| 2597 | + } |
| 2598 | + |
| 2599 | + foreach($primitiveCasts as $key => $type) { |
| 2600 | + try { |
| 2601 | + $v = $model->{$key}; |
| 2602 | + } catch (MissingAttributeException) { |
| 2603 | + $exceptionCount++; |
| 2604 | + } |
| 2605 | + } |
| 2606 | + |
| 2607 | + $this->assertInstanceOf(Address::class, $model->address); |
| 2608 | + |
| 2609 | + $this->assertEquals(1, $model->id); |
| 2610 | + $this->assertEquals('ok', $model->this_is_fine); |
| 2611 | + $this->assertEquals('ok', $model->this_is_also_fine); |
| 2612 | + |
| 2613 | + // Primitive castables, enum castable |
| 2614 | + $expectedExceptionCount = count($primitiveCasts) + 1; |
| 2615 | + $this->assertEquals($expectedExceptionCount, $exceptionCount); |
| 2616 | + } finally { |
| 2617 | + Model::preventAccessingMissingAttributes($originalMode); |
| 2618 | + } |
| 2619 | + } |
| 2620 | + |
2579 | 2621 | public function testUsesOverriddenHandlerWhenAccessingMissingAttributes()
|
2580 | 2622 | {
|
2581 | 2623 | $originalMode = Model::preventsAccessingMissingAttributes();
|
@@ -3349,3 +3391,70 @@ class CustomCollection extends BaseCollection
|
3349 | 3391 | {
|
3350 | 3392 | //
|
3351 | 3393 | }
|
| 3394 | + |
| 3395 | +class EloquentModelWithPrimitiveCasts extends Model |
| 3396 | +{ |
| 3397 | + public $fillable = ['id']; |
| 3398 | + |
| 3399 | + public $casts = [ |
| 3400 | + 'backed_enum' => CastableBackedEnum::class, |
| 3401 | + 'address' => Address::class, |
| 3402 | + ]; |
| 3403 | + |
| 3404 | + public static function makePrimitiveCastsArray(): array |
| 3405 | + { |
| 3406 | + $toReturn = []; |
| 3407 | + |
| 3408 | + foreach(static::$primitiveCastTypes as $index => $primitiveCastType) { |
| 3409 | + $toReturn['primitive_cast_' . $index] = $primitiveCastType; |
| 3410 | + } |
| 3411 | + |
| 3412 | + return $toReturn; |
| 3413 | + } |
| 3414 | + |
| 3415 | + public function __construct(array $attributes = []) |
| 3416 | + { |
| 3417 | + parent::__construct($attributes); |
| 3418 | + |
| 3419 | + $this->mergeCasts(self::makePrimitiveCastsArray()); |
| 3420 | + } |
| 3421 | + |
| 3422 | + public function getThisIsFineAttribute($value) { |
| 3423 | + return 'ok'; |
| 3424 | + } |
| 3425 | + |
| 3426 | + public function thisIsAlsoFine(): Attribute |
| 3427 | + { |
| 3428 | + return Attribute::get(fn() => 'ok'); |
| 3429 | + } |
| 3430 | +} |
| 3431 | + |
| 3432 | +enum CastableBackedEnum: string |
| 3433 | +{ |
| 3434 | + case Value1 = 'value1'; |
| 3435 | +} |
| 3436 | + |
| 3437 | +class Address implements Castable |
| 3438 | +{ |
| 3439 | + public static function castUsing(array $arguments): CastsAttributes |
| 3440 | + { |
| 3441 | + return new class implements CastsAttributes |
| 3442 | + { |
| 3443 | + public function get(Model $model, string $key, mixed $value, array $attributes): Address |
| 3444 | + { |
| 3445 | + return new Address( |
| 3446 | + $attributes['address_line_one'], |
| 3447 | + $attributes['address_line_two'] |
| 3448 | + ); |
| 3449 | + } |
| 3450 | + |
| 3451 | + public function set(Model $model, string $key, mixed $value, array $attributes): array |
| 3452 | + { |
| 3453 | + return [ |
| 3454 | + 'address_line_one' => $value->lineOne, |
| 3455 | + 'address_line_two' => $value->lineTwo, |
| 3456 | + ]; |
| 3457 | + } |
| 3458 | + }; |
| 3459 | + } |
| 3460 | +} |
0 commit comments