2014-10-05 40 views
1

我在我的模型中定義的2個存取器是這樣的:存取器 - 訪問屬性差異

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和標題的新值沒有保存。但是(域和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 

這是很奇怪的,因爲塞的例子是$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']

現在的問題 - 爲什麼突變使用現場的存取器值時,必須使用$this->attributes使用按預期工作,而其他字段即使對於更改的值也可以使用正常的屬性訪問?

回答

2

tldr;簡單地說 - 在增變器中使用$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' 

這就是說,你的屬性陣列從未與突變感動,所以當你保存模型, title保持不變。

這就是爲什麼你應該在增變器中使用$this->attributes['attributeName'],而不是直接調用$this->attributeName

作爲說明:如果不是這種情況,您最終將無限遞歸調用mutator。

+0

所以在mutator中我應該使用'$ this-> attributes' - 現在已經很清楚了。但是增肌的其他領域呢?我可以使用'$ this-> property'訪問其他字段,或者在右側使用'$ this-> property'作爲突變屬性嗎?我的意思是我的第二個解決方案 - 現在是完全安全還是'fillSlug',爲了以防萬一,我還應該使用'$ this-> attributes ['title']'而不是'$ this-> title'? – 2014-10-06 08:30:53

+0

只要沒有設置,您就可以使用' - > property',但是獲取(當然訪問器會被調用,如果有的話)。如果在'fillSlug'中引用'slug'屬性,那麼你可以像這樣使用它,但是記住它會觸發mutator,如果你定義一個'slug' attr有一天。 – 2014-10-06 09:08:35

1

從我知道如果你已經定義了增變器Laravel不處理該特定屬性的setAttribute($key,$value)。所以,你需要使用

$this->attributes['key_name'] in your mutators. 

當過你正在做這 - $>域= parse_url($值,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方法看是否存在突變的功能,它只是調用該函數和線$this->attributes[$key] = $value;從未執行。

+0

好的,但是爲什麼在第一種情況下金屬塊正確創建(它使用'$這個 - > title')並且此屬性使用set'$這 - >標題= $值;'不使用'$這 - >屬性'。在這種情況下,屬性和普通屬性變成2個不同的集合? – 2014-10-05 12:18:01

+0

我看到你的觀點,'$ this-> title'也從屬性數組中獲取它的值。這確實是一種奇怪的行爲,或者我們錯過了什麼?期待解決方案。 – 2014-10-05 13:45:04

+1

這種由__set調用的雄辯方法允許您通過動態屬性訪問屬性。該數組中的所有屬性都可以通過動態屬性自動訪問。它由該方法的最後一行處理。 $ model-> attribute ='';調用調用setAttribute的__set。和$ model->屬性;調用調用getAttribute的__get。這都是基於魔術方法__get和__set。 – lagbox 2014-10-05 14:24:04