简体   繁体   中英

Laravel Polymorphic relation overwrites on save

I have a polymorphic relation on Categories, they can belong to a Client or a Template.

I'm trying to assign a Category from a Template, to a Client. But it's overwriting my Template categories.

Category Model

class Category extends Model
{

    public function categorisable()
    {
        return $this->morphTo();
    }
}

Client Model

class Client extends Model
{
    public function categories()
    {
        return $this->morphMany(Category::class, 'categorisable');
    }
}

Template Model

class Template extends Model
{
    public function categories()
    {
        return $this->morphMany(Category::class, 'categorisable');
    }
}

This is the code I'm trying to copy over the Categories from the Template to the Client

$template = Template::find($request->get('template_id'));
$client = Client::find($request->get('client_id'));

// For this template, get all categories
foreach($template->categories as $category) {
    $client->categories()->save($category);
}

But then it's overwriting the two categories in my categories table. So saving them on the Client, but removing them from the template.

This makes sense. Your table for Category model has two columns, one is for the type of the model it's attached to, the other is for the id (probably something as categorisable_type (which would be something like "App\\Models\\Template") and categorisable_id (which would be something like "4")).

Hence everytime you re-assign already existing Category, it rewrites these two columns from the Template model to the Client model (so it changes to something like "App\\Models\\Client" and "6", for example).

You have several options here:

1) Your relationship type is actually not ideal. You can use simple one2many here. Create several cateogries and then have a category_id on your Template and Client model. This way you'll be able to use the same Category on both Template and Client.

2) If you need to have several categories attached to each Template or Client, use many2many relationship. The rest is similar to option 1, you'll just have two more tables, something like category_client and category_template , assuming you follow the Laravel naming convention, but you can really use anything, you just need to specify it in the relationship method.

3) You can also use many2many polymorphic relationship. You'll end up with clients , templates , categories and categorisable tables. categories table will just hold the Category, categorisable will have the relationship definition, similar to option 2.

4) If you insist on using one2many polymorphic relationships here (advice: don't), you can clone each template for every client you're assigning it to, but that makes zero sense and you actually won't have the same category attached to your Template or Client , just the clone of the original, hence you won't be able to reverse access multiple templates or client from the Category , as they both belong to different category.

Methods 1 and 2 actually reverse the entire relationship in the correct order, since your current logic is inversed and, as mentioned, not ideal.

More info here - https://laravel.com/docs/5.4/eloquent-relationships (For Laravel 5.4, which is the latest release at the time I'm writing this).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM