web-dev-qa-db-ja.com

Laravelで多対多の多形関係のエントリを保存する方法は?

OrgモデルとTagモデルがあります。タグを組織に関連付けたい。私のデータベーステーブルとEloquentモデルは次のように設定されています...

org
    id - integer
    name - string
    ...

tags
    id - integer
    name - string

taggables
    id - integer
    taggable_id - integer
    taggable_type - string

// app/models/Org.php
class Org extends Eloquent
{
    protected $table = "org";

    ...

    public function tags()
    {
        return $this->morphToMany('Tag', 'taggable');
    }
}

// app/models/Tag.php
class Tag extends Eloquent
{
    protected $table = "tags";
    public $timestamps = false;

    public function org() 
    {
        return $this->morphedByMany('Org', 'taggable');
    }
}

私の見解では、ユーザーが組織に関連付けたいタグを選択できる複数選択ボックスのあるフォームがあります...

...
{{ Form::select('tags[]', $tag_options, null, array(
        'multiple',
        'data-placeholder' => 'Select some tags'))
}}
...

...そして$ tag_optionsは私のroutes.phpファイルから来ています...

View::composer('*', function($view)
{
    $tags = Tag::all();

    if(count($tags) > 0)
    {
        $tag_options = array_combine($tags->lists('id'),
                                    $tags->lists('name'));
    }
    else
    {
        $tag_options = array(null, 'Unspecified');
    }

    $view->with('tag_options', $tag_options);
});

私のビューのフォームが送信されると、次のルートがそれをキャッチして組織モデルを更新します...

Route::put('org/{org}', function(Org $org){
    $org->description = Input::get('description');
    $org->website = Input::get('website');
    $org->tags = Input::get('tags');
    $org->save();

    return Redirect::to('org/'.$org->id)
        ->with('message', 'Seccessfully updated page!');
});

ここで、Input :: get( 'tags')は、フォームのタグIDの単なる配列です。

["1","6","8"]

これを使用してタグを組織に関連付けるにはどうすればよいですか?

また、私がこれを行うだけの多態的な関係を使用している組織に対して設定されたコメントもあります...

Route::put('org/post/{org}', function(Org $org){
    $comment = new Comment;
    $comment->user_id = Auth::user()->id;
    $comment->body = Input::get('body');
    $comment->commentable_id = $org->id;
    $comment->commentable_type = 'Org';
    $comment->save();

    return Redirect::to('org/'.$org->id)
        ->with('message', 'Seccessfully posted comment!');
});

ただし、1つ以上のタグを組織に関連付けたい場合、多対多の多態的な関係ではそれほど単純ではありません。

助けてくれてありがとう、ありがとう!!

18
chipit24

これにはすべてのbelongsToManyメソッドを使用できます。多態性の多対多の場合は、その関係を拡張します。

// I would call that relation on tag in plural 'entities()' to be more accurate

$tag->entities()->save(new or existing model, array of pivot data, touch parent = true) (used on existing model)
$tag->entities()->saveMany(array of new or existing models, array of arrays with pivot data)
$tag->entities()->attach(existing model / id, array of pivot data, touch parent = true)
$tag->entities()->sync(array of ids, detach = true)
$tag->entities()->updateExistingPivot(pivot id, array of pivot data, touch)

これらの方法はすべて、もちろん両方の方法で機能します。


例:

$tag = Tag::first();
$entity = Entity::find(10);

// save() works with both newly created and existing models:
$tag->entities()->save(new Entity(...));
$tag->entities()->save($entity);

// saveMany() like above works with new and/or existing models:
$tag->entities()->saveMany([$entity, new Entity(...)]);

// attach() works with existing model or its id:
$tag->entities()->attach($entity);
$tag->entities()->attach($entity->id);

// sync() works with existing models' ids:
$tag->entities()->sync([1,5,10]); // detaches all previous relations
$tag->entities()->sync([1,5,10], false); // does not detach previous relations, attaches new ones skipping existing ids

あなたの場合:

Route::put('org/{org}', function(Org $org){

  $org->description = Input::get('description');
  $org->website = Input::get('website');
  $org->save();

  $org->tags()->sync(Input::get('tags'));

  // or if you don't want to detach previous tags:
  // $org->tags()->sync(Input::get('tags'), false);


  return Redirect::to('org/'.$org->id)
    ->with('message', 'Seccessfully updated page!');
});
57
Jarek Tkaczyk