I have to develop an api with Laravel and i'm stuck with this problem: I need to get all matchs and for each match i need to get the users who belongs to this match (there is 2 users per match)
I've search answer for this problem and i found this https://github.com/topclaudy/compoships but it didn't worked for me.
So far, i have this :
class Match extends Model
{
protected $table = 'matchs';
public $primaryKey = 'id';
public function playerOne() {
return $this->hasMany('App\User', 'id', 'playerOne_id');
}
public function playerTwo() {
return $this->hasMany('App\User', 'id', 'playerTwo_id');
}
}
Controller Method:
public function index()
{
$matchs = Match::with('playerOne', 'playerTwo')->orderBy('created_at', 'asc')->get();
return $matchs;
//return new MatchsCollection($matchs);
}
and my database look like this : (Matchs table)
id | playerOne_id | playertwo_id | winner_id | status
------------------------------------------------------------
1 | 1 | 3 | 0 | PENDING
2 | 2 | 1 | 0 | PENDING
3 | 3 | 2 | 0 | PENDING
and users table :
id | name | email
-----------------------------------
1 | John | [email protected]
2 | Mark | [email protected]
3 | Harry | [email protected]
and when i call my api i get this result:
[
{
id: 1,
playerOne_id: 1,
playerTwo_id: 3,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-10 00:00:00",
updated_at: null,
users: [
{
id: 1,
name: "John",
email: "[email protected]",
email_verified_at: null,
created_at: "2019-01-11 10:38:26",
updated_at: "2019-01-11 10:38:26"
}
]
},
{
id: 2,
playerOne_id: 2,
playerTwo_id: 1,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-11 08:26:28",
updated_at: "2019-01-11 08:26:28",
users: [
{
id: 2,
name: "Mark",
email: "[email protected]",
email_verified_at: null,
created_at: "2019-01-11 10:40:13",
updated_at: "2019-01-11 10:40:13"
}
]
},
{
id: 3,
playerOne_id: 3,
playerTwo_id: 2,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-11 08:45:22",
updated_at: "2019-01-11 08:45:22",
users: [
{
id: 3,
name: "harry",
email: "[email protected]",
email_verified_at: null,
created_at: "2019-01-11 10:40:13",
updated_at: "2019-01-11 10:40:13"
}
]
}
]
What i wan't to get is this result (i just show you the first match)
[
{
id: 1,
playerOne_id: 1,
playerTwo_id: 3,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-10 00:00:00",
updated_at: null,
users: [
{
id: 1,
name: "John",
email: "[email protected]",
email_verified_at: null,
created_at: "2019-01-11 10:38:26",
updated_at: "2019-01-11 10:38:26"
},
{
id: 3,
name: "Harry",
email: "[email protected]",
email_verified_at: null,
created_at: "2019-01-11 10:38:26",
updated_at: "2019-01-11 10:38:26"
}
]
}
]
is this possible in Laravel ? thanks :)
To be able to return all the players as part of the user
array you could either change the relation between Match
and User
to be a belongsToMany (many-to-many) or simply manipulate the match data before returning it from the controller.
Changing it to a BelongsToMany
would be my recommendation since it semantically makes more sense, however, I understand that (depending on how much work you've done so far) it may not be practical.
You would need to:
matchs
table to be matches
(this will also mean you can removeprotected $table = 'matchs';
from your Match
model class ).Create a table called match_user
. If your project is using migrations then you can run:
php artisan make:migration create_match_user_table --create=match_user
In that migration you would need to change the contents of the up()
method to be:
public function up()
{
Schema::create('match_user', function (Blueprint $table) {
$table->integer('match_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
$table->primary(['match_id', 'user_id']);
});
}
Run php artisan migrate
In your Match
model change the users()
relationship to be:
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
If the data you have in your tables is dummy data you can skip this step. Otherwise, you'll need to move the playerOne_id
and playertwo_id
information to the new pivot table. You could do that will the following:
Match::all()->each(function ($match) {
$match->users()->attach([$match->playerOne_id, $match->playertwo_id]);
});
It doesn't really matter where you run this as it only has to be run once so after you've run it you can delete it. I would usually run this in a route or in tinker.
Then comes the clean up. Again, if the data you have is just dummy data, then I would just remove the playerOne_id
and playertwo_id
the original migration, otherwise create a new migration that removes those field Dropping columns docs
Once the above has been done you would just need to do the following in your controller to get the results:
$matches = Match::with('users')->latest()->get();