Correct way to set up this Laravel relationship? - php

I'm after a bit of logic advice. I am creating a system where users login and register their participation at an activity. They can participate at an activity many times. What is the best way to do this? I want to ensure I can use eloquent with this rather than creating my own functions.
I am imagining...
Users:
id
Activitys:
id
name
Participations:
id
user_id
activity_id
time_at_activity
I want to later be able to do such things as:
$user->participations->where('activity_id', 3)
for example.
What is the best way to set this up? I had in mind..
User: hasMany->Participations
Activity: belongsTo->Participation
Participation: hasMany->Activitys & belongsTo->User
Does this look correct?

The users schema can relate to activities through a pivot table called participations:
/**
* Indicate that the model belongs to a user.
*
* #see \App\Model\User
*
* #return BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Indicate that the model belongs to many activity participations.
*
* #see \App\Model\Activity
*
* #return BelongsTo
*/
public function participations()
{
return $this->belongsToMany(Activity::class, 'participations');
}
$user->participations()->attach($activity);
You may want to add the reciprocal relationships. These can be separated out into traits for code reuse. ->attach(['participated_at' => now()])

You can use Many-to-Many Relationship.
Use Participation as your pivot table. Define relationships as
/* in User */
public function activity()
{
return $this->belongsToMany('App\Models\Activitys','participation','user_id','activity_id')->as('participation')->withPivot('time_at_activity');
}
/* in Activity */
public function user()
{
return $this->belongsToMany('App\Models\Users','participation','activity_id','user_id')->as('participation')->withPivot('time_at_activity');
}

DB schema
// App\User
public function participations()
{
return $this->hasMany('App\Participation');
}
// You may create App\Participation Model
// App\Participation
public function user()
{
return $this->belongsTo('App\User');
}
// Controller
$userParticipations = $user->participations->where('activity_id', 3);
// eager loading version
$userWithParticipations = $user->with(['participations' => function($q) { $q->where('activity_id', 3) }])->get();

Related

Laravel / Eloquent : hasManyThrough question

I have 3 tables:
Contract, with id
Contract_User, with contract_id and user_id
User, with id
I'm trying to use hasManyThrought to get the User information when I have a contract, but I'm having trouble.
Is it possible?
Thanks
I agree with Tim Lewis. I think this is just a "simple" BelongsToMany. Depending on what your models look like, here is an example of what they could/should look like.
If you are using something other than the default foreign keys, you'll need to provide those column(s) as extra parameters. You can find more on that in the link above as well. Hope this helps!
User.php
/**
* The contracts that belong to the user.
*/
public function contracts()
{
return $this->belongsToMany('App\Contract');
}
Contract.php
/**
* The users that belong to the contract.
*/
public function users()
{
return $this->belongsToMany('App\User');
}
Then somewhere in your controller, you'd get to the user's contracts by:
$user = App\User::find(1);
foreach ($user->contracts as $contract) {
// $contract->name;
}

Laravel 5.3 get belongsToMany and count pivot

I have next models:
class Polling extends Model
{
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function participants()
{
return $this->belongsToMany(Participant::class, 'participant_poll', 'poll_id');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function results()
{
return $this->belongsToMany(Participant::class, 'poll_results', 'poll_id');
}
}
class Participant extends Model
{
public function polls()
{
return $this->belongsToMany(Polling::class);
}
public function results()
{
return $this->belongsToMany(Polling::class);
}
}
poll_results - pivot table have structure: id, poll_id, participant_id.
I need view next table:
№|participant.name|Count vote|
1|Mike |15 |
2|................|10 |
..............................
Count vote get pivot table poll_results.
Help please, write query.
$poll = Polling::first();
$poll->participants()->get();
You may want to use withCount() method.
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models
Your query would look like this one:
Participant::withCount('polls')->get();
This will add new property to results called polls_count

Laravel relationship query optimization

First of all I apologise for the title, I could not find anything better.
In my project I have Users and Groups. Users can join a group and create a group. The relationships are defined as follows.
User Model
/** Get all the groups the user is administrator of
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function groupsAdmin()
{
return $this->hasMany('App\Group','group_admin_id','id');
}
Group Model
/** Get the users in a group
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function users()
{
return $this->belongsToMany(\App\User::class,'groups_users', 'group_id','user_id');
}
What I am trying to do is get all the users who have joined the groups created by an user. For that I have written a method in my User model:
/**
* Returns all the users who have attended groups created by this user
*/
public function getPastGroupAttendees()
{
// first verify if the user is admin of any group
if(!$this->groupsAdmin)
{
return false;
}
$attendees = array();
foreach($this->groupsAdmin as $group)
{
if(count($group->users) > 0) $attendees[] = $group->users;
}
return $attendees;
}
But the problem with this method is its slow and will get slower with new data. And also as a user can join multiple groups, I would get duplicate users from this method.
So if anyone can show me some directions to optimize and correct this it would be very helpful.
You can setup two relations in User model:
public function groupsAdmin()
{
return $this->hasMany('App\Group', 'group_admin_id', 'id');
}
public function groups()
{
return $this->belongsToMany('App\Group');
}
It's one-to-many for admin and many-to-many for groups and users (you'll need pivot table here).
To load the data, use eager loading:
$groupWithUsers = Group::where('group_admin_id', $adminId)->with('users')->first();
$groupsOfUsers = User::with('groups')->get();
To remove duplicates you can iterate over groups and merge() all users collections into one and then use unique() method to remove duplicates.
Another way to do it is to create model for pivot table and get all users of the group with simple and readable code:
$groups = Group::where('group_admin_id', $adminId)->pluck('id'); // Get IDs of groups.
UserGroup::whereIn('group_id', $groups)->get()->unique(); // Get unique users from these groups.

Laravel 5.3 Different Fields Per User Role Type how to implement this using polymorphism?

Title says it all
For example
I want the main laravel User Model to have different kinds of roles and every role
has different fields
Example
User has a role of Employee
Where that role will have different fields for the user
You don't need to use polymorphism here. User model used by Laravel so, you should keep all similar data in this model. Then create Employee and other models. Then you should add one to one relation between User and all other models.
class User extends Model
{
public function employee()
{
return $this->hasOne('App\Employee');
}
}
You can do it like this, using Polymorphic Relationship :
Table structure would be:
managers
id - integer
title - string
body - text
employees
id - integer
title - string
url - string
users
id - integer
body - text
userable_id - integer
userable_type - string
roles
id - integer
name - string
description - text
role_user
id - integer
role_id - integer
user_id - integer
And Models would be designed as:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get all of the owning userable models.
*/
public function userable()
{
return $this->morphTo();
}
/**
* User and Roles relationship
*/
public function roles()
{
return $this->belongsToMany('App\Roles');
}
}
class Employee extends Model
{
/**
* Get all of the employee's comments.
*/
public function comments()
{
return $this->morphMany('App\Employee', 'userable');
}
}
class Manager extends Model
{
/**
* Get all of the manager's comments.
*/
public function comments()
{
return $this->morphMany('App\Manager', 'userable');
}
}
class Role extends Model
{
/**
* Relationship with User and Role Models
*/
public function users()
{
return $this->belongsToMany('App\User');
}
}
Hope this helps!

Polymorphic many to many from User to Post and Category

I need to implement a follow system like twitter but with exception a user can follow many Post and can follow whole Category or a user can follow a User.
I have come up with this relationship. I am using Laravel 5.1
User Model
public function followers()
{
return $this->belongsToMany('App\User', 'user_follows', 'user_id', 'follow_id');
}
public function follows()
{
return $this->belongsToMany('App\User', 'user_follows', 'follow_id', 'user_id');
}
and for follow a Category
Category Model
public function followers()
{
return $this->belongsToMany('App\User', 'category_follows', 'user_id', 'category_id');
}
and for Post is the same way, as you can see I need 3 tables (user_follows, category_follows, post_follows) to make this work.
I know there is Polymorphic Relation but I cant wrap my head around it.
Please help how i can simplify it. once again below are the requirements
User can follow many Posts
User can follow many Category
User can follow many User
You can use morphedByMany to create polymorphic many to many relations. Instead of having separate *_follows tables, you can have a single followables table with the following schema:
user_id int # user_id that is following something
followable_id int # id of the thing that is being followed
followable_type string # type of the thing that is being followed
Here's a sample implementation:
Category, Post and User models
/*
* This function gets the followers of this entity. The
* followable_id in the followables relation would be
* the id of this entity.
*/
function followers() {
return $this->morphToMany('App\User', 'followable');
}
User model
/*
* Gets the list of users that are followed by this user.
*/
function users() {
return $this->morphedByMany('App\User', 'followable');
}
/*
* Gets the list of posts that are followed by this user.
*/
function posts() {
return $this->morphedByMany('App\User', 'followable');
}
/*
* Gets the list of categories that are followed by this user.
*/
function categories() {
return $this->morphedByMany('App\User', 'followable');
}
Note that in this case, a User is both morphed by many and morphed to many, creating a self-reference many to many relationship.
Every new followable entity you create, you will need to add the followers() function to that entity, and a corresponding inverse relation to the Users entity. You could define a Followable trait containing that function, and simply add use Followable; to the new entity you add.

Categories