简体   繁体   中英

How to make complicated polymorphic relationships in laravel 8?

We are just switching to laravel in my workplace and I still have problems with using more complicated relationships.

I have the following models:

Company

  • id
  • name
  • ...

Domain

  • id
  • url
  • company_id -> belongs to Company
  • ...

CommunicationEvent

  • id
  • name (like: OrderPlaced)
  • ...

Email

  • id
  • name
  • subject
  • body
  • company_id -> belongs to Company
  • ...

SMS similary to Email

Every Company should be able to set the communication to be used in an Event and in an event multiple type of communications can be used. For example, if an OrderPlaced event fires they can choose to have both an email and an SMS to be sent. Moreover they can set a default email/sms for all of their domains in an event and just overwrite it for one of their domains to use a different one there.

My first shot was to make a pivot table with event_id, company_id, domain_id(nullable for default) and communicable_id/type. I made a test relationship like this into CommunicationEvent:

public function mails(){
    return $this->morphToMany('App\Models\Mail', 'communicable', 'comm_event_comms', 'event_id', 'communicable_id')->where('comm_event_comms.company_id', 1);
}

And I put dummy data into the table, but $event->mails returns empty. Reading the documentation made me think I'm not on the right track.

Honestly, I don't really know how to properly connect these models so I can use them easyly. The only way I could make it work was to use DB::where... queries, but nothing with relationships. :(

Can you please help to build a relationship between these models?

I realized what was the problem with the relationship. I should have used morphedByMany instead of morphToMany . Thanks to miken32 I reread documentation and realized this on 3rd read.

The right relationship in communicationEvent:

public function mails(){
        return $this->morphedByMany('App\Models\Communication\Mail', 'communicable', 'communicables', 'event_id')->where('communicables.company_id', DData::getCompanyId());
    }

I also changed the name of the pivot table to communicables for convention.

Like that $event->mails()->attach($mail_id, ['company_id' => DData::getCompanyId()]); works perfectly to set default email communication for event. And setting domain specific communication works as well with additional domain_id data in attach.

I can use $event->mails as well for select.

The only problem that remained is detaching. As I read here :

...if you're storing other data on a "pivot" it's not really a pivot anymore...

I don't think I will be able to solve that with a simple detach() method so I used db queries like this:

DB::table('communicables')->where([
                            ['event_id', $event->id],
                            ['domain_id', NULL],
                            ['company_id', DData::getCompanyId()]
                        ])->delete();

I will have to search for communicable type as well when I connect the SMS model, but I decided it is a good enough solution. Other solution would have been to make a separate model for comminicables table, but I didn't wanted that.

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