支持 Laravel.io 的持续发展 →

在 Laravel 7 中使用自定义 Eloquent 转换

2020年6月26日 阅读时间:3分钟 阅读次数:371次

Laravel 7 即将到来(预定3月3日发布),它提供了一大批令人兴奋的新功能与改进。我最期待的功能之一就是 自定义Eloquent类型转换

在历史上,你只能使用Laravel提供的默认类型转换集,它覆盖了基本语言类型以及日期。虽然有一些现有的包提供了自定义类型转换,但它们有一个主要的缺点。由于它们通过特质覆盖了 setAttributegetAttribute 方法,因此它们不能与任何其他也覆盖这些方法的包一起使用。

现在Laravel 7原生支持了这些类型转换,从而在库之间不会出现兼容性问题!

自定义Eloquent类型转换是如何工作的

任何实现Laravel提供的新 CastsAttributes 合约的对象现在都可以用于模型上的 $casts 属性。当访问模型上的属性时,Eloquent会首先检查是否存在自定义类型转换来转换值,然后再将值返回给你。

请记住,你的类型转换将在模型的每个单个获取和设置操作上被调用,所以请考虑缓存耗时的操作。

创建自定义类型转换

Laravel的一个受欢迎的功能建议是允许选择性对模型属性进行加密,而使用自定义类型转换,这可以非常简单实现。

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class EncryptCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return encrypt($value);
    }

    public function set($model, $key, $value, $attributes)
    {
        return decrypt($value);
    }
}

在你的模型中,你还可以将一个属性分配给我们刚刚创建的类型转换。

class TestModel extends Model
{
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'secret' => EncryptCast::class,
    ];
}

现在我们已经设置好了,让我们来测试一下!由于 encrypt/decrypt 函数会序列化输入,所以你可以存储几乎任何内容(但你可能应该坚持使用简单的内置类型)。

$model = new TestModel();

$model->secret = 'Hello World'; // Plain text value

// Encrypted value (which will be saved to the database)
// Raw Value: eyJpdiI6InV4Q25ZN0FZUW5YSEZkRCtZSGlVXC9BPT0iLCJ2Y...
$model->getAttributes()['secret'];

$model->save(); // Save & reload the model from the DB
$model->fresh();

echo $model->secret; // Hello World

因为自定义转换仅是对象,所以可以根据需要设置得简单或复杂。在实现中还有一些附加功能,包括“入站”转换(只转换设置的值)以及从模型中的 $casts 声明中获取配置的能力。

例如,我们可以限制字符串的长度(只有当设置值时),因此任何现有的值长度将保持不变。

class LimitCaster implements CastsInboundAttributes
{
    public function __construct($length = 25)
    {
        $this->length = $length;
    }

    public function set($model, $key, $value, $attributes)
    {
        return [$key => Str::limit((string) $value, $this->length)];
    }
}

在模型中,用冒号将转换的类名和参数分开。

class TestModel extends Model
{
    protected $casts = [
        'limited_str' => LimitCaster::class . ':10', // Limit to 10 characters
    ];
}

总结

我很期待看到社区在 Laravel 7 测试版发布后提供的那些精彩的转换。将自定义转换发布为包也非常简单,所以希望未来能看到许多包含自定义转换的包。

在我之前的项目中错过的一个是 DateIntervalCarbonInterval 转换,所以我 发布了一个包,以防其他人也遇到过相同的问题。

有什么疑问吗?欢迎在下面评论,我将尽力回答。

进一步阅读

框架 PR
DateInterval 转换 PR

最后更新 1 年前。

driesvints, mariosoftmedic 赞同这篇文章

2
喜欢这篇文章吗?告诉作者并为他们鼓掌!

你可能还喜欢这些文章

2024年3月11日

如何使用 Larastan 将你的 Laravel 应用从0提升到9

在 Laravel 应用执行之前发现错误是可能的,多亏了 Larastan,它...

阅读文章
2024年7月19日

无需使用 traits 标准化 API 响应

我注意到大多数用于 API 响应的库是使用 traits 实现的,...

阅读文章
2024年7月17日

通过 Discord 通知在 Laravel 项目中收集反馈

如何在 Laravel 项目中创建一个反馈模块,并收到 Discord 通知...

阅读文章

我们感谢这些 令人惊叹的公司 对我们的大力支持

您想在这里展示您的标志吗?

Laravel.io

Laravel 问题的解决方案、知识共享和社区建设的信息门户。

© 2024 Laravel.io - 版权所有。