Model with multiple polymorphic fields

800 views Asked by At

I need to add a feature to my system, it's a stock control system.

The feature to be added is about the possibility to start chats in different models. I have Products, Sellers, ProductCollections and a lot of more objects and I need to start conversations within them.

So I thought about making a table with three polymorphic fields to make it fully reusable with any variants. This are the fields

sender_id
sender_type

topic_id
topic_type

receiver_id
receiver_type

And the proper fields to make the conversation possible (message, in_reply_of, etc...)

The sender and receiver needs to be polymorphic because a conversation could be made between SystemUsers and Customers.

Am I in the right way? Will this work in this way? Also I don't know how could I save the Chat entities.

1

There are 1 answers

2
prateekkathal On BEST ANSWER

If you want to set a chat for multiple sender, receiver and topics, I believe this relation is good to go.

Also, I was unable to to understand what you exactly mean by Chat entities but the below approach should clear out any doubts you might be having about this approach.

Below is how you can get things done!

Setting the Relations

Set the relations in the following manner

class Chat
{
  public function sender()
  {
    return $this->morphTo();
  }

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

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

class SystemUser
{
  public function sentChats()
  {
    return $this->morphMany('App\Chat', 'sender');
  }

  public function receivedChats()
  {
    return $this->morphMany('App\Chat', 'receiver');
  }
}

class Customer
{
  public function sentChats()
  {
    return $this->morphMany('App\Chat', 'sender');
  }

  public function receivedChats()
  {
    return $this->morphMany('App\Chat', 'receiver');
  }
}

class Illustrate
{
  public function illustrable()
  {
    return $this->morphTo();
  }

  public function chats()
  {
    return $this->morphMany('App\Chat', 'topic');
  }
}

Creating A Chat

How to create a chat

public function create()
{
  $inputs = request()->only([
    'sender_id', 'sender_type', 'receiver_id', 'receiver_type', 'topic_id', 'topic_type',
    'message', 'in_reply_of',
  ]);

  $sender = $this->getSender($inputs);
  $receiver = $this->getReceiver($inputs);
  $topic = $this->getTopic($inputs);

  if($sender && $receiver && $topic) {
    $chat = $sender->sentChats()->create([
              'receiver_id' => $receiver->id,
              'receiver_type' => get_class($receiver),
              'topic_id' => $topic->id,
              'topic_type' => get_class($topic),
              'message' => $inputs['message'],
              'in_reply_of' => $inputs['in_reply_of'],
            ]);
  }
}

private function getSender($inputs)
{
  if(isset($inputs['sender_type'], $inputs['sender_id']) && is_numeric($inputs['sender_id'])) {
    switch($inputs['sender_type']) {
      case 'SystemUser':
        return SystemUser::find($inputs['sender_id']);
      case 'Customer':
        return Customer::find($inputs['sender_id']);
      default:
        return null;
    }
  }
}

private function getReceiver($inputs)
{
  if(isset($inputs['receiver_type'], $inputs['receiver_id']) && is_numeric($inputs['receiver_id'])) {
    switch($inputs['receiver_type']) {
      case 'SystemUser':
        return SystemUser::find($inputs['receiver_id']);
      case 'Customer':
        return Customer::find($inputs['receiver_id']);
      default:
        return null;
    }
  }
}

private function getTopic($inputs)
{
  if(isset($inputs['topic_type'], $inputs['topic_id']) && is_numeric($inputs['topic_id'])) {
    switch($inputs['topic_type']) {
      case 'Illustrate':
        return Illustrate::find($inputs['topic_id']);
      default:
        return null;
    }
  }
}

Getting a chat

public function get($id) {
  $chat = Chat::find($id);

  $sender = $chat->sender;

  // Inverse
  // $systemUser = SystemUser::find($id);
  // $systemUser->sentChats->where('id', $chatId);

  $receiver = $chat->receiver;

  // Inverse
  // $customer = Customer::find($id);
  // $customer->receivedChats->where('id', $chatId);

  $topic = $chat->topic;

  // Inverse
  // $illustrate = Illustrate::find($id);
  // $illustrate->chats;
}

Note :- Please understand I haven't tested any of this... This is just a small example on how you can get things done.

Let me know if you face any issues understanding this.