我有一个配置模型,在其中实现了自定义转换,getter 工作完美,但让我们看看 setter。
为了清楚起见,我已将代码示例精简为仅与上下文相关的内容。
应用程序/模型/Configuration.php
use Illuminate\Database\Eloquent\Model;
class Configuration extends Model
{
protected function casts(): array
{
return [
'value' => \App\Casts\ConfigValue::class,
];
}
}
应用程序/Casts/ConfigValue.php
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
class ConfigValue implements CastsAttributes
{
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{
$saveable = $value instanceof UploadedFile ||
(isset($value[0]) && $value[0] instanceof UploadedFile);
echo 1; // Take note of this
return match (true) {
...// Other conditions
$saveable => $this->doUpload(UploadedFile|array $value),
...// Other conditions
default => (string) $value,
};
}
}
我们也不必担心文件上传的逻辑,这里的问题是 X-Debug 在处理上传时终止脚本后抛出无限循环错误。但是,如果我直接返回输出,您可以从下图中看到,脚本在返回响应之前会运行多次,添加上传逻辑会使我们陷入无限循环。
应用程序/控制器/ConfigController.php
$config = Configuration::where('key', $key)->first();
$config->value = $value;
$config->save();
在控制器上
$key
和 $value
来自 $request->configurations
的 foreach 循环,当 $value
不是 \Illuminate\Http\UploadedFile
的实例时,上面的方法效果很好,在这种情况下,我们会陷入无限循环。
我在这里做错了什么?
发生无限循环是因为您的自定义转换的
set
方法在处理 UploadedFile 实例时导致对其自身的递归调用。
重写你的设置方法:
class ConfigValue implements CastsAttributes
{
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{
$saveable = $value instanceof UploadedFile ||
(is_array($value) && isset($value[0]) && $value[0] instanceof UploadedFile);
if ($saveable) {
$filePath = $this->doUpload($value);
return $filePath;
}
return (string) $value;
}
private function doUpload(UploadedFile|array $value): string
{
if (is_array($value)) {
$paths = [];
foreach ($value as $file) {
$paths[] = $file->store('uploads');
}
return json_encode($paths);
} else {
return $value->store('uploads');
}
}
}