Laravel:创建动态属性

6
我有一个相当庞大的代码库。其中有几个表和匹配的Eloquent模型,用于以“### 街道,城市,ST,xzipx”的形式存储地址。这些由单个varchar字段称为“address”在数据库中表示。
现在我的问题是,我想添加一个新功能,允许通过它们是否位于同一城市、州等来比较项目。根据当前配置,要做到这一点的方法是对地址字符串进行标记化。这很好,但每次都要这样做有点烦人。
理想的解决方案是重新构造数据库和相关模型,将“address”字段拆分为“street”、“city”、“state”和“zip”。唯一的问题是,其他地方我正在使用“$model->address”访问地址,那么我必须从这些部分构建它。这在整个代码中经常发生,所以即使创建以下帮助函数:
public function address(){
  return $this->street.", ".$this->city.", ".$this->state." ".$this->zip;
}

要求替换所有实例的 $model->address$model->address(),但这仍然很麻烦。理想的解决方案是创建一个动态属性,就像 Laravel 用于关系一样。这是否可能?还有更好的解决方案吗?
1个回答

17

您可以为 address 属性定义一个访问器:

class YourClass {
    public function getAddressAttribute()
    {
        return $this->street.", ".$this->city.", ".$this->state." ".$this->zip;
    }
}

那么,$object->address 应该会返回你需要的内容。如果你希望在模型的数组和 JSON 表单中包含它,你需要将它添加到模型的 $appends 属性中。

class YourClass {
    protected $appends = array('address');
    public function getAddressAttribute()
    {
        return $this->street.', '.$this->city.', '.$this->state.' '.$this->zip;
    }
}

编辑:要进行设置,您需要设置一个突变器,如下所示:

public function setAddressAttribute($value)
{
    // assume $this->handlesParsingAddress parses and returns an assoc array
    $parsed = $this->handlesParsingAddress($value);
    $this->street = $parsed['street'];
    $this->city = $parsed['city'];
    $this->state = $parsed['state'];
    $this->zip = $parsed['zip'];        
}

谢谢。我会试一试的。 - ewok
跟进:是否可以创建一个反向的函数,例如 setAddressProperty(),这样调用 $model->address = BLAHBLAHBLAH; $model->save(); 将解析我传递的内容并将其存储在单独的字段中? - ewok
1
看到编辑,我没有写解析地址的代码,但是设置一个mutator会使这个工作起来,如果你有解析地址的代码。 - derekaug
另一个后续问题:我可以查询这个属性吗?即 Model::where('address','=','whatever'); - ewok
1
我不相信您可以直接查询此属性。我要解析字符串并在所有新列中进行筛选,或找到一种方法将列连接到where子句中,并在那里传递完整的地址字符串(可能需要使用whereRaw,但我真的不确定,请注意SQL注入)。 - derekaug

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