2013-12-02 1 views
8

У меня есть 2 модели с отношением «многие ко многим». Я хочу, чтобы иметь возможность установить определенный атрибут с массивом идентификаторов и сделать отношения в мутатором так:Laravel сохранить отношения «многие ко многим» в «Красноречивых мутаторах»

<?php 

class Profile extends Eloquent { 

    protected $fillable = [ 'name', 'photo', 'tags' ]; 
    protected $appends = [ 'tags' ]; 

    public function getTagsAttribute() 
    { 
     $tag_ids = []; 
     $tags = $this->tags()->get([ 'tag_id' ]); 

     foreach ($tags as $tag) { 
      $tag_ids[] = $tag->tag_id; 
     } 

     return $tag_ids; 
    } 

    public function setTagsAttribute($tag_ids) 
    { 
     foreach ($tag_ids as $tag_id) { 
      $this->tags()->attach($tag_id); 
     } 
    } 

    public function tags() 
    { 
     return $this->belongsToMany('Tag'); 
    } 

} 

<?php 

class Tag extends Eloquent { 

    protected $fillable = [ 'title' ]; 
    protected $appends = [ 'profiles' ]; 

    public function getProfilesAttribute() 
    { 
     $profile_ids = []; 
     $profiles = $this->profiles()->get([ 'profile_id' ]); 

     foreach ($profiles as $profile) { 
      $profile_ids[] = $profile->profile_id; 
     } 

     return $profile_ids; 
    } 

    public function profiles() 
    { 
     return $this->belongsToMany('Profile'); 
    } 

} 

Однако функция setTagsAttribute не работает, как ожидалось. Я получаю следующее сообщение об ошибке: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'profile_id' cannot be null (SQL: insert into profile_tag ( profile_id , tag_id ) values (?, ?)) (Bindings: array (0 => NULL, 1 => 1,))

ответ

19

Вы не можете прикреплять отношения «многие ко многим», пока не сохраните модель. Вызовите save() на модели перед настройкой $model->tags, и все будет в порядке. Причина этого в том, что модель должна иметь идентификатор, который Laravel может помещать в сводную таблицу, для которой требуется идентификатор обеих моделей.

+1

А, я вижу. Я надеялся, что смогу использовать функции mutator для установки отношений на своих моделях без необходимости писать код вручную все время. –

-1

Не доступ тегов с помощью функции tags(), а использовать tags свойство. Используйте имя функции, если вы хотите поместить дополнительные параметры в запрос отношения и свойство, если хотите просто захватить теги. tags() работает в вашем геттере, потому что вы используете get() на конце.

public function setTagsAttribute($tagIds) 
{ 
    foreach ($tagIds as $tagId) 
    { 
     $this->tags->attach($tagId); 
    } 
} 
+0

Я пробовал это, но я получаю следующую ошибку: 'Вызов функции-члена attach() для не-объекта' –

+0

Скобки необходимы при выполнении запросов. Свойство является эквивалентом поиска отношений, но не используется для выполнения запросов. См. Http://laravel.com/docs/eloquent#inserting-related-models –

2

Попробуйте использовать метод синхронизации:

class Profile extends Eloquent { 
    protected $fillable = [ 'name', 'photo', 'tags' ]; 
    protected $appends = [ 'tags' ]; 

    public function getTagsAttribute() 
    { 
     return $this->tags()->lists('tag_id'); 
    } 

    public function setTagsAttribute($tag_ids) 
    { 
     $this->tags()->sync($tagIds, false); 
     // false tells sync not to remove tags whose id's you don't pass. 
     // remove it all together if that is desired. 
    } 

    public function tags() 
    { 
     return $this->belongsToMany('Tag'); 
    } 

} 
+0

не уверен, какая версия Laravel, которую вы используете ... Синхронизация не используется, чтобы использовать второй параметр: [sync api] (http: //laravel.com/api/source-class-Illuminate.Database.Eloquent.Relations.BelongsToMany.html#452-483). Это приведет к удалению всех остальных идентификаторов из сводной таблицы. – TonyArra

+0

@TonyArra sync получил второй параметр, равный 4.0.6, или 4 месяца назад. Конкретное изменение произошло шесть месяцев назад. https://github.com/laravel/framework/blob/v4.0.6/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php#L483 - Очевидно, что api docs устарели в этом случае. –

3

Похоже, вы вызываете функцию неправильно или неинициализированная модель. Ошибка говорит, что profile_id имеет значение NULL. Поэтому, если вы вызываете функцию как $profile->setTagsAttribute(), вам нужно убедиться, что $ profile инициализирован в базе данных с идентификатором.

$profile = new Profile; 
//will fail because $profile->id is NULL 
//INSERT: profile->save() or Profile::Create(); 
$profile->setTagsAttribute(array(1,2,3)); 

Кроме того, вы можете передать массив в функцию придает подключить несколько моделей одновременно, например, так:

$this->tags()->attach($tag_ids); 

Вы можете также передать его модель вместо ID (но уверены, массив моделей не будет работать)

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