Laravel many-to-many - laravel

I've Googled for a while and found multiple threads discussing problems like this, but I just can't get my head around how to do exactly what I want to do, hope someone can point me in the correct direction.
I'm making a learning platform in Laravel. What I want right now is that when lesson A is completed by someone belonging to workplace B a notification should be sent to user C. So I have made a table notification_receivers containing lesson_id, workplace_id, and user_id, pointing to the respective tables.
Of course, I also have the corresponding models (User, Lesson, Workplace) set up, but what I can't understand is exactly how to set up the model relations. I'm currently making the Blade template used for editing the notification receivers belonging to a particular lesson, and I need to make the following: Get all notification receiver users for this lesson and then for every one of those users, get the related workplaces.
My first try was this in the Lesson model:
public function notification_receivers(): BelongsToMany
{
return $this->belongsToMany('App\User', 'notification_receivers')->withPivot(["workplace_id"]);
}
Which of course doesn't work straight off, since some users will be returned multiple times (once for each workplace). How do I do to get every user just once?
And when I have my users, how do I get the workplaces for each user? If I get it to work, the withPivot above will give me the IDs, but how do I get a collection of the Workplaces?

Related

Handle model dependencies in Laravel Repository Pattern

I'm discovering the Repository Pattern for my Laravel project but I have to say that I'm a bit lost once a model has several dependencies and the examples on the web are always basic and don't answer the question for more complex use cases.
Let's imagine a user on my app. He can have badges, he has different things on the app that will be slightly modified when he first performs the action (when he first sees the comments, I tell him once the different things he can do, etc), he has several "counters" to record the number of comments he made, the number of friends he invited, without having to count each entry each time.
My database looks like this:
users table:
id
pseudo
name
password
...
badges table:
user_id
badge1_xxxxxx
badge2_xxxxxx
...
I have a very limited number of badges so I decided to create a column for each of them and as soon as a user wins a badge, I get his entry (in OneToOne relationship) and I indicate that the badge in question has been won.
onboarding table:
user_id
seen_comments (boolean)
seen_results (boolean)
...
As you can see, I store each action I'd like the user to do in different columns and as soon as he has done one and I've been able to modify my app accordingly (by showing him an arrow, etc), I put the column in question to true.
user_counters table:
user_id
count_comments
count_invited_friends
...
I don't consider a user to be a user if he doesn't have an entry in each of the tables (I could have done everything in one table but the users table seemed to me to become huge). The only relationship used is OneToOne between the user and the table in question.
Should I do this ?
class UserRepository {
public function register($data) {
// Create the user
$user = User::create($data);
// Create all its dependencies which are required if I want to consider the user as fully registered in my DB
$user->badges()->create();
$user->onboarding()->create();
$user->counter()->create();
// Return the user
return $user;
}
}
Or should I create a Repository for each of these elements and create the entire user in a UserService ?
How far should I separate things and when does it become overkill?
Is there something that I don't understand in concept of Repository ? If so, could you give me some links that you found useful because I feel like I ran out of ideas for search keywords.
Thanks

Limit to 1 on hasMany-relationship

I have two models that are related to each other. One model contains users, and the other contains all courses and related timestamp of class start. Now the "related key" between them are the 'user_id' which are in both tables. I manage to get out data when having:
return $this->hasMany(ClassInfo::class,'user_id','user_id');
This works just fine. However, since I use the model in a with clause I need to the only one of the classes that starts a given time if start time crashes with another course for the user. I have tried with both:
return $this->hasMany(ClassInfo::class,'user_id','user_id')->take(1);
return $this->hasMany(ClassInfo::class,'user_id','user_id')->limit(1);
But both just give me empty collections, I don't see why that happends?
Is there any way that I can make it return for example the one with the biggest id value from the Class table (id is auto incremental for each course registered on a user).
Thanks for any tips and guidance!

Parse js sdk, How do you query many to many in document DB?

In the Parse js guide it says:
For example, a User may have many Posts that she might like. In this case, you can store the set of Posts that a User likes using relation. In order to add a Post to the “likes” list of the User, you can do:
var user = Parse.User.current();
var relation = user.relation("likes");
relation.add(post);
user.save();
My use case is actually this exact setup. We have Users and they can "like" 0-many Posts, so I set it up exactly as stated above. My issue now is that for a given Post or set of Posts, I need to query how many users have liked each Post. I'm having trouble figuring out how to query for that... Can someone help me out? I'm not sure if this is a limitation or if I just don't know enough to figure this out. I've thought about storing a counter on the Post itself and using increment() and decrement() each time a User likes or unlikes a Post, but I'd rather not if I can get away with it.
There are a couple of ways you can do this. One would be to also have a relation on each post for likedBy so when a user likes a post, you add that user to the post's likedBy relation as well as adding the post the user's likes relation.
Another solution is to create a new Parse class for Like. Whenever a User likes a post, you create a new Like with a pointer to the Post and the User who liked it. Then if you want to find the posts that a user likes, you can easily query that, or if you want to know which users like a post, that query is just as simple.
I personally use the second approach, but either will work

Query builder on hasMany relation

Problem
I'm creating an API with Laravel. Every server can have more than one contact, and every contact belongs to one server - as such, contacts are set up with a belongsTo relationship, and servers have a hasMany relationship to the contacts.
A user can have many servers via its hasMany relationship. Thus, when creating a server, we simply invoke $user->server()->create([values]), which works just fine.
The issue is that when we try to invoke it further, as with contacts - we hit a wall where we get:
Call to undefined method Illuminate\Database\Query\Builder::contacts()
When using: $user->server()->contacts()->create([]).
The method does exist in the server model.
We also have a hasManyThrough relationship on the user model, specifying that a user has many contacts through servers.
When calling $user->contact()->create([]), we instead get:
Call to undefined method Illuminate\Database\Query\Builder::create()
Does anyone have a clue what might be causing this? Do query builders not allow for this type of chaining, or am I missing something blatantly obvious? As you can see, I've tried a few different methods but can't seem to produce a working result.
Cheers!
As you said:
A user can have many servers via its hasMany relationship.
so You cannot build another relation on relation that can return many results (becasue at the end we don't know exacly which server id we should set in contact new record).
So what you can do is to itterate over:
foreach ($user->server as $server) {
$server->contacts()->create($values);
}
You see: now you have specific server with id to put into new contact record.

Three way relationship in Laravel

having a brain failure with a relationship between three objects, hoping someone can help me out.
I have four models: Team, User, ProjectType and Project
Team has many User, has many ProjectType
User belongs to many Team, has many ProjectType
ProjectType belongs to manyUser, belongs to many Team, has many Project
Project belongs to ProjectType
As a single user can belong to many teams, I want to request the ProjectTypes that a User has access to, but only within the Team they are currently logged in with. It may be the case that a User has access to project types across multiple teams, but will only be logged in to one team at any time, so I need just that subset.
I'm hoping this structure makes sense, but I'm struggling to get access to the data I want easily
So I'd like to do $user->projectTypes and get all project types for that user, but only the subset of the team they're currently logged in with.
Equally, once I've got that, I want to be able to get $user->projectTypes->projects within that set.
I'd like to do this whilst maintaining all of the nice relationship methods I get with Laravel, but am struggling to setup the data structure to support this, and get the data in turn.
Worth adding I'm using Laravel 4.2, but am not desparately tied to it, and can upgrade to 5.x if necessary to get this functionality.
Once you've defined the relationships as you've described, you can access the ProjectTypes that belong to a User, that also belong to a certain Team (in your case $teamid should be the id of the Team that the User is currently logged in to) like so:
$projectTypes = $user->projectTypes()->where('team_id', $teamid)->get();
To easily access a collection of all Projects that belong to all ProjectTypes that belong to a User, you would first define the HasManyThrough relationship like so:
class User extends Eloquent {
public function projects()
{
return $this->hasManyThrough('Project', 'ProjectType');
}
}
Then you can access that collection like so:
$projects = $user->projects;
And finally, to access the Projects that belong to the ProjectTypes that belong to a User, that also belong to a certain Team (i.e. what it seems you're looking for), you can use lists() to get a list of relevant ProjectType ids, then whereIn() to filter for those within that list:
$projectTypeIds = $user->projectTypes()->where('team_id', $teamid)->lists('id');
$projects = $user->projects()->whereIn('projecttype_id', $projectTypeIds)->get();

Resources