我在我的模型中以这种方式定义了2个mutators:
public function setUrlAttribute($value) {
$this->url = $value;
$this->domain = parse_url($value, PHP_URL_HOST);
$this->fillSlug();
}
public function setTitleAttribute($value) {
$this->title = $value;
$this->fillSlug();
}
private function fillSlug() {
$this->slug = $this->createSlug($this->title) . '-' . $this->domain;
}
然而我注意到一些奇怪的事情 - 当我设置url和title时,以这种方式定义了访问器,实际上他们的新值没有被保存。但是,基于相同属性的(域和slug)会正确保存。
例如:
$model = Model::find(1); // url = 'http://oldurl.com', title = 'old title'
$model->url = 'http://testurl.com';
$model->title = 'test title';
$model->save();
$model = Model::find(1);
现在我的属性是:
url: oldurl.com
title: old title
domain: testurl.com
slug: test-title-testurl.com
这很奇怪,因为slug例如基于$this->title
,所以值应该相同但不是。
使其运作的解决方案是:
public function setUrlAttribute($value) {
$this->attributes['url'] = $value;
$this->domain = parse_url($value, PHP_URL_HOST);
$this->fillSlug();
}
public function setTitleAttribute($value) {
$this->attributes['title'] = $value;
$this->fillSlug();
}
private function fillSlug() {
$this->slug = $this->createSlug($this->title) . '-' . $this->domain;
}
所以不要直接访问属性,而是使用$this->attributes['key_name']
现在的问题 - 为什么在使用mutator的字段值为mutator时必须使用$this->attributes
按预期工作,而其他字段可以使用普通属性访问,即使是更改的值?
答案 0 :(得分:2)
<强> tldr;简单地说 - 在mutator中使用$this->title
在对象上创建public property
,稍后可以使用$model->title
访问它(它永远不会再遇到魔法__call
),它永远不会触及属性数组,所以实际上你并没有改变这个领域。
@AlleyShairu是对的,但无法解释会发生什么,所以在这里:
// having this mutator
public function setTitleAttribute($value)
{
$this->title = $value;
}
// and doing so:
$model->title; // 'old title'
$model->title = 'some string';
// then this is true:
$model->title; // 'some string'
// but
$model->getAttribute('title'); // 'old title'
也就是说,您的属性数组永远不会被该mutator触及,因此当您保存模型时,title
保持不变。
这就是为什么你应该在mutator中使用$this->attributes['attributeName']
,而不是直接调用$this->attributeName
。
作为一个注释:如果不是这样的话,你最终会对mutator进行无限递归调用。
答案 1 :(得分:1)
据我所知,如果你定义了mutator,Laravel不会处理该特定属性的setAttribute($key,$value)
。所以你需要使用
$this->attributes['key_name'] in your mutators.
你什么时候做$ this-&gt; domain = parse_url($ value,PHP_URL_HOST); Laravel实际上在做
$this->attributes[$key] = $value;
这就是setAttribute在laravel
中的样子public function setAttribute($key, $value)
{
// First we will check for the presence of a mutator for the set operation
// which simply lets the developers tweak the attribute as it is set on
// the model, such as "json_encoding" an listing of data for storage.
if ($this->hasSetMutator($key))
{
$method = 'set'.studly_case($key).'Attribute';
return $this->{$method}($value);
}
// If an attribute is listed as a "date", we'll convert it from a DateTime
// instance into a form proper for storage on the database tables using
// the connection grammar's date format. We will auto set the values.
elseif (in_array($key, $this->getDates()) && $value)
{
$value = $this->fromDateTime($value);
}
$this->attributes[$key] = $value;
}
正如您在setAttribute方法中看到的,如果存在mutator函数,它只调用该函数并且行$this->attributes[$key] = $value;
永远不会执行。