Insert a row that contains relational data? - laravel

This is a simplified version but... a user can submit the form which contains their name and qualification.
I have two tables - users and qualifications. A user has many qualifications. A qualification has one user.
I save like so:
$user = new User;
$user->first_name = 'Derek';
$qualification = new Qualification;
$qualification->qualification = 'History Degree';
DB::transaction(function() use ($user, $qualification) {
$user->save();
User::find($user->id)->qualifications()->save($qualification);
});
My questions are:
Is this the correct way to insert a row to a table and it's relationship? Is there a better way?
And my 2nd question...this line:
User::find($user->id)->qualifications()->save($qualification);
This may be a bit crazy but I just would like this explaining to me, the $user->id gets the id of the previously inserted row, if two people were to insert at the same time, how would I be sure that it would get the correct id? As in, user A saves, then user B saves, then the first User::find bit runs for user A but this would find user B's id. Is this where the transaction comes in?

Before you save the user by doing this:
user->save();
I think you should first save the "qualification" to that user. As long as your code functions as you currently have it, I would think this would do the trick:
$user->qualifications()->save($qualification);
and then do
user->save();
If you can get it to work in that order, you'll never have to worry about obtaining the wrong user ID and switching the qualifications on the wrong user, if they were to enter their information at approximately the same time.

Related

Laravel many-to-many

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?

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!

In need of a logic to create comments in laravel

Ok so the basis is that I want to be able to have comments on each of my post. The comments will have a reply button for each. It’s not multi threaded so one comment will have many replies. Those replies won’t have replies. Also I want to be able to like and dislike a comment/reply. All of this will not be bind to the user model or any of such. The public visitors will be able to add comments and reply to comments but the approval is needed.
So here is the logic I got so far. Am I on the right track here (hoping this post may help someone else as well):
So i create aComment model. And then create a table named comments.
And I create a model named Reply and a table named replies
And finally, a model name Like and it’s table likes
So the relationship is:
comments will have many replies and replies belongs to one comment
replies & comments will have many likes.
And now for the logic:
I will use AJAX to call the store function on the CommentController to store comments. And I will call the store function on the ReplyController to store the replies. As for the likes, LikeController store function will store the likes for the comment and reply.
Here is the table structure:
Comments table
id
post_id
name
email
comment
approved
timestap
Replies table
id
comment_id
name
email
comment (or reply)
approved
timestamp
Likes table
id
comment_id
reply_id
like
dislike
timestamp
Now what I do not understand is, likes table. Is it right to have comment_id and reply_id and also like and dislike?
I could call the store function everytime someone clicks the like or dislike and have it stored in the table and update the column if it is a reply or a comment by it’s id to the respective id columns. Is the logic right?
Also, if you guys have any suggestions or better and efficient way of doing this, please let me know.
This is getting too long so I’ll just leave it here.
Edit
Also forgot to mention that I am not sure how I will be taking the amount of likes from db to blade and count it. Not with the current structure mentioned above. Also, how to check and see if the person already liked. And if so, don’t let them like again or dislike again. A liked person can not dislike. They can do only one thing.
I would definitely recommend associating comments, replied and likes to a User which you are pretty much already doing with comments and replies.
There are ways that you could have a "liking" system that would allow guest usage, however, this would be very easy to get around and ultimately make your "like" stats useless.
An example DB structure going forward would be:
comments and replies
id
post_id // or comment_id if on the replies table
user_id
body
approved
( "_at" dates)
likes
id
likeable_id // id of the comment or reply
likeable_type // Comment or Reply
user_id
liked (boolean)
("_at" dates)
The likes table is setup to be used as a Polymorphic relationship e.g. in your Comment model:
public function likes()
{
return $this->morphMany(Like::class, 'likeable');
}
Then to add a like you would have something like:
$like = new Like(['user_id' => auth()->user()->id, 'liked' => true]);
$comment->likes()->save();
There are many different ways you would then check if the current auth user has liked a post, one example would be to have a separate relationship so that you can eager load the results:
public function authUserLike()
{
return $this->morphOne(Like::class, 'likeable')->where('user_id', auth()->id());
}
Then if the auth_user_like is null they haven't already liked that comment.
I don't see any need of the Replies Table just use parent_id in comments table. This tutorial might help you get started Nesting Comments in Laravel

Facing issue in laravel orderby

I am facing a issue with laravel order by function.
i want to fetch the records according to country and the result should start from the current user's country.
For example.
if auth user belong to india then list should start from india.
My Current code is
$users = User::where('status', '=',1)->with(['profile'])->latest()->orderBy('last_login', 'desc')->paginate(12);
Thanks
Ok, whatever I've understood, you are looking to sort the data through the country attributes from profiles table, which is in relation with User model, for this you need to use join I'm not sure about your structure so I'm just giving you an example. Suppose you want to sort by profiles => id then you can write something:
Edit: As per the requirement given in comments I would recommend to have something like this:
First of all lets have authenticated user by
$AuthUser = Auth::user();
Then lets call the relation
$users = User::->leftJoinRelations('profile')
->orderByRaw("FIELD(country , ". $AuthUser->profile->country ."), ASC")
->paginate();
So in this way you can have user sorted by authenticated user country. Hope this helps.

Resources