After I update my model, the cast is ignored and an old value that comes from classCastCache is shown.
I'm getting a Illuminate\Http\Testing\File instead of 'GETTING'.
- Create a custom cast:
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class Image implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function get($model, $key, $value, $attributes)
{
return 'GETTING';
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function set($model, $key, $value, $attributes)
{
return 'SETTING';
}
}
- Apply it to a model:
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Casts\Image;
class Product extends Model
{
use HasFactory;
/**
* Mass assignable attributes.
*
* @var string[]
*/
protected $fillable = [
'name',
'image',
];
/**
* Model's attribute casting.
*
* @var array
*/
protected $casts = [
'image' => Image::class,
];
}
- Create a test for it:
/** @test */
public function it_can_change_product_image()
{
Storage::fake();
$business = Business::factory()->create();
$product = Product::factory()->for($business)->create();
$this->authenticate($business->owner); // Helper to authenticate with Sanctum. Ignore.
// The important part here, sending a fake image.
$response = $this->putJson(route('v1.products.update', $product), [
'image' => UploadedFile::fake()->image('example.jpg'),
]);
$response->assertOk(); // Among other tests that are hidden due demo purposes.
}
- Create a Controller action to update the value of it.
/**
* Update the specified resource in storage.
*
* @param UpdateRequest $request
* @param Product $product
* @return ProductResource
*/
public function update(UpdateRequest $request, Product $product): ProductResource
{
// The custom request validator checks for:
// 'image' => ['sometimes', 'file', 'max:1024', 'image', 'mimes:jpg,bmp,png']
// This should update the product image based on the cast.
// The current DB value should be `SETTING`.
$product->update($request->validated());
// This should be `GETTING`.
// Instead, it is: Illuminate\Http\Testing\File
dd($product->image);
// a BAD workaround is to:
$product->refresh();
// This is the correct value `GETTING`.
dd($product->image);
}