Reputation: 433
I am developing a messaging system for my app, and currently, I have two tables:
1) messages
table:
Schema::create('messages', function (Blueprint $table) {
$table->increments('id');
$table->text('subject');
$table->integer('sender_id');
$table->text('body');
$table->timestamps('create_date');
$table->integer('sent_to_id');
});
2) users
table:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Currently, I can store messages and their subjects to the messages
table. Now, I want to pick the id
of the user I'm sending the message to. So that I can use it to create a conversation.
Is there any way I can list all the users and pick the preferred user that I want to send message to? or anyone with a messaging technique to help out?
Upvotes: 3
Views: 8699
Reputation: 18445
Your question is a bit vague and too broad. Anyway, I assume you want to enable users to send messages to other existing users in the system.
Before we start, please note that there are a lot of design decisions involved. I'll simply go with the easiest and quickest approach as it's just a demonstration to get you started.
In order to enable users to send messages to each other, you need to setup foreign keys in your database migrations, setup eloquent relationships and create helper methods to be used in your controller classes.
Pretty self-explanatory; but if you have no idea what I'm talking about, have a look at the documentation on foreign key constraints.
Your users
table migration needs no change for now, so I skip ahead to messages
table migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMessagesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('messages', function (Blueprint $table) {
$table->increments('id');
$table->integer('sender_id');
$table->integer('sent_to_id');
$table->text('body');
$table->text('subject');
// It's better to work with default timestamp names:
$table->timestamps();
// `sender_id` field referenced the `id` field of `users` table:
$table->foreign('sender_id')
->references('id')
->on('users');
// Let's add another foreign key on the same table,
// but this time fot the `sent_to_id` field:
$table->foreign('sent_to_id')
->references('id')
->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('messages');
}
}
This sets up foreign key constraints on your messages
table as the comments explain. Don't forget to: php artisan migrate:refresh [-seed]
.
First, have a look at the documentation on eloquent relationships. Then see how we setup the relationship between two of your models; Message
and User
.
Here's your App\Message
class:
<?php
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
protected $fillable = ['body', 'subject', 'sent_to_id', 'sender_id'];
// A message belongs to a sender
public function sender()
{
return $this->belongsTo(User::class, 'sender_id');
}
// A message also belongs to a receiver
public function receiver()
{
return $this->belongsTo(User::class, 'sent_to_id');
}
}
And your App\User
class:
<?php
namespace App;
use App\Message;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = ['name', 'email', 'password'];
// A user can send a message
public function sent()
{
return $this->hasMany(Message::class, 'sender_id');
}
// A user can also receive a message
public function received()
{
return $this->hasMany(Message::class, 'sent_to_id');
}
}
With these files in place, you'll have a solid eloquent API at your disposal. Look at these examples:
$user->sent // All messages sent by this user
$user->received // All messages received by this user
App\User::has('sent')->get() // Retrieve all users that have at lest one sent message
App\User::has('sent', '>', 2)->get()
$user->sent()->where('subject', 'Happy new year!')->first();
See the documentation for more examples or play with them in php artisan tinker
to see how powerful it is.
Now that you have your migrations and models in place. You need to utilize them to implement your inter-user messaging system.
This needs a lot of boilerplate code like routes, controllers, and views that I'm not gonna write down here. But I'm sure you can find your way through. I just add a sample usage example here.
I assume you gonna need a controller in order to let a user send a message to another one. Here's an example:
<?php
namespace App\Http\Controllers;
use Auth;
use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ConversationController extends Controller
{
public function sendMessage(Request $request)
{
// Do the validation...
// Send the message from the current user to the user with ID of 1,
// You probably always want the current logged-in user as the sender.
// We talk about the recipient later...
//
Auth::user()->sent()->create([
'body' => $request->body,
'subject' => $request->subject,
'sent_to_id' => 1,
]);
// Set flash message, render view, etc...
}
}
This will send a message from the logged-in user to the user with ID of 1
. Your question is was mainly about the recipient and how you can list users and choose from them. We'll get to that later.
This works, but it's not so clean. Let's wrap the logic in a model method instead:
class User extends Authenticatable
{
// ...
public function sendMessageTo($recipient, $message, $subject)
{
return $this->sent()->create([
'body' => $message,
'subject' => $subject,
'sent_to_id' => $recipient,
]);
}
}
Add this method to your App\User
model and have your controller code like this:
Auth::user()->sendMessageTo(1, $request->subject, $request->body);
Better, right?
The only remaining question is about the recipient ID. You probably have a form that users use to compose messages. It probably has a textarea named body
and subject input named subject
. You just need another input, so that the user can pass the ID of the recipient user as well. Then you just say:
Auth::user()->sendMessageTo($request->recipient, $request->subject, $request->body);
You probably want to use a dropdown (or an autocomplete widget) that lists the names of users. When rendering the form, you can add pass your users data to the view like this:
<?php
namespace App\Http\Controllers;
use Auth;
use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ConversationController extends Controller
{
public function composeMessage()
{
// ...
// Get a collection of `[id => name]` probable recipients,
// so that the logged-in user can choose from. Note that
// you probably want to exclude the current user herself
// from the list.
$users = User::where('id', '!=', Auth::id())->pluck('name', 'id');
return view('view.name', compact('users'));
}
}
Then, in your view you can render this data like this:
{{ Form::select('recipient', $users) }}
// See: https://laravelcollective.com/docs/5.3/html
Easy, right? It's untested code but hopefully, it gives you the idea.
After all this, why not using a well-designed, well-tested messaging package instead? Meet Laravel Messenger.
Upvotes: 13