How to save entries in many to many polymorphic relationship in Laravel?

25,405

You can use all of the belongsToMany methods for this, for polymorphic many-to-many extends that relation:

// 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)

All of those methods work both ways of course.


Examples:

$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

Your case:

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!');
});
Share:
25,405

Related videos on Youtube

chipit24
Author by

chipit24

Updated on July 19, 2020

Comments

  • chipit24
    chipit24 almost 4 years

    I have an Org model and a Tag model. I want to associate tags with organizations. My database tables and Eloquent models are set up like so ...

    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');
        }
    }
    

    In my view, I have a form with a multiple select box where the user can select the tags he/she wants to be associated with the organization ...

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

    ... And $tag_options comes from my routes.php file ...

    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);
    });
    

    When the form in my view is submitted, the following route will catch it to update the org model ...

    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!');
    });
    

    Now, Input::get('tags') is just an array of the tag IDs, of the form

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

    How can I use this to associate the tags with the organization?

    I also have comments set up for organizations using a polymorphic relationship where I just do this ...

    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!');
    });
    

    However, it's not as simple with a many-to-many polymorphic relationship when I want to associate one or more tags with an organization.

    Any help is appreciated, thanks!!

  • chipit24
    chipit24 almost 10 years
    This doesn't really help me. Can you give an example of how I can use this for my situation? I have updated my question so it should be a bit more clear (hopefully).
  • Jarek Tkaczyk
    Jarek Tkaczyk almost 10 years
    So the question is how to sync array of tags' ids with organization? Then my answer covers that. Anyway check the edit in a sec.
  • chipit24
    chipit24 almost 10 years
    Sorry, I have not even heard of polymorphic relations before and was having some trouble wrapping my head around them. Using sync works perfectly, thanks a lot!!
  • Victor
    Victor about 9 years
    By the way, when I use save or attach method it seems like Laravel adds multiple records (like in case you use sync with false flag).
  • Jarek Tkaczyk
    Jarek Tkaczyk about 9 years
    @Victor save and attach may create duplicates. sync will never do that, with or without the $detach = false flag.
  • Saugat Thapa
    Saugat Thapa almost 7 years
    @JarekTkaczyk does the values insert on tagables table too by laravel using sync??
  • Jarek Tkaczyk
    Jarek Tkaczyk almost 7 years
    @SaugatThapa have you tried? What result did you get?
  • Saugat Thapa
    Saugat Thapa almost 7 years
    @JarekTkaczyk updated_at and created_aat didnt have timestamp inserted