I'm trying to figure out what is an elegant way to organize the following workflow
- Submit form ( the form contains the
title of the conversation, the body of the message and the name of the invited participant.
- Create a conversation
- associate the message with the conversation
- associate the participant with the conversation
- notify the participant that a new conversation is created
My current approach is the following:
- I validate all the input values in the form request and then i call
persist() to create the conversation.
- Then i associate the participants with the converastion
- I associate the message with the conversation
- finally i fire an even that the conversation was created
ConversationController
public function store(Request $request, CreateConversationRequest $conversationRequest)
{
$conversation = $conversationRequest->persist();
$conversation->addParticipants(
$request->input('participants'),
$request->boolean('admin')
);
$conversation->addMessage(
$request->input('message')
);
event(new NewConversationWasCreated($conversation));
}
public function addMessage($message, $user = null)
{
$message = $this->messages()
->create([
'body' => $message,
'user_id' => $user ? $user->id : auth()->id(),
]);
event(new NewMessageWasAddedToConversation($this, $message));
return $message;
}
public function addParticipants(array $usernames, $admin = false)
{
$participantIds = $this->getParticipantIds($usernames);
foreach ($participantIds->toArray() as $participantId) {
$participants[$participantId] = ['admin' => $admin];
}
$this->participants()->syncWithoutDetaching($participants);
event(new NewParticipantsWereAdded($this, $participantIds));
}
The Issue is
I think that the ConversationController as well as the Conversation model have too much logic.
-
First Alternative
Move the logic from the controller in the persist method of the Form request
( For some reason it doesn't look like a good idea to put everything in the form request)
-
Second Alternative
Create a CreateConverastionService
I was thinking that if i create a service to encapsulate all the steps for creating a conversation
Then probably i would have to get rid of the form request which means that i should handle the validation of the inputs within the service.
class ConversationCointroller extends Controller
{
public function store(Request $request)
{
(new CreateConversationService($request))->handle();
}
{
class CreateConversationService
{
protected $request;
public function __construct(Request $request)
{
$this->request = request;
}
public function handle()
{
$this->validate();
$conversation = Conversation::create(
[
'user_id' => auth()->id()
'title' => $this->request->input('title')
]
$conversation->addParticipants(
$this->request->input('participants'),
$this->request->boolean('admin')
);
$conversation->addMessage(
$this->request->input('message')
);
event(new NewConversationWasCreated($conversation));
}
{
With regards to the methods addParticipants and addMessage, maybe i could keep them but instead of implementing the logic inside the methods, i could call another service to handle all the logic for ***adding a participant and adding a message .
public function addParticipants(array $usernames, $admin = false)
{
(new (AddParticipantToConversationService($this, $usernames, $admin))->handle();
}
public function addMessage($message, $user = null)
{
(new(AddMessageToConversationService($this, $message, $user))->handle();
}
Which one do you think is the better approach ?
Any other suggestion is welcome of course.