2014-10-05 2 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.

В качестве примечания: если бы это было не так, вы получили бы бесконечный рекурсивный вызов мутатору.

+0

Итак, в мутаторе я должен использовать '$ this-> attributes' - теперь это понятно. Но как насчет других полей в мутаторе? Могу ли я получить доступ к другим полям с помощью '$ this-> property' или даже использовать свойство $ this-> для мутированного атрибута, когда он находится на правой стороне? Я имею в виду мое второе решение - теперь это полностью безопасно или, возможно, для 'fillSlug', я должен использовать атрибуты $ this-> ['title']' вместо '$ this-> title' на всякий случай? –

+0

Вы можете использовать свойство '->', если оно не установлено, но получение (конечно, аксессоры будут вызваны, если они есть). Если в 'fillSlug' вы ссылаетесь на атрибут' slug', вы можете использовать его именно так, но имейте в виду, что он вызовет мутатор, если вы определите один из них для 'slug' attr один день. –

1

Из того, что я знаю, если вы определили мутатор, Laravel не обрабатывает setAttribute($key,$value) для этого конкретного атрибута. Так что вам нужно получить к нему доступ с помощью

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

Если когда-нибудь вы делаете $ this-> домен = 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

Хорошо, но почему в первом случае slug создается правильно (он использует '$ this-> title'), и это свойство устанавливается с помощью' $ this-> title = $ value; 'без использования атрибутов $ this-> '. В этом случае атрибуты и нормальные свойства становятся 2 разными наборами? –

+0

Я вижу вашу точку, а '$ this-> title' также получает значение из массива атрибутов. Это действительно странное поведение или мы что-то упускаем? С нетерпением ждем решения. –

+1

Этот метод от красноречивого, который вызывается __set, позволяет вам получить доступ к атрибутам с помощью динамических свойств. Все атрибуты в этом массиве автоматически доступны через динамические свойства. Он обрабатывается последней строкой этого метода. $ model-> attribute = ''; вызывает __set, который вызывает setAttribute. и $ model->; вызывает __get, который вызывает getAttribute. Все это основано на магических методах __get и __set. – lagbox

Смежные вопросы