Laravel 5 Eloquent,如何动态设置转换属性

7
在Laravel 5.1中,有一个名为“属性转换(Attribute Casting)”的新功能,文档详见此处:http://laravel.com/docs/5.1/eloquent-mutators#attribute-casting 我的问题是,是否可以动态地进行属性转换?
例如,我有一个包含以下列的表:
id | name          | value       | type    |
1  | Test_Array    | [somearray] | array   |
2  | Test_Boolean  | someboolean | boolean |

是否可以根据type字段设置value属性的转换,使其在写入(创建/更新)和提取时均可工作?

3个回答

6

您需要在您的模型类中覆盖Eloquent模型的getCastType()方法:

protected function getCastType($key) {
  if ($key == 'value' && !empty($this->type)) {
    return $this->type;
  } else {
    return parent::getCastType($key);
  }
}

您还需要向$this->casts中添加,以便Eloquent将该字段识别为可转换类型。您可以在那里放置默认的转换类型,如果没有设置类型,则将使用它。 更新: 从数据库中读取数据时,以上方法完美运作。当写入数据时,您必须确保在之前设置类型。有两种选项:
  1. Always pass an array of attributes where type key comes before value key - at the moment model's fill() method respects the order of keys when processing data, but it's not future-proof.

  2. Explicitely set type attribute before setting other attributes. It can be easily done with the following code:

    $model == (new Model(['type' => $data['type']))->fill($data)->save();
    

1
啊,我喜欢这个。比我的选项好多了。该睡觉了。 - patricus
1
很酷 :) 我还没有测试过这段代码,如果你有任何问题,请告诉我,我会为你解决。 - jedrzej.kurylo
1
我可以看到你的表中有“type”列 - 我猜这是用来确定投掷类型的,对吗? - jedrzej.kurylo
1
查看Eloquent模型的代码,除了确保在设置值之前设置类型之外,没有其他方法-涉及转换的所有方法仅访问当前正在转换的属性,而不是整个更改集。但是,在设置值时,create/update尊重$attributes数组中的顺序,因此您可以使用它。 - jedrzej.kurylo
1
非常好的聊天 @jedrzej.kurylo 你救了我的一天 :D - antoniputra
显示剩余5条评论

3

这里的一些答案过于深入思考,或者它们微妙地错误了。

原则很简单,就是在需要之前设置 $casts 属性,例如,在将属性写入或从数据库读取之前。

在我的情况下,我需要使用配置的列名并对其进行转换。因为 PHP 不允许在常量表达式中调用函数,所以它不能在类声明中设置,因此我只需在模型的构造函数中声明我的列/属性的转换即可。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model; 

class MyModel extends Model
{
    protected $casts = [
        // we can't call a function in a class constant expression or
        // we'll get 'Constant expression contains invalid operations'
        // config('my-table.array-column.name') => 'array', // this won't work
    ];

    public function __construct()
    {
        $this->casts = array_merge(
            $this->casts, // we can still use $casts above if desired
            [
                // my column name is configured so it isn't known at
                // compile-time so I have to set its cast run-time;
                // the model's constructor is as good a place as any
                config('my-table.array-column.name') => 'array',
            ]
        );

        parent::__construct(...func_get_args());
    }
}

2
$casts 属性是在你访问字段时使用的,而不是在它从数据库中获取时使用的。因此,您可以在填充模型后更新 $casts 属性,并且每当访问 value 字段时它都应该正常工作。 您只需要找出如何在更改 type 字段时更新 $casts 属性。

可能的一个选项是重写 fill() 方法,使其首先调用父 fill() 方法,然后使用 type 字段中的数据更新 $casts 属性。

另一个可能的选项是滥用修改器功能,并在 type 字段上创建一个修改器,以便每当它更改时,它都会更新 $casts 属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接